From e858b865f34968cd8cef52988c207c817ffa4c6f Mon Sep 17 00:00:00 2001
From: Dmitry Ermakov <de@dimer.org.ua>
Date: Wed, 9 Feb 2022 11:14:57 +0300
Subject: [PATCH] Add GM813x patch

---
 .../board/gm8136/gm8136.config                |      4 +-
 .../board/gm8136/kernel/gm8136.generic.config |    128 +-
 .../patches/00_gm8136_kernel-3.3_v2.patch     | 155722 +++++++++++++++
 .../kernel/patches/10_overlayfs.v13.patch     |   3363 +
 .../kernel/patches/10_uimage_makefile.patch   |     62 -
 .../11_fix_yylloc_for_modern_computers.patch  |     11 +
 6 files changed, 159194 insertions(+), 96 deletions(-)
 create mode 100644 br-ext-chip-grainmedia/board/gm8136/kernel/patches/00_gm8136_kernel-3.3_v2.patch
 create mode 100644 br-ext-chip-grainmedia/board/gm8136/kernel/patches/10_overlayfs.v13.patch
 delete mode 100644 br-ext-chip-grainmedia/board/gm8136/kernel/patches/10_uimage_makefile.patch
 create mode 100644 br-ext-chip-grainmedia/board/gm8136/kernel/patches/11_fix_yylloc_for_modern_computers.patch

diff --git a/br-ext-chip-grainmedia/board/gm8136/gm8136.config b/br-ext-chip-grainmedia/board/gm8136/gm8136.config
index f151c869..ebd79130 100644
--- a/br-ext-chip-grainmedia/board/gm8136/gm8136.config
+++ b/br-ext-chip-grainmedia/board/gm8136/gm8136.config
@@ -1,2 +1,2 @@
-MEM_START_ADDR=0x40000000
-KERNEL_UPLOAD_ADDR=0x41000000
+MEM_START_ADDR=0x00000000
+KERNEL_UPLOAD_ADDR=0x00008000
diff --git a/br-ext-chip-grainmedia/board/gm8136/kernel/gm8136.generic.config b/br-ext-chip-grainmedia/board/gm8136/kernel/gm8136.generic.config
index abce3846..e3c59c7d 100644
--- a/br-ext-chip-grainmedia/board/gm8136/kernel/gm8136.generic.config
+++ b/br-ext-chip-grainmedia/board/gm8136/kernel/gm8136.generic.config
@@ -36,7 +36,7 @@ CONFIG_IRQ_WORK=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
+CONFIG_CROSS_COMPILE=""
 CONFIG_LOCALVERSION=""
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_HAVE_KERNEL_GZIP=y
@@ -44,10 +44,10 @@ CONFIG_HAVE_KERNEL_LZMA=y
 CONFIG_HAVE_KERNEL_XZ=y
 CONFIG_HAVE_KERNEL_LZO=y
 # CONFIG_KERNEL_GZIP is not set
-CONFIG_KERNEL_LZMA=y
-# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZMA is not set
+CONFIG_KERNEL_XZ=y
 # CONFIG_KERNEL_LZO is not set
-CONFIG_DEFAULT_HOSTNAME="grain-media"
+CONFIG_DEFAULT_HOSTNAME="openipc-gm8136"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
@@ -89,7 +89,13 @@ CONFIG_NET_NS=y
 # CONFIG_SCHED_AUTOGROUP is not set
 # CONFIG_SYSFS_DEPRECATED is not set
 # CONFIG_RELAY is not set
-# CONFIG_BLK_DEV_INITRD 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_RD_XZ is not set
+# CONFIG_RD_LZO is not set
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -217,6 +223,7 @@ CONFIG_MMU=y
 # CONFIG_ARCH_FARADAY is not set
 CONFIG_ARCH_GM=y
 # CONFIG_ARCH_GM_DUO is not set
+# CONFIG_ARCH_GM_SMP is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
@@ -276,6 +283,7 @@ CONFIG_FORCE_MAX_ZONEORDER=12
 CONFIG_CLOCK_TICK_RATE=33000000
 CONFIG_FTINTC030=y
 # CONFIG_FPGA is not set
+CONFIG_VIDEO_FASTTHROUGH=y
 
 #
 # System MMU
@@ -286,6 +294,8 @@ CONFIG_FTINTC030=y
 #
 CONFIG_CPU_FA626TE=y
 # CONFIG_CPU_FA726TE is not set
+# CONFIG_CPU_CA9 is not set
+# CONFIG_CPU_CA7 is not set
 # CONFIG_CPU_ARM926T is not set
 CONFIG_CPU_32v5=y
 CONFIG_CPU_ABRT_EV5T=y
@@ -440,18 +450,17 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 # CONFIG_UNIX_DIAG is not set
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
 # CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
@@ -459,7 +468,7 @@ CONFIG_INET=y
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
 # CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 CONFIG_INET_LRO=y
@@ -470,7 +479,24 @@ CONFIG_INET_TCP_DIAG=y
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETWORK_PHY_TIMESTAMPING is not set
 # CONFIG_NETFILTER is not set
@@ -513,13 +539,26 @@ CONFIG_WIRELESS_EXT=y
 CONFIG_WEXT_CORE=y
 CONFIG_WEXT_PROC=y
 CONFIG_WEXT_PRIV=y
-# CONFIG_CFG80211 is not set
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
 # CONFIG_WIRELESS_EXT_SYSFS is not set
 # CONFIG_LIB80211 is not set
-
-#
-# CFG80211 needs to be enabled for MAC80211
-#
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
@@ -718,12 +757,11 @@ CONFIG_NET_CORE=y
 # CONFIG_EQUALIZER is not set
 CONFIG_MII=y
 # CONFIG_NET_TEAM is not set
-CONFIG_MACVLAN=y
-# CONFIG_MACVTAP is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_TUN is not set
+CONFIG_TUN=m
 # CONFIG_VETH is not set
 
 #
@@ -739,6 +777,7 @@ CONFIG_NET_VENDOR_FARADAY=y
 CONFIG_FTGMAC100=y
 CONFIG_FTGMAC100_DRIVER_0_MASTER=y
 CONFIG_FTMAC_TINY=y
+# CONFIG_FTGMAC030 is not set
 # CONFIG_FTMAC110 is not set
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
@@ -784,8 +823,28 @@ CONFIG_REALTEK_PHY=y
 # CONFIG_USB_USBNET is not set
 # CONFIG_USB_IPHETH is not set
 CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AT76C50X_USB is not set
 # CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_BRCMFMAC is not set
 # CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+CONFIG_RTL8192CU=m
+CONFIG_RTLWIFI=m
+CONFIG_RTL8192C_COMMON=m
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX_MENU is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_MWIFIEX is not set
 
 #
 # Enable WiMAX (Networking options) to see the WiMAX drivers
@@ -1253,9 +1312,8 @@ CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_FTSDC021=y
 CONFIG_SDC0_IP=y
-CONFIG_MMC_FTSDC021_VEND_TUNE=y
 # CONFIG_SDC1_IP is not set
-# CONFIG_MMC_CD_INVERSE is not set
+CONFIG_MMC_FTSDC021_VEND_TUNE=y
 # CONFIG_MMC_SPI is not set
 # CONFIG_MMC_DW is not set
 # CONFIG_MMC_VUB300 is not set
@@ -1312,7 +1370,7 @@ CONFIG_IOMMU_SUPPORT=y
 # CONFIG_GFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
 # CONFIG_NILFS2_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FS_POSIX_ACL=y
 CONFIG_FILE_LOCKING=y
 CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
@@ -1322,6 +1380,7 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTACTL is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
+CONFIG_OVERLAYFS_FS=y
 
 #
 # Caches
@@ -1337,9 +1396,9 @@ CONFIG_INOTIFY_USER=y
 #
 # DOS/FAT/NT Filesystems
 #
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
 CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
@@ -1369,7 +1428,9 @@ CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
 # CONFIG_JFFS2_FS_WBUF_VERIFY is not set
 # CONFIG_JFFS2_SUMMARY is not set
-# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
 # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
 CONFIG_JFFS2_ZLIB=y
 # CONFIG_JFFS2_LZO is not set
@@ -1399,6 +1460,7 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -1448,7 +1510,7 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+CONFIG_NLS_UTF8=y
 
 #
 # Kernel hacking
@@ -1502,6 +1564,7 @@ CONFIG_DEBUG_LIST=y
 # CONFIG_DEBUG_SG is not set
 # CONFIG_DEBUG_NOTIFIERS is not set
 # CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
@@ -1617,7 +1680,7 @@ CONFIG_CRYPTO_RNG2=m
 #
 CONFIG_CRYPTO_AES=m
 # CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
+CONFIG_CRYPTO_ARC4=m
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_CAST5 is not set
@@ -1671,11 +1734,12 @@ CONFIG_XZ_DEC_ARMTHUMB=y
 CONFIG_XZ_DEC_SPARC=y
 CONFIG_XZ_DEC_BCJ=y
 # CONFIG_XZ_DEC_TEST is not set
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
 CONFIG_DQL=y
 CONFIG_NLATTR=y
 CONFIG_GENERIC_ATOMIC64=y
-# CONFIG_AVERAGE is not set
+CONFIG_AVERAGE=y
 # CONFIG_CORDIC is not set
diff --git a/br-ext-chip-grainmedia/board/gm8136/kernel/patches/00_gm8136_kernel-3.3_v2.patch b/br-ext-chip-grainmedia/board/gm8136/kernel/patches/00_gm8136_kernel-3.3_v2.patch
new file mode 100644
index 00000000..b4dea020
--- /dev/null
+++ b/br-ext-chip-grainmedia/board/gm8136/kernel/patches/00_gm8136_kernel-3.3_v2.patch
@@ -0,0 +1,155722 @@
+diff --git a/Makefile b/Makefile
+index 19329844..7f764cc5 100644
+--- a/Makefile
++++ b/Makefile
+@@ -4,6 +4,8 @@ SUBLEVEL = 0
+ EXTRAVERSION =
+ NAME = Saber-toothed Squirrel
+ 
++ARCH = arm
++
+ # *DOCUMENTATION*
+ # To see a list of typical targets execute "make help"
+ # More info can be located in ./README
+@@ -825,7 +827,7 @@ ifdef CONFIG_KALLSYMS
+ #   temporary bypass to allow the kernel to be built while the
+ #   maintainers work out what went wrong with kallsyms.
+ 
+-last_kallsyms := 2
++last_kallsyms := 3
+ 
+ ifdef KALLSYMS_EXTRA_PASS
+ ifneq ($(KALLSYMS_EXTRA_PASS),0)
+@@ -920,6 +922,7 @@ endif
+ 	$(call vmlinux-modpost)
+ 	$(call if_changed_rule,vmlinux__)
+ 	$(Q)rm -f .old_version
++	@grep 'CONFIG_CROSS_COMPILE' .config | sed 's/"//g' | sed 's/CONFIG_CROSS_COMPILE/CROSS_COMPILE/g' > cross_compiler_def
+ 
+ # build vmlinux.o first to catch section mismatch errors early
+ ifdef CONFIG_KALLSYMS
+@@ -1529,7 +1532,7 @@ quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN   $(wildcard $(rm-files))
+ # Run depmod only if we have System.map and depmod is executable
+ quiet_cmd_depmod = DEPMOD  $(KERNELRELEASE)
+       cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \
+-                   $(KERNELRELEASE)
++                   $(KERNELRELEASE) $(INSTALL_MOD_PATH)
+ 
+ # Create temporary dir for module support files
+ # clean it up only when building all modules
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index dfb0312f..0ae3d360 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -7,12 +7,13 @@ config ARM
+ 	select HAVE_MEMBLOCK
+ 	select RTC_LIB
+ 	select SYS_SUPPORTS_APM_EMULATION
+-	select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
++	select GENERIC_ATOMIC64 if ((CPU_V6 || !CPU_32v6K || !AEABI) && !CPU_FMP626)
+ 	select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
+ 	select HAVE_ARCH_KGDB
+ 	select HAVE_KPROBES if !XIP_KERNEL
+ 	select HAVE_KRETPROBES if (HAVE_KPROBES)
+ 	select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
++	select HAVE_FUNCTION_GRAPH_TRACER if (!XIP_KERNEL)
+ 	select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
+ 	select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL)
+ 	select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
+@@ -21,6 +22,7 @@ config ARM
+ 	select HAVE_KERNEL_GZIP
+ 	select HAVE_KERNEL_LZO
+ 	select HAVE_KERNEL_LZMA
++	select HAVE_KERNEL_XZ
+ 	select HAVE_IRQ_WORK
+ 	select HAVE_PERF_EVENTS
+ 	select PERF_USE_VMALLOC
+@@ -394,6 +396,74 @@ config ARCH_PRIMA2
+ 	help
+           Support for CSR SiRFSoC ARM Cortex A9 Platform
+ 
++config ARCH_FARADAY
++	bool "Faraday All SoC Platforms"
++	select MIGHT_HAVE_PCI
++	select GENERIC_TIME
++	select GENERIC_CLOCKEVENTS
++	select CLKDEV_LOOKUP
++	select HAVE_SMP
++	select MULTI_IRQ_HANDLER if CPU_FMP626
++	help
++	   Faraday ARM processors are ARM9 (ARMv4 architecture) compatible processors
++	   with many optimizations. Faraday corp. provides many SOC platforms and IPs
++	   based on these processors for different target markets.
++	   For more information please visit:
++	   <http://www.faraday-tech.com/html/ASIC/embedded/processors/index.html>
++
++config ARCH_GM
++	bool "GM All SoC Platforms"
++	select MIGHT_HAVE_PCI
++	select GENERIC_TIME
++	select GENERIC_CLOCKEVENTS
++	select NEED_MACH_MEMORY_H
++	select USB_ARCH_HAS_EHCI if CONFIG_USB_SUPPORT
++	select ARCH_REQUIRE_GPIOLIB
++	select ARCH_HAS_CPUFREQ
++
++    help
++      Faraday ARM processors are ARM9 (ARMv4 architecture) compatible processors
++      with many optimizations. Faraday corp. provides many SOC platforms and IPs
++      based on these processors for different target markets.
++      For more information please visit:
++      <http://www.faraday-tech.com/html/ASIC/embedded/processors/index.html>
++
++config ARCH_GM_DUO
++	bool "GM Dual-Core CPU SoC Platforms"
++	select MIGHT_HAVE_PCI
++	select GENERIC_TIME
++	select GENERIC_CLOCKEVENTS
++	select NEED_MACH_MEMORY_H
++	select USB_ARCH_HAS_EHCI if CONFIG_USB_SUPPORT
++	select ARCH_REQUIRE_GPIOLIB
++
++    help
++      Faraday ARM processors, Dual-Core CPU, are ARM9 (ARMv4 architecture) compatible processors
++      with many optimizations. Faraday corp. provides many SOC platforms and IPs
++      based on these processors for different target markets.
++      For more information please visit:
++      <http://www.faraday-tech.com/html/ASIC/embedded/processors/index.html>
++
++config ARCH_GM_SMP
++	bool "GM SMP CPU SoC Platforms"
++        select CLKSRC_MMIO
++	select MIGHT_HAVE_PCI
++	select GENERIC_TIME
++	select GENERIC_CLOCKEVENTS
++	select CLKDEV_LOOKUP
++	select NEED_MACH_MEMORY_H
++	select USB_ARCH_HAS_EHCI if CONFIG_USB_SUPPORT
++	select ARCH_REQUIRE_GPIOLIB
++	select HAVE_SCHED_CLOCK
++	select HAVE_SMP
++
++    help
++      Faraday ARM processors are ARM9 (ARMv4 architecture) compatible processors
++      with many optimizations. Faraday corp. provides many SOC platforms and IPs
++      based on these processors for different target markets.
++      For more information please visit:
++      <http://www.faraday-tech.com/html/ASIC/embedded/processors/index.html>
++
+ config ARCH_EBSA110
+ 	bool "EBSA-110"
+ 	select CPU_SA110
+@@ -1004,6 +1074,22 @@ source "arch/arm/mach-dove/Kconfig"
+ 
+ source "arch/arm/mach-ep93xx/Kconfig"
+ 
++if ARCH_FARADAY
++source "arch/arm/mach-faraday/Kconfig"
++endif
++
++if ARCH_GM
++source "arch/arm/mach-GM/Kconfig"
++endif
++
++if ARCH_GM_DUO
++source "arch/arm/mach-GM-Duo/Kconfig"
++endif
++
++if ARCH_GM_SMP
++source "arch/arm/mach-GM-SMP/Kconfig"
++endif
++
+ source "arch/arm/mach-footbridge/Kconfig"
+ 
+ source "arch/arm/mach-gemini/Kconfig"
+@@ -1149,7 +1235,7 @@ config XSCALE_PMU
+ 	default y
+ 
+ config CPU_HAS_PMU
+-	depends on (CPU_V6 || CPU_V6K || CPU_V7 || XSCALE_PMU) && \
++	depends on (CPU_V6 || CPU_V6K || CPU_V7 || XSCALE_PMU || CPU_FMP626) && \
+ 		   (!ARCH_OMAP3 || OMAP3_EMU)
+ 	default y
+ 	bool
+@@ -1454,7 +1540,7 @@ config HAVE_SMP
+ 
+ config SMP
+ 	bool "Symmetric Multi-Processing"
+-	depends on CPU_V6K || CPU_V7
++	depends on CPU_V6K || CPU_V7 || CPU_FMP626
+ 	depends on GENERIC_CLOCKEVENTS
+ 	depends on HAVE_SMP
+ 	depends on MMU
+@@ -1520,6 +1606,19 @@ config HAVE_ARM_SCU
+ 	help
+ 	  This option enables support for the ARM system coherency unit
+ 
++config ARM_ARCH_TIMER
++	bool "Architected timer support"
++	depends on CPU_V7
++	select TICK_ONESHOT
++	help
++	  This option enables support for the ARM architected timer
++
++config ARM_ARCH_TIMER
++	bool "Architected timer support"
++	depends on CPU_V7
++	select TICK_ONESHOT
++	help
++	  This option enables support for the ARM architected timer
+ config HAVE_ARM_TWD
+ 	bool
+ 	depends on SMP
+@@ -1593,7 +1692,9 @@ config HZ
+ 	default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
+ 	default AT91_TIMER_HZ if ARCH_AT91
+ 	default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE
+-	default 100
++    default GM8210_TIMER_HZ if ARCH_GM_DUO && PLATFORM_GM8210
++    default 100 if ARCH_GM
++    default 100
+ 
+ config THUMB2_KERNEL
+ 	bool "Compile the kernel in Thumb-2 mode (EXPERIMENTAL)"
+@@ -2073,6 +2174,7 @@ endmenu
+ 
+ menu "CPU Power Management"
+ 
++if PLATFORM_GM8139 || PLATFORM_GM8136
+ if ARCH_HAS_CPUFREQ
+ 
+ source "drivers/cpufreq/Kconfig"
+@@ -2154,6 +2256,7 @@ config CPU_FREQ_S3C24XX_DEBUGFS
+ 	  Export status information via debugfs.
+ 
+ endif
++endif
+ 
+ source "drivers/cpuidle/Kconfig"
+ 
+@@ -2203,7 +2306,7 @@ config FPE_FASTFPE
+ 
+ config VFP
+ 	bool "VFP-format floating point maths"
+-	depends on CPU_V6 || CPU_V6K || CPU_ARM926T || CPU_V7 || CPU_FEROCEON
++	depends on CPU_V6 || CPU_V6K || CPU_ARM926T || CPU_V7 || CPU_FEROCEON || CPU_FA626TE
+ 	help
+ 	  Say Y to include VFP support code in the kernel. This is needed
+ 	  if your hardware includes a VFP unit.
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 1683bfb9..c704a663 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -82,7 +82,10 @@ tune-$(CONFIG_CPU_ARM920T)	:=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_ARM922T)	:=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_ARM925T)	:=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_ARM926T)	:=-mtune=arm9tdmi
+-tune-$(CONFIG_CPU_FA526)	:=-mtune=arm9tdmi
++tune-$(CONFIG_CPU_FA526)	:=-mtune=fa526
++tune-$(CONFIG_CPU_FA626TE)	:=-mtune=fa626te
++tune-$(CONFIG_CPU_FA726TE)	:=-mtune=fa726te
++tune-$(CONFIG_CPU_FMP626)	:=-mtune=fmp626
+ tune-$(CONFIG_CPU_SA110)	:=-mtune=strongarm110
+ tune-$(CONFIG_CPU_SA1100)	:=-mtune=strongarm1100
+ tune-$(CONFIG_CPU_XSCALE)	:=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
+@@ -91,6 +94,7 @@ tune-$(CONFIG_CPU_FEROCEON)	:=$(call cc-option,-mtune=marvell-f,-mtune=xscale)
+ tune-$(CONFIG_CPU_V6)		:=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+ tune-$(CONFIG_CPU_V6K)		:=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+ 
++
+ ifeq ($(CONFIG_AEABI),y)
+ CFLAGS_ABI	:=-mabi=aapcs-linux -mno-thumb-interwork
+ else
+@@ -128,12 +132,10 @@ textofs-$(CONFIG_PM_H1940)      := 0x00108000
+ ifeq ($(CONFIG_ARCH_SA1100),y)
+ textofs-$(CONFIG_SA1111) := 0x00208000
+ endif
+-textofs-$(CONFIG_ARCH_MSM7X30) := 0x00208000
+-textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
+-textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
+ 
+ # Machine directory name.  This list is sorted alphanumerically
+ # by CONFIG_* macro name.
++machine-$(CONFIG_ARCH_AAEC2000)		:= aaec2000
+ machine-$(CONFIG_ARCH_AT91)		:= at91
+ machine-$(CONFIG_ARCH_BCMRING)		:= bcmring
+ machine-$(CONFIG_ARCH_CLPS711X)		:= clps711x
+@@ -142,9 +144,9 @@ machine-$(CONFIG_ARCH_DAVINCI)		:= davinci
+ machine-$(CONFIG_ARCH_DOVE)		:= dove
+ machine-$(CONFIG_ARCH_EBSA110)		:= ebsa110
+ machine-$(CONFIG_ARCH_EP93XX)		:= ep93xx
++machine-$(CONFIG_ARCH_FARADAY)		:= faraday
+ machine-$(CONFIG_ARCH_GEMINI)		:= gemini
+ machine-$(CONFIG_ARCH_H720X)		:= h720x
+-machine-$(CONFIG_ARCH_HIGHBANK)		:= highbank
+ machine-$(CONFIG_ARCH_INTEGRATOR)	:= integrator
+ machine-$(CONFIG_ARCH_IOP13XX)		:= iop13xx
+ machine-$(CONFIG_ARCH_IOP32X)		:= iop32x
+@@ -154,55 +156,63 @@ machine-$(CONFIG_ARCH_IXP23XX)		:= ixp23xx
+ machine-$(CONFIG_ARCH_IXP4XX)		:= ixp4xx
+ machine-$(CONFIG_ARCH_KIRKWOOD)		:= kirkwood
+ machine-$(CONFIG_ARCH_KS8695)		:= ks8695
+-machine-$(CONFIG_ARCH_LPC32XX)		:= lpc32xx
++machine-$(CONFIG_ARCH_L7200)		:= l7200
++machine-$(CONFIG_ARCH_LH7A40X)		:= lh7a40x
++machine-$(CONFIG_ARCH_LOKI) 		:= loki
+ machine-$(CONFIG_ARCH_MMP)		:= mmp
+ machine-$(CONFIG_ARCH_MSM)		:= msm
+ machine-$(CONFIG_ARCH_MV78XX0)		:= mv78xx0
+-machine-$(CONFIG_ARCH_IMX_V4_V5)	:= imx
+-machine-$(CONFIG_ARCH_IMX_V6_V7)	:= imx
+-machine-$(CONFIG_ARCH_MXS)		:= mxs
++machine-$(CONFIG_ARCH_MX1)		:= mx1
++machine-$(CONFIG_ARCH_MX2)		:= mx2
++machine-$(CONFIG_ARCH_MX25)		:= mx25
++machine-$(CONFIG_ARCH_MX3)		:= mx3
++machine-$(CONFIG_ARCH_MX5)		:= mx5
++machine-$(CONFIG_ARCH_MXC91231)		:= mxc91231
+ machine-$(CONFIG_ARCH_NETX)		:= netx
+ machine-$(CONFIG_ARCH_NOMADIK)		:= nomadik
++machine-$(CONFIG_ARCH_NS9XXX)		:= ns9xxx
+ machine-$(CONFIG_ARCH_OMAP1)		:= omap1
+ machine-$(CONFIG_ARCH_OMAP2)		:= omap2
+ machine-$(CONFIG_ARCH_OMAP3)		:= omap2
+ machine-$(CONFIG_ARCH_OMAP4)		:= omap2
+ machine-$(CONFIG_ARCH_ORION5X)		:= orion5x
+-machine-$(CONFIG_ARCH_PICOXCELL)	:= picoxcell
+ machine-$(CONFIG_ARCH_PNX4008)		:= pnx4008
+-machine-$(CONFIG_ARCH_PRIMA2)		:= prima2
+ machine-$(CONFIG_ARCH_PXA)		:= pxa
+ machine-$(CONFIG_ARCH_REALVIEW)		:= realview
+ machine-$(CONFIG_ARCH_RPC)		:= rpc
+-machine-$(CONFIG_ARCH_S3C2410)		:= s3c2410 s3c2412 s3c2416 s3c2440 s3c2443
++machine-$(CONFIG_ARCH_S3C2410)		:= s3c2410 s3c2400 s3c2412 s3c2416 s3c2440 s3c2443
++machine-$(CONFIG_ARCH_S3C24A0)		:= s3c24a0
+ machine-$(CONFIG_ARCH_S3C64XX)		:= s3c64xx
+-machine-$(CONFIG_ARCH_S5P64X0)		:= s5p64x0
++machine-$(CONFIG_ARCH_S5P6440)		:= s5p6440
++machine-$(CONFIG_ARCH_S5P6442)		:= s5p6442
+ machine-$(CONFIG_ARCH_S5PC100)		:= s5pc100
+ machine-$(CONFIG_ARCH_S5PV210)		:= s5pv210
+-machine-$(CONFIG_ARCH_EXYNOS4)		:= exynos
+ machine-$(CONFIG_ARCH_SA1100)		:= sa1100
+ machine-$(CONFIG_ARCH_SHARK)		:= shark
+ machine-$(CONFIG_ARCH_SHMOBILE) 	:= shmobile
+-machine-$(CONFIG_ARCH_TEGRA)		:= tegra
++machine-$(CONFIG_ARCH_STMP378X)		:= stmp378x
++machine-$(CONFIG_ARCH_STMP37XX)		:= stmp37xx
+ machine-$(CONFIG_ARCH_U300)		:= u300
+ machine-$(CONFIG_ARCH_U8500)		:= ux500
+ machine-$(CONFIG_ARCH_VERSATILE)	:= versatile
+ machine-$(CONFIG_ARCH_VEXPRESS)		:= vexpress
+-machine-$(CONFIG_ARCH_VT8500)		:= vt8500
+ machine-$(CONFIG_ARCH_W90X900)		:= w90x900
++machine-$(CONFIG_ARCH_NUC93X)		:= nuc93x
+ machine-$(CONFIG_FOOTBRIDGE)		:= footbridge
+ machine-$(CONFIG_MACH_SPEAR300)		:= spear3xx
+ machine-$(CONFIG_MACH_SPEAR310)		:= spear3xx
+ machine-$(CONFIG_MACH_SPEAR320)		:= spear3xx
+ machine-$(CONFIG_MACH_SPEAR600)		:= spear6xx
+-machine-$(CONFIG_ARCH_ZYNQ)		:= zynq
++machine-$(CONFIG_ARCH_GM)           := GM
++machine-$(CONFIG_ARCH_GM_DUO)       := GM-Duo
++machine-$(CONFIG_ARCH_GM_SMP)       := GM-SMP
+ 
+ # Platform directory name.  This list is sorted alphanumerically
+ # by CONFIG_* macro name.
+ plat-$(CONFIG_ARCH_MXC)		:= mxc
+ plat-$(CONFIG_ARCH_OMAP)	:= omap
+ plat-$(CONFIG_ARCH_S3C64XX)	:= samsung
+-plat-$(CONFIG_ARCH_ZYNQ)	:= versatile
++plat-$(CONFIG_ARCH_STMP3XXX)	:= stmp3xxx
+ plat-$(CONFIG_PLAT_IOP)		:= iop
+ plat-$(CONFIG_PLAT_NOMADIK)	:= nomadik
+ plat-$(CONFIG_PLAT_ORION)	:= orion
+@@ -212,6 +222,20 @@ plat-$(CONFIG_PLAT_S5P)		:= s5p samsung
+ plat-$(CONFIG_PLAT_SPEAR)	:= spear
+ plat-$(CONFIG_PLAT_VERSATILE)	:= versatile
+ 
++# Luke Lee 09/07/2005 ins begin
++ifeq ($(machine-y),GM)
++include arch/arm/mach-GM/Makefile
++endif
++ifeq ($(machine-y),GM-Duo)
++include arch/arm/mach-GM-Duo/Makefile
++endif
++ifeq ($(machine-y),GM-SMP)
++include arch/arm/mach-GM-SMP/Makefile
++endif
++# Luke Lee 09/07/2005 ins end
++
++
++
+ ifeq ($(CONFIG_ARCH_EBSA110),y)
+ # This is what happens if you forget the IOCS16 line.
+ # PCMCIA cards stop working.
+@@ -246,13 +270,12 @@ ifeq ($(FASTFPE),$(wildcard $(FASTFPE)))
+ FASTFPE_OBJ	:=$(FASTFPE)/
+ endif
+ 
+-core-$(CONFIG_FPE_NWFPE)	+= arch/arm/nwfpe/
+-core-$(CONFIG_FPE_FASTFPE)	+= $(FASTFPE_OBJ)
+-core-$(CONFIG_VFP)		+= arch/arm/vfp/
+-
+ # If we have a machine-specific directory, then include it in the build.
+ core-y				+= arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
+ core-y				+= $(machdirs) $(platdirs)
++core-$(CONFIG_FPE_NWFPE)	+= arch/arm/nwfpe/
++core-$(CONFIG_FPE_FASTFPE)	+= $(FASTFPE_OBJ)
++core-$(CONFIG_VFP)		+= arch/arm/vfp/
+ 
+ drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
+ 
+diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
+index fc871e71..82704e5e 100644
+--- a/arch/arm/boot/Makefile
++++ b/arch/arm/boot/Makefile
+@@ -25,7 +25,15 @@ ZRELADDR    := $(zreladdr-y)
+ PARAMS_PHYS := $(params_phys-y)
+ INITRD_PHYS := $(initrd_phys-y)
+ 
+-export ZRELADDR INITRD_PHYS PARAMS_PHYS
++ifeq ($(CONFIG_PLATFORM_GM8210),y)
++ZRELADDR_FA726 := $(zreladdr_fa726-y)
++ZRELADDR_FA626 := $(zreladdr_fa626-y)
++export ZRELADDR_FA726 ZRELADDR_FA626
++else
++export ZRELADDR
++endif
++
++export INITRD_PHYS PARAMS_PHYS
+ 
+ targets := Image zImage xipImage bootpImage uImage
+ 
+diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
+index cf0a64ce..53e47f38 100644
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -41,6 +41,22 @@ ifeq ($(CONFIG_ARCH_SHARK),y)
+ OBJS		+= head-shark.o ofw-shark.o
+ endif
+ 
++ifeq ($(CONFIG_ARCH_FARADAY),y)
++OBJS	        += head-faraday.o
++endif
++
++ifeq ($(CONFIG_ARCH_GM),y)
++OBJS	        += head-GM.o
++endif
++
++ifeq ($(CONFIG_ARCH_GM_DUO),y)
++OBJS		+= head-GM.o
++endif
++
++ifeq ($(CONFIG_ARCH_GM_SMP),y)
++OBJS		+= head-GM.o
++endif
++
+ ifeq ($(CONFIG_ARCH_P720T),y)
+ # Borrow this code from SA1100
+ OBJS		+= head-sa1100.o
+@@ -92,6 +108,7 @@ SEDFLAGS	= s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
+ suffix_$(CONFIG_KERNEL_GZIP) = gzip
+ suffix_$(CONFIG_KERNEL_LZO)  = lzo
+ suffix_$(CONFIG_KERNEL_LZMA) = lzma
++suffix_$(CONFIG_KERNEL_XZ)   = xzkern
+ 
+ # Borrowed libfdt files for the ATAG compatibility mode
+ 
+@@ -112,10 +129,12 @@ endif
+ 
+ targets       := vmlinux vmlinux.lds \
+ 		 piggy.$(suffix_y) piggy.$(suffix_y).o \
+-		 lib1funcs.o lib1funcs.S font.o font.c head.o misc.o $(OBJS)
++		 lib1funcs.o lib1funcs.S ashldi3.o ashldi3.S \
++		 font.o font.c head.o misc.o $(OBJS)
+ 
+ # Make sure files are removed during clean
+-extra-y       += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs)
++extra-y       += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern \
++		 lib1funcs.S ashldi3.S $(libfdt) $(libfdt_hdrs)
+ 
+ ifeq ($(CONFIG_FUNCTION_TRACER),y)
+ ORIG_CFLAGS := $(KBUILD_CFLAGS)
+@@ -123,7 +142,7 @@ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
+ endif
+ 
+ ccflags-y := -fpic -fno-builtin -I$(obj)
+-asflags-y := -Wa,-march=all
++#asflags-y := -Wa,-march=all
+ 
+ # Supply kernel BSS size to the decompressor via a linker symbol.
+ KBSS_SZ = $(shell $(CROSS_COMPILE)size $(obj)/../../../../vmlinux | \
+@@ -131,8 +150,12 @@ KBSS_SZ = $(shell $(CROSS_COMPILE)size $(obj)/../../../../vmlinux | \
+ LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
+ # Supply ZRELADDR to the decompressor via a linker symbol.
+ ifneq ($(CONFIG_AUTO_ZRELADDR),y)
++ifeq ($(CONFIG_PLATFORM_GM8210),y)
++LDFLAGS_vmlinux += --defsym zreladdr_fa726=$(ZRELADDR_FA726) --defsym zreladdr_fa626=$(ZRELADDR_FA626)
++else
+ LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
+ endif
++endif
+ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
+ LDFLAGS_vmlinux += --be8
+ endif
+@@ -151,6 +174,12 @@ lib1funcs = $(obj)/lib1funcs.o
+ $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S
+ 	$(call cmd,shipped)
+ 
++# For __aeabi_llsl
++ashldi3 = $(obj)/ashldi3.o
++
++$(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S
++	$(call cmd,shipped)
++
+ # We need to prevent any GOTOFF relocs being used with references
+ # to symbols in the .bss section since we cannot relocate them
+ # independently from the rest at run time.  This can be achieved by
+@@ -172,7 +201,7 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
+ fi
+ 
+ $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
+-	 	$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
++	 	$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) FORCE
+ 	@$(check_for_multiple_zreladdr)
+ 	$(call if_changed,ld)
+ 	@$(check_for_bad_syms)
+diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c
+index 6ce11c48..797f04be 100644
+--- a/arch/arm/boot/compressed/atags_to_fdt.c
++++ b/arch/arm/boot/compressed/atags_to_fdt.c
+@@ -77,6 +77,8 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)
+ 		} else if (atag->hdr.tag == ATAG_MEM) {
+ 			if (memcount >= sizeof(mem_reg_property)/4)
+ 				continue;
++			if (!atag->u.mem.size)
++				continue;
+ 			mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start);
+ 			mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size);
+ 		} else if (atag->hdr.tag == ATAG_INITRD2) {
+diff --git a/arch/arm/boot/compressed/boot_8210/Makefile b/arch/arm/boot/compressed/boot_8210/Makefile
+new file mode 100644
+index 00000000..b503f9ad
+--- /dev/null
++++ b/arch/arm/boot/compressed/boot_8210/Makefile
+@@ -0,0 +1,19 @@
++CFLAGS = -Wall -O2 -ffunction-sections -fdata-sections -fno-exceptions -fno-builtin -march=armv4 -msoft-float
++LDFLAGS = -nostdlib -Bstatic -T boot.lds -Ttext 0
++TARGET =start.bin
++START=start.o
++SOURCE=start.S
++
++AS = /usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-as
++	  
++all: clean start.bin
++
++start.bin : start.o
++	/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-ld $(LDFLAGS) $(START) -o start
++	/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-objcopy -O binary start start8210.bin
++    
++start.o:
++	/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-gcc $(CFLAGS) $(SOURCE) -c -o $(START)
++
++clean:
++	rm -f *.o *.bin start
+diff --git a/arch/arm/boot/compressed/boot_8210/boot.lds b/arch/arm/boot/compressed/boot_8210/boot.lds
+new file mode 100644
+index 00000000..5b957baf
+--- /dev/null
++++ b/arch/arm/boot/compressed/boot_8210/boot.lds
+@@ -0,0 +1,52 @@
++/*
++ * (C) Copyright 2000
++ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * 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
++ */
++
++OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
++OUTPUT_ARCH(arm)
++ENTRY(_start)
++SECTIONS
++{
++    . = 0x00000000;
++    _start = .;
++    
++    . = ALIGN(4);
++	.text      :
++	{
++	  	start.o	(.text)
++	  	*(.text)
++	}
++
++    . = ALIGN(4);
++    .rodata : { *(.rodata) }
++
++    . = ALIGN(4);
++    .data : { *(.data) }
++
++    . = ALIGN(4);
++    .got : { *(.got) }
++
++    . = ALIGN(4);
++    .bss : { *(.bss) }
++	
++	_end = .;
++}
+diff --git a/arch/arm/boot/compressed/boot_8210/readme.txt b/arch/arm/boot/compressed/boot_8210/readme.txt
+new file mode 100644
+index 00000000..2b3bd976
+--- /dev/null
++++ b/arch/arm/boot/compressed/boot_8210/readme.txt
+@@ -0,0 +1,11 @@
++This fold is designed to be boot code for PCI device boot.
++
++1.Compiler this gmboot_8181 by gcc
++  #make
++
++  start8210.bin is the boot code of PCI device.
++
++2.To translate it to HEX code, execute ex.bat in PC windows
++  D:\>ex.bat
++
++3.The start8210.c will be generated, you've copy it to 00_main
+\ No newline at end of file
+diff --git a/arch/arm/boot/compressed/boot_8210/start b/arch/arm/boot/compressed/boot_8210/start
+new file mode 100644
+index 00000000..59b7ed14
+Binary files /dev/null and b/arch/arm/boot/compressed/boot_8210/start differ
+diff --git a/arch/arm/boot/compressed/boot_8210/start.S b/arch/arm/boot/compressed/boot_8210/start.S
+new file mode 100644
+index 00000000..b6f5a838
+--- /dev/null
++++ b/arch/arm/boot/compressed/boot_8210/start.S
+@@ -0,0 +1,99 @@
++/*
++Offset 0x20 ==> command			0x33333333->0x06260626 => 626 has boot and run
++Offset 0x24 ==> boot pc			0xFFFFFFFF
++Offset 0x28 ==> response		0x0 -> 0x35737888
++ */
++ 
++reset:  b start_boot
++undef:  b undef
++swi:    b swi
++pref:   b pref
++dabt:   b dabt
++resv:   b resv
++irq:    b irq
++fiq:    b fiq
++
++_offset_command:            @ command at 0x20
++	.word 0x33333333        @ default value
++
++_offset_bootpc:             @ boot address at 0x24, FA726 will update it.
++	.word 0xFFFFFFFF        @ jump to address XXX
++
++_offset_response:           @ response at 0x28 to notice both ends
++	.word 0x0
++
++.globl _start,_end
++.globl _boot_start
++_boot_start:
++	.word _start
++
++.globl _boot_end
++_boot_end:
++	.word _end
++
++start_boot:
++    mov     r0, #0
++    mov     r1, #0
++    mov     r2, #0
++    mov     r3, #0
++    mov     r4, #0
++    mov     r5, #0
++    mov     r6, #0
++    mov     r7, #0      @reserved for counter
++    mov     r8, #0
++    mov     r9, #0
++    mov     r10, #0 
++    mov     r11, #0
++
++delay:    
++    //mov	r10, lr
++    
++    //delay for a while
++    ldr     r0, =0x10000
++    ldr     r1, =0x0
++myloop1:
++    sub     r0, r0, #1
++    cmp     r0, r1
++    bne     myloop1
++    //mov	    pc, r10
++    
++    //UART divisor to 38400
++    //ldr     r1, =0x98400000
++    //ldr     r0, =0x83
++    //str     r0, [r1,#0xc]
++    //ldr     r0, =0x14
++    //str     r0, [r1]
++    //ldr     r0, =0x3
++    //str     r0, [r1,#0xc]
++    //ldr     r0, =0x43
++    //str     r0, [r1]    
++    
++    //update the command to inform fa726, I am ok.
++    ldr     r2, =0x06260626
++    adr     r3, _offset_command
++    str     r2, [r3]
++    
++    ldr     r4, =0x35737888
++wait_response:
++    ldr     r5, _offset_response
++    cmp     r4, r5
++    beq     get_bootpc
++    //bl      delay
++    nop
++    nop
++    nop    
++    b       wait_response
++        
++/* jump to specified address */
++get_bootpc:
++    ldr     r2, =0x11111111
++    adr     r3, _offset_command
++    str     r2, [r3]
++    
++    ldr     r2, _offset_bootpc     @boot address
++    mov     pc, r2
++    nop
++    nop
++    nop
++    nop
++    nop
+\ No newline at end of file
+diff --git a/arch/arm/boot/compressed/boot_8210/start8210.bin b/arch/arm/boot/compressed/boot_8210/start8210.bin
+new file mode 100644
+index 00000000..70ff9fbe
+Binary files /dev/null and b/arch/arm/boot/compressed/boot_8210/start8210.bin differ
+diff --git a/arch/arm/boot/compressed/boot_8210/start8210.c b/arch/arm/boot/compressed/boot_8210/start8210.c
+new file mode 100644
+index 00000000..13ae0a87
+--- /dev/null
++++ b/arch/arm/boot/compressed/boot_8210/start8210.c
+@@ -0,0 +1,19 @@
++// This file is generated from a C program automatically
++__align(4) const unsigned char inner[] =
++{
++	0x0b, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, // 0x0 ~ 0xf
++	0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, // 0x10 ~ 0x1f
++	0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 ~ 0x2f
++	0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x20, 0xa0, 0xe3, // 0x30 ~ 0x3f
++	0x00, 0x30, 0xa0, 0xe3, 0x00, 0x40, 0xa0, 0xe3, 0x00, 0x50, 0xa0, 0xe3, 0x00, 0x60, 0xa0, 0xe3, // 0x40 ~ 0x4f
++	0x00, 0x70, 0xa0, 0xe3, 0x00, 0x80, 0xa0, 0xe3, 0x00, 0x90, 0xa0, 0xe3, 0x00, 0xa0, 0xa0, 0xe3, // 0x50 ~ 0x5f
++	0x00, 0xb0, 0xa0, 0xe3, 0x01, 0x08, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x01, 0x00, 0x40, 0xe2, // 0x60 ~ 0x6f
++	0x01, 0x00, 0x50, 0xe1, 0xfc, 0xff, 0xff, 0x1a, 0x4c, 0x20, 0x9f, 0xe5, 0x64, 0x30, 0x4f, 0xe2, // 0x70 ~ 0x7f
++	0x00, 0x20, 0x83, 0xe5, 0x44, 0x40, 0x9f, 0xe5, 0x68, 0x50, 0x1f, 0xe5, 0x05, 0x00, 0x54, 0xe1, // 0x80 ~ 0x8f
++	0x03, 0x00, 0x00, 0x0a, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, // 0x90 ~ 0x9f
++	0xf8, 0xff, 0xff, 0xea, 0x28, 0x20, 0x9f, 0xe5, 0x90, 0x30, 0x4f, 0xe2, 0x00, 0x20, 0x83, 0xe5, // 0xa0 ~ 0xaf
++	0x94, 0x20, 0x1f, 0xe5, 0x02, 0xf0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, // 0xb0 ~ 0xbf
++	0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x26, 0x06, 0x26, 0x06, // 0xc0 ~ 0xcf
++	0x88, 0x78, 0x73, 0x35, 0x11, 0x11, 0x11, 0x11
++};
++const unsigned int inner_len = sizeof (inner);
+\ No newline at end of file
+diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c
+index 07be5a2f..f41b38ca 100644
+--- a/arch/arm/boot/compressed/decompress.c
++++ b/arch/arm/boot/compressed/decompress.c
+@@ -44,6 +44,12 @@ extern void error(char *);
+ #include "../../../../lib/decompress_unlzma.c"
+ #endif
+ 
++#ifdef CONFIG_KERNEL_XZ
++#define memmove memmove
++#define memcpy memcpy
++#include "../../../../lib/decompress_unxz.c"
++#endif
++
+ int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
+ {
+ 	return decompress(input, len, NULL, NULL, output, NULL, error);
+diff --git a/arch/arm/boot/compressed/head-GM.S b/arch/arm/boot/compressed/head-GM.S
+new file mode 100644
+index 00000000..d8ac95d3
+--- /dev/null
++++ b/arch/arm/boot/compressed/head-GM.S
+@@ -0,0 +1,4 @@
++#include <asm/mach-types.h>
++
++		.section	".start", "ax"
++		ldr	r7, =MACH_TYPE_GM
+diff --git a/arch/arm/boot/compressed/head-faraday.S b/arch/arm/boot/compressed/head-faraday.S
+new file mode 100644
+index 00000000..74a16211
+--- /dev/null
++++ b/arch/arm/boot/compressed/head-faraday.S
+@@ -0,0 +1,4 @@
++#include <asm/mach-types.h>
++
++		.section	".start", "ax"
++		ldr	r7, =MACH_TYPE_FARADAY
+diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
+index c5d60250..2bb7b9a9 100644
+--- a/arch/arm/boot/compressed/head.S
++++ b/arch/arm/boot/compressed/head.S
+@@ -172,8 +172,22 @@ not_angel:
+ 		mov	r4, pc
+ 		and	r4, r4, #0xf8000000
+ 		add	r4, r4, #TEXT_OFFSET
++#else
++#ifdef CONFIG_PLATFORM_GM8210
++        mrc p15, 0, r9, c0, c0  @ get processor ID
++        ldr r3, =0x0000fff0
++        and r9, r9, r3
++        ldr r3, =0x00007260     @ check id if fa726 exists
++        cmp r9, r3
++        beq 1f
++        ldr r4, =zreladdr_fa626
++        b   2f
++1:
++        ldr r4, =zreladdr_fa726
++2:
+ #else
+ 		ldr	r4, =zreladdr
++#endif
+ #endif
+ 
+ 		bl	cache_on
+@@ -273,7 +287,7 @@ restart:	adr	r0, LC0
+ 		add	r0, r0, #0x100
+ 		mov	r1, r6
+ 		sub	r2, sp, r6
+-		blne	atags_to_fdt
++		bleq	atags_to_fdt
+ 
+ 		ldmfd	sp!, {r0-r3, ip, lr}
+ 		sub	sp, sp, #0x10000
+@@ -794,7 +808,7 @@ proc_types:
+ 		W(b)	__armv3_mpu_cache_on
+ 		W(b)	__armv3_mpu_cache_off
+ 		W(b)	__armv3_mpu_cache_flush
+-		
++
+ 		.word	0x41009400		@ ARM94x
+ 		.word	0xff00ff00
+ 		W(b)	__armv4_mpu_cache_on
+@@ -807,6 +821,12 @@ proc_types:
+ 		W(b)	__armv4_mmu_cache_off
+ 		W(b)	__armv5tej_mmu_cache_flush
+ 
++		.word	0x66057260		@ FA726, ARMv5TE
++		.word	0xff0ffff0
++		W(b)	__armv4_mmu_cache_on
++		W(b)	__armv4_mmu_cache_off
++		W(b)	__armv5tej_mmu_cache_flush
++
+ 		.word	0x00007000		@ ARM7 IDs
+ 		.word	0x0000f000
+ 		mov	pc, lr
+@@ -863,6 +883,12 @@ proc_types:
+ 		W(b)	__armv4_mmu_cache_off
+ 		W(b)	__fa526_cache_flush
+ 
++		.word	0x66056260		@ FA626TE
++		.word	0xff0ffff0
++		W(b)	__fa526_cache_on
++		W(b)	__armv4_mmu_cache_off
++		W(b)	__fa526_cache_flush
++
+ 		@ These match on the architecture ID
+ 
+ 		.word	0x00020000		@ ARMv4T
+@@ -1021,7 +1047,7 @@ __armv4_mpu_cache_flush:
+ 		mcrne	p15, 0, ip, c7, c5, 0	@ invalidate I cache
+ 		mcr	p15, 0, ip, c7, c10, 4	@ drain WB
+ 		mov	pc, lr
+-		
++
+ __fa526_cache_flush:
+ 		mov	r1, #0
+ 		mcr	p15, 0, r1, c7, c14, 0	@ clean and invalidate D cache
+diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
+index 8e2a8fca..1b473e17 100644
+--- a/arch/arm/boot/compressed/misc.c
++++ b/arch/arm/boot/compressed/misc.c
+@@ -1,7 +1,7 @@
+ /*
+  * misc.c
+- * 
+- * This is a collection of several routines from gzip-1.0.3 
++ *
++ * This is a collection of several routines from gzip-1.0.3
+  * adapted for Linux.
+  *
+  * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+@@ -10,7 +10,7 @@
+  *
+  * Nicolas Pitre <nico@visuaide.com>  1999/04/14 :
+  *  For this code to run directly from Flash, all constant variables must
+- *  be marked with 'const' and all other variables initialized at run-time 
++ *  be marked with 'const' and all other variables initialized at run-time
+  *  only.  This way all non constant variables will end up in the bss segment,
+  *  which should point to addresses in RAM and cleared to 0 on start.
+  *  This allows for a much quicker boot time.
+@@ -83,6 +83,51 @@ static void icedcc_putc(int ch)
+ #define putc(ch)	icedcc_putc(ch)
+ #endif
+ 
++#define CPU_FA726   0x1
++#define CPU_FA626   0x2
++#define PCI_HOST    0x40
++#define PCI_DEV     0x80
++
++#ifdef CONFIG_PLATFORM_GM8210
++/* return x0:726, x1:626, 1x:device */
++static unsigned int mode_detect(void)
++{
++	u32 ret = 0;
++	u32 value;
++
++    value = (readl(PMU_FTPMU010_PA_BASE + 0x04) >> 19) & 0x3;
++    if (value == 0x1)
++		ret |= PCI_DEV;
++    else
++        ret |= PCI_HOST;
++
++	__asm__ __volatile__ ("mrc p15, 0, %0, c0, c0, 0\t\n": "=r"(value));
++
++	if (((value >> 0x4) & 0xFFF) == 0x626)
++     	ret |= CPU_FA626;
++    else
++        ret |= CPU_FA726;
++
++	return ret;
++}
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8210
++static void gm_putc(int c)
++{
++    unsigned long base;
++
++    base = (mode_detect() & CPU_FA726) ? UART_FTUART010_0_PA_BASE : UART_FTUART010_1_PA_BASE;
++
++    while ((readl(base + SERIAL_LSR) & SERIAL_LSR_THRE) == 0)
++        barrier();
++
++    writel(c, base + SERIAL_THR);
++}
++
++#define putc(ch)	gm_putc(ch)
++#endif /* CONFIG_PLATFORM_GM8210 */
++
+ static void putstr(const char *ptr)
+ {
+ 	char c;
+@@ -127,8 +172,18 @@ asmlinkage void __div0(void)
+ 	error("Attempting division by 0!");
+ }
+ 
++#ifdef CONFIG_PLATFORM_GM8210
++#include "start8210.c"
++unsigned int boot_addr = 0;
++#endif /* CONFIG_PLATFORM_GM8210 */
++
+ extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));
+ 
++#define BOOT_IMAGE_SIZE     0x200
++#define FC7500_ADDR_LIMIT   0x1000000
++#define FA626_SIGNATURE     0x06260626
++#define FA626_BOOT_PC       0x18100040  //changeable, 256+128MB+0x40 uImage header
++#define FA626_GO            0x35737888
+ 
+ void
+ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
+@@ -151,4 +206,115 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
+ 		error("decompressor returned an error");
+ 	else
+ 		putstr(" done, booting the kernel.\n");
++
++#ifdef CONFIG_FA626
++    /*
++     * 1. copy the bootcode to the memory address 0x0
++     * 2. copy linux image of FA626 to the designate address.
++     * 3. let the FA626 CPU go.
++     * FA626 boot flow:
++     *  a. FA726 waits FA626 to update 0x20(command offset) to FA626_SIGNATURE
++     *  b. FA626 starts to wait 0x28 to be FA626_GO
++     *  c. FA726 updates 0x24 to FA626_BOOT_PC and then updates 0x28 to FA626_GO
++     *  d. FA626 loads FA626_BOOT_PC from 0x24 and jumps to specific PC.
++     *
++     * Note: in __setup_mmu of head.S, the zero address is mapped to NCNB in MMU already and whole
++     *       4G memory is created to 1:1 mapping.
++     */
++    if (mode_detect() & CPU_FA726) {
++        volatile unsigned int val, i, ttbr;
++
++        /* work around to turn on write buffer */
++        __asm__ __volatile__ ("mrc p15, 0, %0, c15, c0, 0\t\n":"=r"(val));
++        val |= (0x1 << 20);
++        __asm__ __volatile__ ("mcr p15, 0, %0, c15, c0, 0\t\n":"=r"(val));
++
++       /*
++        * copy the target image to the designate address and then decompress the image
++        * Note: the MMU was established in __setup_mmu of head.S and the memory address from 0 ~
++        * 0x01800000 is created in NCNB(see mov	r9, r0, lsr #18 and mov	r9, r9, lsl #18 of head.S),
++        * so we don't need to consider cache sync problem. But for safety, we still do the sanity
++        * check.
++        */
++
++#ifdef CONFIG_FC7500
++	    /* copy the start code and linux
++	     */
++	    putstr("start to copy FC7500 core boot image at 0x18100000 and wait response... \n");
++
++	    /* because memory address 0 contains FC7500 image, so we need to
++	     * copy the front part of FC7500 to specific memory address for backup. FA626 will move it
++	     * back.
++	     */
++		memcpy((char *)(FC7500_ADDR_LIMIT - BOOT_IMAGE_SIZE), (char *)boot_addr, BOOT_IMAGE_SIZE);
++#endif
++	    /* copy boot image */
++	    memcpy((char *)boot_addr, inner, sizeof(inner));
++
++	    /* for safety only, actually it is unnecessary because of 0-16M is NCNB in head.S */
++	    __asm__ __volatile__ ("mrc p15, 0, %0, c2, c0, 0\t\n":"=r"(ttbr));
++	    val = *((unsigned int *)ttbr);  //get first 1M for boot_addr
++	    if (val & 0xc) {
++	        /* for safety only, actually it is unnecessary */
++	        __asm__ __volatile__ ("mov r3, #0\n"
++	                              "mcr p15, 0, r3, c7, c10, 3\n"    /* Test and Clean DCache */
++	                              "mcr p15, 0, r3, c7, c10, 4");	/* drain WB */
++	       putstr("The start address in MMU is unexpected! \n");
++	    }
++
++	    //delay for a while to retire DDR write buffer
++	    for (i = 0; i < 0x1000; i ++) {}
++
++        //copy flash image for 626.
++
++        /* step 1: release the fa626 reset
++         */
++        *(unsigned int *)(PMU_FTPMU010_PA_BASE + 0x4) |= (1 << 17);
++
++        /* step 2: turn on fclk
++         */
++        val = *(unsigned int *)(PMU_FTPMU010_PA_BASE + 0xC);
++        val &= ~(0x1 << 6);
++        *(unsigned int *)(PMU_FTPMU010_PA_BASE + 0xC) = val;
++
++        /* wait FA6 to update the response flag. 0x20 default value is 0x33333333
++         */
++        do {
++            val = *(volatile unsigned int *)(boot_addr + 0x20);
++        } while (val != FA626_SIGNATURE);
++
++        putstr("wait FA6 core response ok \n");
++        *(unsigned int *)(boot_addr + 0x24) = FA626_BOOT_PC;
++        *(unsigned int *)(boot_addr + 0x28) = FA626_GO;  //start to boot FA626
++
++        /* before moving pc to boot address, FA626 will update the staus again */
++        do {
++            val = *(volatile unsigned int *)(boot_addr + 0x20);
++        } while (val == FA626_SIGNATURE);
++        putstr("done, FA7 core now is booting. \n");
++
++    }
++#endif /* CONFIG_FA626 */
++
++#ifdef CONFIG_FC7500
++    /* only FA626 can copy FC7500 images to specific address */
++	if ((mode_detect() & CPU_FA626) == CPU_FA626) {
++        volatile unsigned int i, tmp_size = BOOT_IMAGE_SIZE, src_base = FC7500_ADDR_LIMIT - BOOT_IMAGE_SIZE;
++
++        /* copy the start code and linux
++         */
++        putstr("start to copy FC7500 core boot image... \n");
++
++        memcpy((char *)boot_addr, (char *)src_base, tmp_size);
++
++        for (i = 0; i < 0x1000; i ++) {}
++
++        /* pmu go
++         */
++        *(unsigned int *)(PMU_FTPMU010_PA_BASE + 0x4) |= (1 << 18);
++
++        putstr("done, FA6 core now is booting. \n");
++    }
++#endif
++
+ }
+diff --git a/arch/arm/boot/compressed/piggy.xzkern.S b/arch/arm/boot/compressed/piggy.xzkern.S
+new file mode 100644
+index 00000000..5703f300
+--- /dev/null
++++ b/arch/arm/boot/compressed/piggy.xzkern.S
+@@ -0,0 +1,6 @@
++	.section .piggydata,#alloc
++	.globl	input_data
++input_data:
++	.incbin	"arch/arm/boot/compressed/piggy.xzkern"
++	.globl	input_data_end
++input_data_end:
+diff --git a/arch/arm/boot/compressed/start8210.c b/arch/arm/boot/compressed/start8210.c
+new file mode 100644
+index 00000000..4427fd72
+--- /dev/null
++++ b/arch/arm/boot/compressed/start8210.c
+@@ -0,0 +1,19 @@
++// This file is generated from a C program automatically
++const unsigned char inner[] =
++{
++	0x0b, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, // 0x0 ~ 0xf
++	0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, // 0x10 ~ 0x1f
++	0x33, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 ~ 0x2f
++	0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x20, 0xa0, 0xe3, // 0x30 ~ 0x3f
++	0x00, 0x30, 0xa0, 0xe3, 0x00, 0x40, 0xa0, 0xe3, 0x00, 0x50, 0xa0, 0xe3, 0x00, 0x60, 0xa0, 0xe3, // 0x40 ~ 0x4f
++	0x00, 0x70, 0xa0, 0xe3, 0x00, 0x80, 0xa0, 0xe3, 0x00, 0x90, 0xa0, 0xe3, 0x00, 0xa0, 0xa0, 0xe3, // 0x50 ~ 0x5f
++	0x00, 0xb0, 0xa0, 0xe3, 0x01, 0x08, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x01, 0x00, 0x40, 0xe2, // 0x60 ~ 0x6f
++	0x01, 0x00, 0x50, 0xe1, 0xfc, 0xff, 0xff, 0x1a, 0x4c, 0x20, 0x9f, 0xe5, 0x64, 0x30, 0x4f, 0xe2, // 0x70 ~ 0x7f
++	0x00, 0x20, 0x83, 0xe5, 0x44, 0x40, 0x9f, 0xe5, 0x68, 0x50, 0x1f, 0xe5, 0x05, 0x00, 0x54, 0xe1, // 0x80 ~ 0x8f
++	0x03, 0x00, 0x00, 0x0a, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, // 0x90 ~ 0x9f
++	0xf8, 0xff, 0xff, 0xea, 0x28, 0x20, 0x9f, 0xe5, 0x90, 0x30, 0x4f, 0xe2, 0x00, 0x20, 0x83, 0xe5, // 0xa0 ~ 0xaf
++	0x94, 0x20, 0x1f, 0xe5, 0x02, 0xf0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, // 0xb0 ~ 0xbf
++	0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x26, 0x06, 0x26, 0x06, // 0xc0 ~ 0xcf
++	0x88, 0x78, 0x73, 0x35, 0x11, 0x11, 0x11, 0x11
++};
++const unsigned int inner_len = sizeof (inner);
+diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts
+index 305635bd..37c0ff9c 100644
+--- a/arch/arm/boot/dts/highbank.dts
++++ b/arch/arm/boot/dts/highbank.dts
+@@ -72,15 +72,15 @@
+ 		ranges;
+ 
+ 		timer@fff10600 {
+-			compatible = "arm,smp-twd";
++			compatible = "arm,cortex-a9-twd-timer";
+ 			reg = <0xfff10600 0x20>;
+-			interrupts = <1 13 0xf04>;
++			interrupts = <1 13 0xf01>;
+ 		};
+ 
+ 		watchdog@fff10620 {
+-			compatible = "arm,cortex-a9-wdt";
++			compatible = "arm,cortex-a9-twd-wdt";
+ 			reg = <0xfff10620 0x20>;
+-			interrupts = <1 14 0xf04>;
++			interrupts = <1 14 0xf01>;
+ 		};
+ 
+ 		intc: interrupt-controller@fff11000 {
+diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
+index 263e8f36..4905f51a 100644
+--- a/arch/arm/boot/dts/imx6q.dtsi
++++ b/arch/arm/boot/dts/imx6q.dtsi
+@@ -88,9 +88,9 @@
+ 		ranges;
+ 
+ 		timer@00a00600 {
+-			compatible = "arm,smp-twd";
+-			reg = <0x00a00600 0x100>;
+-			interrupts = <1 13 0xf4>;
++			compatible = "arm,cortex-a9-twd-timer";
++			reg = <0x00a00600 0x20>;
++			interrupts = <1 13 0xf01>;
+ 		};
+ 
+ 		L2: l2-cache@00a02000 {
+diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
+index c47d6199..ca6b5dd6 100644
+--- a/arch/arm/common/gic.c
++++ b/arch/arm/common/gic.c
+@@ -694,13 +694,12 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
+ 	 * For primary GICs, skip over SGIs.
+ 	 * For secondary GICs, skip over PPIs, too.
+ 	 */
+-	domain->hwirq_base = 32;
+-	if (gic_nr == 0) {
+-		if ((irq_start & 31) > 0) {
+-			domain->hwirq_base = 16;
+-			if (irq_start != -1)
+-				irq_start = (irq_start & ~31) + 16;
+-		}
++	if (gic_nr == 0 && (irq_start & 31) > 0) {
++		domain->hwirq_base = 16;
++		if (irq_start != -1)
++			irq_start = (irq_start & ~31) + 16;
++	} else {
++		domain->hwirq_base = 32;
+ 	}
+ 
+ 	/*
+diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
+index dcb004a8..cb6b49ad 100644
+--- a/arch/arm/common/vic.c
++++ b/arch/arm/common/vic.c
+@@ -441,11 +441,9 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
+ 	u32 stat, irq;
+ 	int handled = 0;
+ 
+-	stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
+-	while (stat) {
++	while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
+ 		irq = ffs(stat) - 1;
+ 		handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs);
+-		stat &= ~(1 << irq);
+ 		handled = 1;
+ 	}
+ 
+diff --git a/arch/arm/configs/GM8126_defconfig b/arch/arm/configs/GM8126_defconfig
+new file mode 100644
+index 00000000..96577a7d
+--- /dev/null
++++ b/arch/arm/configs/GM8126_defconfig
+@@ -0,0 +1,1724 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_FIQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../target/rootfs-cpio"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_OPROFILE is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++CONFIG_FTINTC010EX=y
++CONFIG_PLATFORM_GM8126=y
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=240000000
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=1000
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,38400 mem=128M"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK_ACCT is not set
++# CONFIG_NETFILTER_NETLINK_QUEUE is not set
++# CONFIG_NETFILTER_NETLINK_LOG is not set
++# CONFIG_NF_CONNTRACK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_GM is not set
++# CONFIG_MTD_GPIO_ADDR is not set
++# CONFIG_MTD_PLATRAM is not set
++# CONFIG_MTD_LATCH_ADDR is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++# CONFIG_MTD_NAND is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_PROC_FS is not set
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_ISCSI_BOOT_SYSFS is not set
++# CONFIG_LIBFC is not set
++# CONFIG_LIBFCOE is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++# CONFIG_FTGMAC100 is not set
++CONFIG_FTMAC110=y
++CONFIG_FTMAC110_PHYADDR=1
++# CONFIG_FTMAC110_PHYMON is not set
++CONFIG_FTMAC110_NDESC_TX=256
++CONFIG_FTMAC110_NDESC_RX=256
++CONFIG_FTMAC110_NAPI=y
++CONFIG_FTMAC110_NAPI_LRO=y
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++CONFIG_PPP=y
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPP_DEFLATE is not set
++CONFIG_PPP_FILTER=y
++# CONFIG_PPP_MPPE is not set
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOE=y
++CONFIG_PPP_ASYNC=y
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=y
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++# CONFIG_SPI_FTSPI020 is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++# CONFIG_GPIO_SYSFS is not set
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_FTGPIO010 is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=m
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_EHCI_HCD is not set
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++CONFIG_EXT2_FS_SECURITY=y
++CONFIG_EXT2_FS_XIP=y
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_FS_XIP=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++# CONFIG_TMPFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8129_FPGA_defconfig b/arch/arm/configs/GM8129_FPGA_defconfig
+new file mode 100644
+index 00000000..fe3bacb4
+--- /dev/null
++++ b/arch/arm/configs/GM8129_FPGA_defconfig
+@@ -0,0 +1,1257 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../target/rootfs-cpio"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_FTINTC010EX is not set
++# CONFIG_PLATFORM_GM8126 is not set
++# CONFIG_PLATFORM_GM8287 is not set
++CONFIG_PLATFORM_GM8129=y
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++CONFIG_FPGA=y
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=1000
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,38400 mem=128M"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++CONFIG_INET_TUNNEL=m
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++# CONFIG_INET_LRO is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++CONFIG_IPV6=m
++# CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
++# CONFIG_IPV6_OPTIMISTIC_DAD is not set
++# CONFIG_INET6_AH is not set
++# CONFIG_INET6_ESP is not set
++# CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++CONFIG_IPV6_SIT=m
++# CONFIG_IPV6_SIT_6RD is not set
++CONFIG_IPV6_NDISC_NODETYPE=y
++# CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_IPV6_MROUTE is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++# CONFIG_BLK_DEV is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_93CX6 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++
++#
++# Altera FPGA firmware download module
++#
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0=y
++# CONFIG_FTGMAC100_DRIVER_1 is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_WLAN=y
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++# CONFIG_I2C is not set
++# CONFIG_SPI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++# CONFIG_USB_SUPPORT is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++CONFIG_EXT2_FS_SECURITY=y
++CONFIG_EXT2_FS_XIP=y
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_FS_XIP=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++# CONFIG_TMPFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++# CONFIG_NFS_FS is not set
++# CONFIG_NFSD is not set
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8136_defconfig b/arch/arm/configs/GM8136_defconfig
+new file mode 100644
+index 00000000..a9d96222
+--- /dev/null
++++ b/arch/arm/configs/GM8136_defconfig
+@@ -0,0 +1,1681 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPUFREQ=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++# CONFIG_KERNEL_GZIP is not set
++CONFIG_KERNEL_LZMA=y
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_PLATFORM_GM8126 is not set
++# CONFIG_PLATFORM_GM8287 is not set
++# CONFIG_PLATFORM_GM8139 is not set
++CONFIG_PLATFORM_GM8136=y
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++# CONFIG_FPGA is not set
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 mem=256M gmmem=190M user_debug=31 init=/squashfs_init root=/dev/mtdblock4 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_STAT is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++# CONFIG_CFG80211 is not set
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++# CONFIG_PROC_EVENTS is not set
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_FTNANDC023 is not set
++# CONFIG_MTD_NAND_FTNANDC024V2 is not set
++CONFIG_MTD_NAND_FTSPINAND020=y
++CONFIG_SPI_NAND_USE_AHBDMA=y
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_IWMC3200TOP is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++CONFIG_FTMAC_TINY=y
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++CONFIG_SERIAL_UART1_IP=y
++CONFIG_SERIAL_UART2_IP=y
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++CONFIG_FTSPI020_USE_AHBDMA=y
++# CONFIG_FTSPI020_USE_AXIDMA is not set
++# CONFIG_SPI_FTSSP010 is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_FTWDT010_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_PHY_TEST is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PLTFM=y
++CONFIG_MMC_FTSDC021=y
++CONFIG_SDC0_IP=y
++CONFIG_MMC_FTSDC021_VEND_TUNE=y
++# CONFIG_SDC1_IP is not set
++# CONFIG_MMC_CD_INVERSE is not set
++# CONFIG_MMC_SPI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++# CONFIG_SQUASHFS_ZLIB is not set
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_ALGAPI2=m
++CONFIG_CRYPTO_RNG=m
++CONFIG_CRYPTO_RNG2=m
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_MANAGER2 is not set
++# CONFIG_CRYPTO_USER is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=m
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++CONFIG_CRYPTO_ANSI_CPRNG=m
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8136_defconfig_glibc b/arch/arm/configs/GM8136_defconfig_glibc
+new file mode 100644
+index 00000000..042abebc
+--- /dev/null
++++ b/arch/arm/configs/GM8136_defconfig_glibc
+@@ -0,0 +1,1680 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPUFREQ=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/arm-none-linux-gnueabi-4.4.0_linux-3.3/bin/arm-none-linux-gnueabi-"
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_PLATFORM_GM8126 is not set
++# CONFIG_PLATFORM_GM8287 is not set
++# CONFIG_PLATFORM_GM8139 is not set
++CONFIG_PLATFORM_GM8136=y
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++# CONFIG_FPGA is not set
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 mem=256M gmmem=190M user_debug=31 init=/squashfs_init root=/dev/mtdblock4 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_STAT is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++# CONFIG_CFG80211 is not set
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++# CONFIG_PROC_EVENTS is not set
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_FTNANDC023 is not set
++# CONFIG_MTD_NAND_FTNANDC024V2 is not set
++CONFIG_MTD_NAND_FTSPINAND020=y
++CONFIG_SPI_NAND_USE_AHBDMA=y
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_IWMC3200TOP is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++CONFIG_FTMAC_TINY=y
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++CONFIG_SERIAL_UART1_IP=y
++CONFIG_SERIAL_UART2_IP=y
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++CONFIG_FTSPI020_USE_AHBDMA=y
++# CONFIG_FTSPI020_USE_AXIDMA is not set
++# CONFIG_SPI_FTSSP010 is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_FTWDT010_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_PHY_TEST is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PLTFM=y
++CONFIG_MMC_FTSDC021=y
++CONFIG_SDC0_IP=y
++# CONFIG_SDC1_IP is not set
++# CONFIG_MMC_CD_INVERSE is not set
++# CONFIG_MMC_SPI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++# CONFIG_SQUASHFS_ZLIB is not set
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_ALGAPI2=m
++CONFIG_CRYPTO_RNG=m
++CONFIG_CRYPTO_RNG2=m
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_MANAGER2 is not set
++# CONFIG_CRYPTO_USER is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=m
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++CONFIG_CRYPTO_ANSI_CPRNG=m
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8136_lite_defconfig b/arch/arm/configs/GM8136_lite_defconfig
+new file mode 100644
+index 00000000..19562ad9
+--- /dev/null
++++ b/arch/arm/configs/GM8136_lite_defconfig
+@@ -0,0 +1,1444 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPUFREQ=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++# CONFIG_KERNEL_GZIP is not set
++CONFIG_KERNEL_LZMA=y
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++# CONFIG_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_GM_SMP is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_PLATFORM_GM8126 is not set
++# CONFIG_PLATFORM_GM8287 is not set
++# CONFIG_PLATFORM_GM8139 is not set
++CONFIG_PLATFORM_GM8136=y
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++# CONFIG_FPGA is not set
++CONFIG_VIDEO_FASTTHROUGH=y
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_CA9 is not set
++# CONFIG_CPU_CA7 is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++CONFIG_COMPACTION=y
++CONFIG_MIGRATION=y
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 mem=256M gmmem=190M user_debug=31 init=/squashfs_init root=/dev/mtdblock4 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++# CONFIG_CPU_FREQ_STAT is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=m
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++# CONFIG_WIRELESS is not set
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++# CONFIG_PROC_EVENTS is not set
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++# CONFIG_MTD_NAND is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++CONFIG_FTMAC_TINY=y
++# CONFIG_FTGMAC030 is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++CONFIG_SERIAL_UART1_IP=y
++CONFIG_SERIAL_UART2_IP=y
++# CONFIG_SERIAL_CTSRTS is not set
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++CONFIG_FTSPI020_USE_AHBDMA=y
++# CONFIG_FTSPI020_USE_AXIDMA is not set
++# CONFIG_SPI_FTSSP010 is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_FTWDT010_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++# CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++# CONFIG_USB_SUPPORT is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_FILE_LOCKING is not set
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++# CONFIG_MSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++# CONFIG_SQUASHFS_ZLIB is not set
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_NETWORK_FILESYSTEMS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_ALGAPI2=m
++CONFIG_CRYPTO_RNG=m
++CONFIG_CRYPTO_RNG2=m
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_MANAGER2 is not set
++# CONFIG_CRYPTO_USER is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=m
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++CONFIG_CRYPTO_ANSI_CPRNG=m
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++# CONFIG_CRYPTO_HW is not set
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++# CONFIG_XZ_DEC_X86 is not set
++# CONFIG_XZ_DEC_POWERPC is not set
++# CONFIG_XZ_DEC_IA64 is not set
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++# CONFIG_XZ_DEC_SPARC is not set
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8139_FPGA_defconfig b/arch/arm/configs/GM8139_FPGA_defconfig
+new file mode 100644
+index 00000000..2793300e
+--- /dev/null
++++ b/arch/arm/configs/GM8139_FPGA_defconfig
+@@ -0,0 +1,1320 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../target/rootfs-cpio"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_PLATFORM_GM8126 is not set
++# CONFIG_PLATFORM_GM8287 is not set
++CONFIG_PLATFORM_GM8139=y
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++CONFIG_FPGA=y
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=1000
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,38400 mem=128M user_debug=31"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++# CONFIG_CONNECTOR is not set
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++# CONFIG_BLK_DEV is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_93CX6 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++
++#
++# Altera FPGA firmware download module
++#
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0=y
++# CONFIG_FTGMAC100_DRIVER_1 is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_WLAN=y
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=1
++CONFIG_SERIAL_8250_RUNTIME_UARTS=1
++# CONFIG_SERIAL_UART1_IP is not set
++# CONFIG_SERIAL_UART2_IP is not set
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_SPI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++# CONFIG_USB_SUPPORT is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM813x_defconfig b/arch/arm/configs/GM813x_defconfig
+new file mode 100644
+index 00000000..6e841e69
+--- /dev/null
++++ b/arch/arm/configs/GM813x_defconfig
+@@ -0,0 +1,1828 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPUFREQ=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_PLATFORM_GM8126 is not set
++# CONFIG_PLATFORM_GM8287 is not set
++CONFIG_PLATFORM_GM8139=y
++# CONFIG_PLATFORM_GM8136 is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++# CONFIG_FPGA is not set
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++# CONFIG_CPU_FA626TE is not set
++CONFIG_CPU_FA726TE=y
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++CONFIG_OUTER_CACHE=y
++CONFIG_OUTER_CACHE_SYNC=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_CACHE_FTL2CC031=y
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 mem=256M gmmem=190M user_debug=31 init=/squashfs_init root=/dev/mtdblock2 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++CONFIG_CPU_FREQ_STAT=y
++CONFIG_CPU_FREQ_STAT_DETAILS=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++# CONFIG_CFG80211 is not set
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_FTNANDC023 is not set
++CONFIG_MTD_NAND_FTNANDC024V2=y
++CONFIG_MTD_NAND_FTSPINAND020=y
++CONFIG_SPI_NAND_USE_AHBDMA=y
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_IWMC3200TOP is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_ISCSI_BOOT_SYSFS is not set
++# CONFIG_LIBFC is not set
++# CONFIG_LIBFCOE is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++# CONFIG_FTMAC_TINY is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=2
++CONFIG_SERIAL_8250_RUNTIME_UARTS=2
++CONFIG_SERIAL_UART1_IP=y
++# CONFIG_SERIAL_UART2_IP is not set
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++CONFIG_FTSPI020_USE_AHBDMA=y
++# CONFIG_FTSPI020_USE_AXIDMA is not set
++# CONFIG_SPI_FTSSP010 is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_PHY_TEST is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PLTFM=y
++CONFIG_MMC_FTSDC021=y
++CONFIG_MMC_FTSDC021_VEND_TUNE=y
++# CONFIG_MMC_CD_INVERSE is not set
++# CONFIG_MMC_SPI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++# CONFIG_RTC_HCTOSYS is not set
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_ISL12022 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++# CONFIG_RTC_DRV_EM3027 is not set
++# CONFIG_RTC_DRV_RV3029C2 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T93 is not set
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_CMOS is not set
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM813x_defconfig_glibc b/arch/arm/configs/GM813x_defconfig_glibc
+new file mode 100644
+index 00000000..b59dc81c
+--- /dev/null
++++ b/arch/arm/configs/GM813x_defconfig_glibc
+@@ -0,0 +1,1827 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPUFREQ=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/arm-none-linux-gnueabi-4.4.0_linux-3.3/bin/arm-none-linux-gnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_PLATFORM_GM8126 is not set
++# CONFIG_PLATFORM_GM8287 is not set
++CONFIG_PLATFORM_GM8139=y
++# CONFIG_PLATFORM_GM8136 is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++# CONFIG_FPGA is not set
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++# CONFIG_CPU_FA626TE is not set
++CONFIG_CPU_FA726TE=y
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++CONFIG_OUTER_CACHE=y
++CONFIG_OUTER_CACHE_SYNC=y
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_CACHE_FTL2CC031=y
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 mem=256M gmmem=190M user_debug=31 init=/squashfs_init root=/dev/mtdblock2 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++
++#
++# CPU Frequency scaling
++#
++CONFIG_CPU_FREQ=y
++CONFIG_CPU_FREQ_TABLE=y
++CONFIG_CPU_FREQ_STAT=y
++CONFIG_CPU_FREQ_STAT_DETAILS=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
++# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
++CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
++CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
++CONFIG_CPU_FREQ_GOV_POWERSAVE=y
++CONFIG_CPU_FREQ_GOV_USERSPACE=y
++CONFIG_CPU_FREQ_GOV_ONDEMAND=y
++# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
++
++#
++# ARM CPU frequency scaling drivers
++#
++# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++# CONFIG_CFG80211 is not set
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_FTNANDC023 is not set
++CONFIG_MTD_NAND_FTNANDC024V2=y
++CONFIG_MTD_NAND_FTSPINAND020=y
++CONFIG_SPI_NAND_USE_AHBDMA=y
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_IWMC3200TOP is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_ISCSI_BOOT_SYSFS is not set
++# CONFIG_LIBFC is not set
++# CONFIG_LIBFCOE is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++# CONFIG_FTMAC_TINY is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=2
++CONFIG_SERIAL_8250_RUNTIME_UARTS=2
++CONFIG_SERIAL_UART1_IP=y
++# CONFIG_SERIAL_UART2_IP is not set
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++CONFIG_FTSPI020_USE_AHBDMA=y
++# CONFIG_FTSPI020_USE_AXIDMA is not set
++# CONFIG_SPI_FTSSP010 is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_PHY_TEST is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PLTFM=y
++CONFIG_MMC_FTSDC021=y
++# CONFIG_MMC_CD_INVERSE is not set
++# CONFIG_MMC_SPI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++# CONFIG_RTC_HCTOSYS is not set
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_ISL12022 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++# CONFIG_RTC_DRV_EM3027 is not set
++# CONFIG_RTC_DRV_RV3029C2 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T93 is not set
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_CMOS is not set
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8210_1G_defconfig b/arch/arm/configs/GM8210_1G_defconfig
+new file mode 100644
+index 00000000..9347565b
+--- /dev/null
++++ b/arch/arm/configs/GM8210_1G_defconfig
+@@ -0,0 +1,1893 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_FIQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++# CONFIG_KERNEL_GZIP is not set
++CONFIG_KERNEL_LZMA=y
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++CONFIG_RD_LZMA=y
++CONFIG_RD_XZ=y
++# CONFIG_RD_LZO is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_OPROFILE is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++# CONFIG_ARCH_GM is not set
++CONFIG_ARCH_GM_DUO=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++CONFIG_FTDMAC030=y
++# CONFIG_FTINTC010EX is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++CONFIG_PLATFORM_GM8210=y
++
++#
++# GM Platform Options
++#
++CONFIG_GM8210_TIMER_HZ=100
++CONFIG_PLATFORM_AXIDMA=y
++CONFIG_FA626=y
++CONFIG_FC7500=y
++CONFIG_GM8312=y
++CONFIG_GM8210_EP_MODE=y
++# CONFIG_GM8210_FPGA is not set
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++# CONFIG_CPU_FA626TE is not set
++CONFIG_CPU_FA726TE=y
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++# CONFIG_NO_HZ is not set
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=240M@0x01000000 gmmem=30M console=ttyS0,115200 user_debug=31 init=/squashfs_init root=/dev/mtdblock4 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK_ACCT is not set
++# CONFIG_NETFILTER_NETLINK_QUEUE is not set
++# CONFIG_NETFILTER_NETLINK_LOG is not set
++# CONFIG_NF_CONNTRACK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++# CONFIG_CFG80211 is not set
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++# CONFIG_MTD_GPIO_ADDR is not set
++# CONFIG_MTD_PLATRAM is not set
++# CONFIG_MTD_LATCH_ADDR is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_FTNANDC023=y
++# CONFIG_NAND_USE_AHBDMA is not set
++# CONFIG_NAND_USE_AXIDMA is not set
++CONFIG_FTNANDC023_DEBUG=0
++# CONFIG_GPIO_WP is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=1
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_IWMC3200TOP is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_EXTERNAL_CRYSTAL_CLOCK is not set
++# CONFIG_EP_SATA_ENABLE is not set
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++# CONFIG_FTGMAC100_DRIVER_0_SLAVE is not set
++# CONFIG_FTGMAC100_DRIVER_1_MASTER is not set
++CONFIG_FTGMAC100_DRIVER_1_SLAVE=y
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++CONFIG_PPP=y
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPP_DEFLATE is not set
++CONFIG_PPP_FILTER=y
++# CONFIG_PPP_MPPE is not set
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOE=y
++CONFIG_PPP_ASYNC=y
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=y
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=6
++CONFIG_SERIAL_8250_RUNTIME_UARTS=6
++CONFIG_SERIAL_UART2_IP=y
++CONFIG_SERIAL_UART3_IP=y
++# CONFIG_SERIAL_UART4_IP is not set
++CONFIG_SERIAL_UART5_IP=y
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++# CONFIG_I2C_INTERRUPT_MODE is not set
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++# CONFIG_FTSPI020_USE_AHBDMA is not set
++CONFIG_FTSPI020_USE_AXIDMA=y
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_FTWDT010_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++CONFIG_SOUND_OSS_CORE_PRECLAIM=y
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_HRTIMER is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++# CONFIG_SND_RAWMIDI_SEQ is not set
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARM is not set
++# CONFIG_SND_SPI is not set
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_UA101 is not set
++# CONFIG_SND_USB_CAIAQ is not set
++# CONFIG_SND_USB_6FIRE is not set
++# CONFIG_SND_SOC is not set
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_PRODIKEYS is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_EYE_DIAGRAM is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=y
++CONFIG_MMC_SDHCI_PLTFM=y
++CONFIG_MMC_FTSDC021=y
++# CONFIG_MMC_SPI is not set
++# CONFIG_MMC_DW is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++# CONFIG_ZISOFS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_DECOMPRESS_XZ=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8210_FA726_1G_only b/arch/arm/configs/GM8210_FA726_1G_only
+new file mode 100644
+index 00000000..c176d5fb
+--- /dev/null
++++ b/arch/arm/configs/GM8210_FA726_1G_only
+@@ -0,0 +1,1792 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_PLATFORM_GM8210=y
++CONFIG_FIQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++# CONFIG_KERNEL_GZIP is not set
++CONFIG_KERNEL_LZMA=y
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++# CONFIG_ARCH_GM is not set
++CONFIG_ARCH_GM_DUO=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++CONFIG_FTDMAC030=y
++# CONFIG_FTINTC010EX is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++CONFIG_PLATFORM_GM8210_M=y
++# CONFIG_PLATFORM_GM8210_S is not set
++
++#
++# GM Platform Options
++#
++CONFIG_GM8210_M_HZ=1000
++CONFIG_PLATFORM_AXIDMA=y
++# CONFIG_FA626 is not set
++CONFIG_GM8312=y
++# CONFIG_GM8210_FPGA is not set
++# CONFIG_GM8210_EP_MODE is not set
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++# CONFIG_CPU_FA626TE is not set
++CONFIG_CPU_FA726TE=y
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++# CONFIG_NO_HZ is not set
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=1000
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=496M@0x01000000 gmmem=256M console=ttyS0,115200 mem=512M@0x20000000 user_debug=31 init=/squashfs_init root=/dev/mtdblock4 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++CONFIG_IP_ADVANCED_ROUTER=y
++# CONFIG_IP_FIB_TRIE_STATS is not set
++# CONFIG_IP_MULTIPLE_TABLES is not set
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++# CONFIG_INET_LRO is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++# CONFIG_CFG80211 is not set
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++# CONFIG_MTD_GPIO_ADDR is not set
++# CONFIG_MTD_PLATRAM is not set
++# CONFIG_MTD_LATCH_ADDR is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_FTNANDC023=y
++# CONFIG_NAND_USE_AHBDMA is not set
++# CONFIG_NAND_USE_AXIDMA is not set
++CONFIG_FTNANDC023_DEBUG=0
++# CONFIG_GPIO_WP is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_EXTERNAL_CRYSTAL_CLOCK is not set
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++CONFIG_FTGMAC100_DRIVER_0_SLAVE=y
++# CONFIG_FTGMAC100_DRIVER_1_MASTER is not set
++# CONFIG_FTGMAC100_DRIVER_1_SLAVE is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++CONFIG_PPP=y
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPP_DEFLATE is not set
++CONFIG_PPP_FILTER=y
++# CONFIG_PPP_MPPE is not set
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOE=y
++CONFIG_PPP_ASYNC=y
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=y
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=6
++CONFIG_SERIAL_8250_RUNTIME_UARTS=6
++# CONFIG_SERIAL_UART1_IP is not set
++CONFIG_SERIAL_UART2_IP=y
++CONFIG_SERIAL_UART3_IP=y
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++# CONFIG_I2C_INTERRUPT_MODE is not set
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++# CONFIG_FTSPI020_USE_AHBDMA is not set
++CONFIG_FTSPI020_USE_AXIDMA=y
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_FTWDT010_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_EYE_DIAGRAM is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8210_FA726_only b/arch/arm/configs/GM8210_FA726_only
+new file mode 100644
+index 00000000..ba6d61c2
+--- /dev/null
++++ b/arch/arm/configs/GM8210_FA726_only
+@@ -0,0 +1,1796 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_PLATFORM_GM8210=y
++CONFIG_FIQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../target/rootfs-cpio"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++# CONFIG_ARCH_GM is not set
++CONFIG_ARCH_GM_DUO=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++CONFIG_FTDMAC030=y
++# CONFIG_FTINTC010EX is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++CONFIG_PLATFORM_GM8210_M=y
++# CONFIG_PLATFORM_GM8210_S is not set
++
++#
++# GM Platform Options
++#
++CONFIG_GM8210_M_HZ=100
++CONFIG_PLATFORM_AXIDMA=y
++# CONFIG_FA626 is not set
++CONFIG_GM8312=y
++# CONFIG_GM8210_FPGA is not set
++# CONFIG_GM8210_EP_MODE is not set
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++# CONFIG_CPU_FA626TE is not set
++CONFIG_CPU_FA726TE=y
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++# CONFIG_NO_HZ is not set
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=112M@0x01000000 gmmem=70M console=ttyS0,115200 mem=384M@0x8000000 user_debug=31"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++CONFIG_IP_ADVANCED_ROUTER=y
++# CONFIG_IP_FIB_TRIE_STATS is not set
++# CONFIG_IP_MULTIPLE_TABLES is not set
++# CONFIG_IP_ROUTE_MULTIPATH is not set
++# CONFIG_IP_ROUTE_VERBOSE is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++# CONFIG_INET_LRO is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++# CONFIG_CFG80211 is not set
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++# CONFIG_MTD_GPIO_ADDR is not set
++# CONFIG_MTD_PLATRAM is not set
++# CONFIG_MTD_LATCH_ADDR is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_FTNANDC023=y
++# CONFIG_NAND_USE_AHBDMA is not set
++# CONFIG_NAND_USE_AXIDMA is not set
++CONFIG_FTNANDC023_DEBUG=0
++# CONFIG_GPIO_WP is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_EXTERNAL_CRYSTAL_CLOCK is not set
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++CONFIG_FTGMAC100_DRIVER_0_SLAVE=y
++# CONFIG_FTGMAC100_DRIVER_1_MASTER is not set
++# CONFIG_FTGMAC100_DRIVER_1_SLAVE is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++CONFIG_PPP=y
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPP_DEFLATE is not set
++CONFIG_PPP_FILTER=y
++# CONFIG_PPP_MPPE is not set
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOE=y
++CONFIG_PPP_ASYNC=y
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=y
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=6
++CONFIG_SERIAL_8250_RUNTIME_UARTS=6
++# CONFIG_SERIAL_UART1_IP is not set
++CONFIG_SERIAL_UART2_IP=y
++CONFIG_SERIAL_UART3_IP=y
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++# CONFIG_I2C_INTERRUPT_MODE is not set
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++# CONFIG_FTSPI020_USE_AHBDMA is not set
++CONFIG_FTSPI020_USE_AXIDMA=y
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_FTWDT010_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_EYE_DIAGRAM is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++# CONFIG_SQUASHFS_XZ is not set
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8210_FPGA_defconfig b/arch/arm/configs/GM8210_FPGA_defconfig
+new file mode 100644
+index 00000000..165baaab
+--- /dev/null
++++ b/arch/arm/configs/GM8210_FPGA_defconfig
+@@ -0,0 +1,1547 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_PLATFORM_GM8210=y
++CONFIG_FIQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../target/rootfs-cpio"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_OPROFILE is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++# CONFIG_ARCH_GM is not set
++CONFIG_ARCH_GM_DUO=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++# CONFIG_FTINTC010EX is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_PLATFORM_GM8210_M=y
++# CONFIG_PLATFORM_GM8210_S is not set
++
++#
++# GM Platform Options
++#
++# CONFIG_PLATFORM_AXIDMA is not set
++CONFIG_FTINTC030=y
++# CONFIG_MFIQ is not set
++# CONFIG_GM8312 is not set
++CONFIG_GM8210_FPGA=y
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=1000
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=112M@0x01000000 gmmem=50M console=ttyS0,38400 mem=128M@0x18000000"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK_ACCT is not set
++# CONFIG_NETFILTER_NETLINK_QUEUE is not set
++# CONFIG_NETFILTER_NETLINK_LOG is not set
++# CONFIG_NF_CONNTRACK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++CONFIG_MTD_CFI_UTIL=y
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_GM is not set
++# CONFIG_MTD_GPIO_ADDR is not set
++# CONFIG_MTD_PLATRAM is not set
++# CONFIG_MTD_LATCH_ADDR is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SPI_FLASH is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++# CONFIG_MTD_NAND is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_PROC_FS is not set
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++# CONFIG_BLK_DEV_SD is not set
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_ISCSI_BOOT_SYSFS is not set
++# CONFIG_LIBFC is not set
++# CONFIG_LIBFCOE is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++CONFIG_PPP=y
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPP_DEFLATE is not set
++CONFIG_PPP_FILTER=y
++# CONFIG_PPP_MPPE is not set
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOE=y
++CONFIG_PPP_ASYNC=y
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=y
++CONFIG_WLAN=y
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++# CONFIG_SPI_FTSPI020 is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=m
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++# CONFIG_USB_SUPPORT is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++CONFIG_EXT2_FS_SECURITY=y
++CONFIG_EXT2_FS_XIP=y
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_FS_XIP=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++# CONFIG_TMPFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8210_M_1G_EP_defconfig b/arch/arm/configs/GM8210_M_1G_EP_defconfig
+new file mode 100644
+index 00000000..6822959d
+--- /dev/null
++++ b/arch/arm/configs/GM8210_M_1G_EP_defconfig
+@@ -0,0 +1,1415 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_PLATFORM_GM8210=y
++CONFIG_FIQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++# CONFIG_KERNEL_GZIP is not set
++CONFIG_KERNEL_LZMA=y
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../target/rootfs-cpio"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_OPROFILE is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++# CONFIG_ARCH_GM is not set
++CONFIG_ARCH_GM_DUO=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++CONFIG_FTDMAC030=y
++# CONFIG_FTINTC010EX is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++CONFIG_PLATFORM_GM8210_M=y
++# CONFIG_PLATFORM_GM8210_S is not set
++
++#
++# GM Platform Options
++#
++CONFIG_GM8210_M_HZ=1000
++CONFIG_PLATFORM_AXIDMA=y
++# CONFIG_FA626 is not set
++# CONFIG_GM8312 is not set
++# CONFIG_GM8210_FPGA is not set
++CONFIG_GM8210_EP_MODE=y
++CONFIG_FC7500=y
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++# CONFIG_CPU_FA626TE is not set
++CONFIG_CPU_FA726TE=y
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++# CONFIG_NO_HZ is not set
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=1000
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=496M@0x01000000 gmmem=196M mem=512M@0x20000000 console=ttyS0,115200 user_debug=31"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK_ACCT is not set
++# CONFIG_NETFILTER_NETLINK_QUEUE is not set
++# CONFIG_NETFILTER_NETLINK_LOG is not set
++# CONFIG_NF_CONNTRACK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_NETDEVICES is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=6
++CONFIG_SERIAL_8250_RUNTIME_UARTS=6
++# CONFIG_SERIAL_UART1_IP is not set
++CONFIG_SERIAL_UART2_IP=y
++CONFIG_SERIAL_UART3_IP=y
++# CONFIG_SERIAL_UART4_IP is not set
++CONFIG_SERIAL_UART5_IP=y
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++# CONFIG_I2C_INTERRUPT_MODE is not set
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_SPI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MCP23S08 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_FTWDT010_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++CONFIG_SOUND_OSS_CORE_PRECLAIM=y
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_HRTIMER is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++# CONFIG_SND_RAWMIDI_SEQ is not set
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARM is not set
++# CONFIG_SND_SOC is not set
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++# CONFIG_HID_PID is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_USB_SUPPORT is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8210_M_1G_defconfig b/arch/arm/configs/GM8210_M_1G_defconfig
+new file mode 100644
+index 00000000..de7c49ba
+--- /dev/null
++++ b/arch/arm/configs/GM8210_M_1G_defconfig
+@@ -0,0 +1,1852 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_PLATFORM_GM8210=y
++CONFIG_FIQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++# CONFIG_KERNEL_GZIP is not set
++CONFIG_KERNEL_LZMA=y
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_OPROFILE is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++# CONFIG_ARCH_GM is not set
++CONFIG_ARCH_GM_DUO=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++CONFIG_FTDMAC030=y
++# CONFIG_FTINTC010EX is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++CONFIG_PLATFORM_GM8210_M=y
++# CONFIG_PLATFORM_GM8210_S is not set
++
++#
++# GM Platform Options
++#
++CONFIG_GM8210_M_HZ=100
++CONFIG_PLATFORM_AXIDMA=y
++CONFIG_FA626=y
++CONFIG_GM8312=y
++# CONFIG_GM8210_FPGA is not set
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++# CONFIG_CPU_FA626TE is not set
++CONFIG_CPU_FA726TE=y
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++# CONFIG_NO_HZ is not set
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=240M@0x01000000 gmmem=30M console=ttyS0,115200 user_debug=31 init=/squashfs_init root=/dev/mtdblock4 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_NETFILTER_ADVANCED=y
++
++#
++# Core Netfilter Configuration
++#
++# CONFIG_NETFILTER_NETLINK_ACCT is not set
++# CONFIG_NETFILTER_NETLINK_QUEUE is not set
++# CONFIG_NETFILTER_NETLINK_LOG is not set
++# CONFIG_NF_CONNTRACK is not set
++# CONFIG_NETFILTER_XTABLES is not set
++# CONFIG_IP_VS is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_NF_DEFRAG_IPV4 is not set
++# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++# CONFIG_MTD_GPIO_ADDR is not set
++# CONFIG_MTD_PLATRAM is not set
++# CONFIG_MTD_LATCH_ADDR is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_FTNANDC023=y
++# CONFIG_NAND_USE_AHBDMA is not set
++# CONFIG_NAND_USE_AXIDMA is not set
++CONFIG_FTNANDC023_DEBUG=0
++# CONFIG_GPIO_WP is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++# CONFIG_FTGMAC100_DRIVER_0_SLAVE is not set
++# CONFIG_FTGMAC100_DRIVER_1_MASTER is not set
++CONFIG_FTGMAC100_DRIVER_1_SLAVE=y
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++CONFIG_NET_VENDOR_MICROCHIP=y
++# CONFIG_ENC28J60 is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++CONFIG_PPP=y
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPP_DEFLATE is not set
++CONFIG_PPP_FILTER=y
++# CONFIG_PPP_MPPE is not set
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOE=y
++CONFIG_PPP_ASYNC=y
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=y
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=6
++CONFIG_SERIAL_8250_RUNTIME_UARTS=6
++# CONFIG_SERIAL_UART1_IP is not set
++CONFIG_SERIAL_UART2_IP=y
++CONFIG_SERIAL_UART3_IP=y
++# CONFIG_SERIAL_UART4_IP is not set
++CONFIG_SERIAL_UART5_IP=y
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++# CONFIG_I2C_INTERRUPT_MODE is not set
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++# CONFIG_FTSPI020_USE_AHBDMA is not set
++CONFIG_FTSPI020_USE_AXIDMA=y
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++CONFIG_FTWDT010_WATCHDOG=y
++# CONFIG_MAX63XX_WATCHDOG is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++CONFIG_SOUND_OSS_CORE_PRECLAIM=y
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++# CONFIG_SND_HRTIMER is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++# CONFIG_SND_RAWMIDI_SEQ is not set
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARM is not set
++# CONFIG_SND_SPI is not set
++CONFIG_SND_USB=y
++# CONFIG_SND_USB_AUDIO is not set
++# CONFIG_SND_USB_UA101 is not set
++# CONFIG_SND_USB_CAIAQ is not set
++# CONFIG_SND_USB_6FIRE is not set
++# CONFIG_SND_SOC is not set
++# CONFIG_SOUND_PRIME is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_PRODIKEYS is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_EYE_DIAGRAM is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++# CONFIG_EXT3_FS is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_USE_FOR_EXT23=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8210_S_1G_defconfig b/arch/arm/configs/GM8210_S_1G_defconfig
+new file mode 100644
+index 00000000..2d3a995a
+--- /dev/null
++++ b/arch/arm/configs/GM8210_S_1G_defconfig
+@@ -0,0 +1,1407 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_PLATFORM_GM8210=y
++CONFIG_FIQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++# CONFIG_KERNEL_GZIP is not set
++CONFIG_KERNEL_LZMA=y
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../target/rootfs-cpio"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++CONFIG_RD_LZMA=y
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_OPROFILE is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++CONFIG_INLINE_SPIN_UNLOCK=y
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++CONFIG_INLINE_READ_UNLOCK=y
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++CONFIG_INLINE_READ_UNLOCK_IRQ=y
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++CONFIG_INLINE_WRITE_UNLOCK=y
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++# CONFIG_ARCH_GM is not set
++CONFIG_ARCH_GM_DUO=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++# CONFIG_FTINTC010EX is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++# CONFIG_PLATFORM_GM8210_M is not set
++CONFIG_PLATFORM_GM8210_S=y
++
++#
++# GM Platform Options
++#
++# CONFIG_PLATFORM_AXIDMA is not set
++CONFIG_GM8312=y
++# CONFIG_GM8210_FPGA is not set
++CONFIG_GM8210_S_HZ=1000
++CONFIG_FC7500=y
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
++# CONFIG_PREEMPT is not set
++CONFIG_HZ=1000
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=256M@0x10000000 gmmem=190M console=ttyS0,115200 mem=512M@0x20000000"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++# CONFIG_INET_LRO is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_PROC_FS is not set
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++# CONFIG_BLK_DEV_SD is not set
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_ISCSI_BOOT_SYSFS is not set
++# CONFIG_LIBFC is not set
++# CONFIG_LIBFCOE is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++# CONFIG_FTGMAC100_DRIVER_0_SLAVE is not set
++# CONFIG_FTGMAC100_DRIVER_1_MASTER is not set
++CONFIG_FTGMAC100_DRIVER_1_SLAVE=y
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++CONFIG_MARVELL_PHY=y
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_WLAN=y
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_BMA150 is not set
++# CONFIG_INPUT_MMA8450 is not set
++# CONFIG_INPUT_MPU3050 is not set
++# CONFIG_INPUT_GP2A is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_KXTJ9 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_PCF8574 is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++# CONFIG_SERIAL_UART1_IP is not set
++# CONFIG_SERIAL_UART2_IP is not set
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++# CONFIG_I2C_INTERRUPT_MODE is not set
++CONFIG_I2C0_IP=y
++# CONFIG_I2C1_IP is not set
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_SPI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MCP23S08 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++# CONFIG_FB_MODE_HELPERS is not set
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++# CONFIG_USB_SUPPORT is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++CONFIG_EXT2_FS_SECURITY=y
++CONFIG_EXT2_FS_XIP=y
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_FS_XIP=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++# CONFIG_VFAT_FS is not set
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++# CONFIG_TMPFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++# CONFIG_SQUASHFS_XZ is not set
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM8220_defconfig b/arch/arm/configs/GM8220_defconfig
+new file mode 100644
+index 00000000..88e1d6dd
+--- /dev/null
++++ b/arch/arm/configs/GM8220_defconfig
+@@ -0,0 +1,1365 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_HAVE_SCHED_CLOCK=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_LOCKBREAK=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="arm-none-linux-gnueabi-"
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_IRQ_DOMAIN=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++CONFIG_RCU_FANOUT=32
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++# CONFIG_NAMESPACES is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++# CONFIG_RELAY is not set
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="../target_ca7/rootfs"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_USE_GENERIC_SMP_HELPERS=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_HW_BREAKPOINT=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_STOP_MACHINE=y
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++CONFIG_MUTEX_SPIN_ON_OWNER=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++# CONFIG_ARCH_GM is not set
++# CONFIG_ARCH_GM_DUO is not set
++CONFIG_ARCH_GM_SMP=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++# CONFIG_FTDMAC030 is not set
++CONFIG_FTTMR010=y
++CONFIG_FORCE_MAX_ZONEORDER=12
++CONFIG_CLOCK_TICK_RATE=25000000
++# CONFIG_FTINTC030 is not set
++CONFIG_FPGA=y
++CONFIG_PLATFORM_AXIDMA=y
++CONFIG_PLATFORM_GM8220=y
++CONFIG_CPU_HAS_GIC=y
++
++#
++# GM Platform Options
++#
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++# CONFIG_CPU_CA9 is not set
++CONFIG_CPU_CA7=y
++CONFIG_CPU_V7=y
++CONFIG_CPU_32v6K=y
++CONFIG_CPU_32v7=y
++CONFIG_CPU_ABRT_EV7=y
++CONFIG_CPU_PABRT_V7=y
++CONFIG_CPU_CACHE_V7=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_COPY_V6=y
++CONFIG_CPU_TLB_V7=y
++CONFIG_CPU_HAS_ASID=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_ARM_LPAE is not set
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++CONFIG_ARM_THUMB=y
++# CONFIG_ARM_THUMBEE is not set
++CONFIG_SWP_EMULATE=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_MIGHT_HAVE_CACHE_L2X0=y
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT_6=y
++CONFIG_ARM_L1_CACHE_SHIFT=6
++CONFIG_ARM_DMA_MEM_BUFFERABLE=y
++CONFIG_ARM_NR_BANKS=8
++CONFIG_CPU_HAS_PMU=y
++CONFIG_MULTI_IRQ_HANDLER=y
++# CONFIG_ARM_ERRATA_430973 is not set
++# CONFIG_ARM_ERRATA_458693 is not set
++# CONFIG_ARM_ERRATA_460075 is not set
++# CONFIG_ARM_ERRATA_742230 is not set
++# CONFIG_ARM_ERRATA_742231 is not set
++# CONFIG_ARM_ERRATA_720789 is not set
++# CONFIG_ARM_ERRATA_743622 is not set
++# CONFIG_ARM_ERRATA_751472 is not set
++# CONFIG_ARM_ERRATA_754322 is not set
++# CONFIG_ARM_ERRATA_754327 is not set
++CONFIG_ARM_ERRATA_764369=y
++CONFIG_ARM_GIC=y
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++# CONFIG_NO_HZ is not set
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_HAVE_SMP=y
++CONFIG_SMP=y
++CONFIG_SMP_ON_UP=y
++CONFIG_ARM_CPU_TOPOLOGY=y
++# CONFIG_SCHED_MC is not set
++# CONFIG_SCHED_SMT is not set
++CONFIG_HAVE_ARM_SCU=y
++CONFIG_ARM_ARCH_TIMER=y
++CONFIG_HAVE_ARM_TWD=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_NR_CPUS=4
++CONFIG_HOTPLUG_CPU=y
++CONFIG_LOCAL_TIMERS=y
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++# CONFIG_THUMB2_KERNEL is not set
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_HW_PERF_EVENTS=y
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++CONFIG_CC_STACKPROTECTOR=y
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="mem=256M console=ttyS0,38400 user_debug=31 earlyprintk"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_PM_SLEEP=y
++CONFIG_PM_SLEEP_SMP=y
++# CONFIG_PM_RUNTIME is not set
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++# CONFIG_APM_EMULATION is not set
++CONFIG_PM_CLK=y
++CONFIG_CPU_PM=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_ARM_CPU_SUSPEND=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_RPS=y
++CONFIG_RFS_ACCEL=y
++CONFIG_XPS=y
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++# CONFIG_PROC_EVENTS is not set
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_FTSPINAND020 is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ATMEL_PWM is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++
++#
++# Altera FPGA firmware download module
++#
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++# CONFIG_SCSI is not set
++# CONFIG_SCSI_DMA is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++# CONFIG_FTGMAC100 is not set
++CONFIG_FTGMAC030=y
++CONFIG_FTGMAC030_DRIVER_0=y
++# CONFIG_FTGMAC030_DRIVER_1 is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++CONFIG_WLAN=y
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_GPIO_TILT_POLLED is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
++# CONFIG_INPUT_ADXL34X is not set
++# CONFIG_INPUT_CMA3000 is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=1
++CONFIG_SERIAL_8250_RUNTIME_UARTS=1
++# CONFIG_SERIAL_UART1_IP is not set
++# CONFIG_SERIAL_UART2_IP is not set
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_UART6_IP is not set
++# CONFIG_SERIAL_UART7_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++# CONFIG_I2C is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++# CONFIG_SPI_FTSPI020 is not set
++# CONFIG_SPI_FTSSP010 is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++# CONFIG_GPIO_SYSFS is not set
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_FTGPIO010 is not set
++
++#
++# I2C GPIO expanders:
++#
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_CORE is not set
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_FTWDT010_WATCHDOG is not set
++# CONFIG_DW_WATCHDOG is not set
++# CONFIG_MPCORE_WATCHDOG is not set
++# CONFIG_MAX63XX_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_MFD_TC6393XB is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++# CONFIG_HID_SUPPORT is not set
++# CONFIG_USB_SUPPORT is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++CONFIG_CLKDEV_LOOKUP=y
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_CLKSRC_MMIO=y
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++# CONFIG_EXT2_FS is not set
++# CONFIG_EXT4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++# CONFIG_SQUASHFS_ZLIB is not set
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++CONFIG_RCU_CPU_STALL_TIMEOUT=60
++CONFIG_RCU_CPU_STALL_VERBOSE=y
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_DEBUG_PER_CPU_MAPS is not set
++# CONFIG_LKDTM is not set
++# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
++# CONFIG_FAULT_INJECTION 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++# CONFIG_CRYPTO is not set
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_CPU_RMAP=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/GM828x_defconfig b/arch/arm/configs/GM828x_defconfig
+new file mode 100644
+index 00000000..23e0586c
+--- /dev/null
++++ b/arch/arm/configs/GM828x_defconfig
+@@ -0,0 +1,1757 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/arm 3.3.0 Kernel Configuration
++#
++CONFIG_ARM=y
++CONFIG_MIGHT_HAVE_PCI=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_ARCH_HAS_CPUFREQ=y
++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_VECTORS_BASE=0xffff0000
++# CONFIG_ARM_PATCH_PHYS_VIRT is not set
++CONFIG_NEED_MACH_MEMORY_H=y
++CONFIG_GENERIC_BUG=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="grain-media"
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++# CONFIG_POSIX_MQUEUE is not set
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_FHANDLE is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_HAVE_SPARSE_IRQ=y
++CONFIG_GENERIC_IRQ_SHOW=y
++# CONFIG_SPARSE_IRQ is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_PREEMPT_RCU=y
++CONFIG_PREEMPT_RCU=y
++# CONFIG_RCU_TRACE is not set
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_RCU_BOOST is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++# CONFIG_SCHED_AUTOGROUP is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++CONFIG_EFI_PARTITION=y
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_HIGHBANK is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_PRIMA2 is not set
++# CONFIG_ARCH_FARADAY is not set
++CONFIG_ARCH_GM=y
++# CONFIG_ARCH_GM_DUO is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_MXS is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PICOXCELL is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P64X0 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_EXYNOS is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_ARCH_VT8500 is not set
++# CONFIG_ARCH_ZYNQ is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_PLATFORM_GM8126 is not set
++CONFIG_PLATFORM_GM8287=y
++# CONFIG_PLATFORM_GM8139 is not set
++# CONFIG_PLATFORM_GM8136 is not set
++CONFIG_FORCE_MAX_ZONEORDER=12
++
++#
++# GM Platform Options
++#
++CONFIG_CLOCK_TICK_RATE=33000000
++CONFIG_FTINTC030=y
++
++#
++# System MMU
++#
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++CONFIG_CPU_USE_DOMAINS=y
++
++#
++# Processor Features
++#
++# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++# CONFIG_CACHE_L2X0 is not set
++# CONFIG_CACHE_FTL2CC031 is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_ARM_NR_BANKS=8
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++# CONFIG_VMSPLIT_3G is not set
++CONFIG_VMSPLIT_2G=y
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0x80000000
++CONFIG_ARCH_NR_GPIO=0
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++CONFIG_HAVE_ARCH_PFN_VALID=y
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_SECCOMP is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++# CONFIG_USE_OF is not set
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,115200 mem=256M gmmem=190M user_debug=31 init=/squashfs_init root=/dev/mtdblock2 rootfstype=squashfs"
++CONFIG_CMDLINE_FROM_BOOTLOADER=y
++# CONFIG_CMDLINE_EXTEND is not set
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM_RUNTIME is not set
++# CONFIG_ARM_CPU_SUSPEND is not set
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_WEXT_PRIV=y
++# CONFIG_CFG80211 is not set
++# CONFIG_WIRELESS_EXT_SYSFS is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++# CONFIG_DMA_SHARED_BUFFER is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++# CONFIG_MTD_SWAP is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++CONFIG_MTD_SPI_FLASH=y
++CONFIG_MTD_ERASE_64K=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++CONFIG_MTD_BLOCK2MTD=y
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++# CONFIG_MTD_DOCG3 is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_NAND_ECC_BCH is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++CONFIG_MTD_NAND_FTNANDC023=y
++# CONFIG_NAND_USE_AHBDMA is not set
++# CONFIG_NAND_USE_AXIDMA is not set
++# CONFIG_MTD_NAND_FTNANDC024V2 is not set
++# CONFIG_MTD_NAND_FTSPINAND020 is not set
++CONFIG_FTNANDC023_DEBUG=0
++# CONFIG_GPIO_WP is not set
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_BMP085 is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_AT24 is not set
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++CONFIG_ATA=y
++# CONFIG_ATA_NONSTANDARD is not set
++CONFIG_ATA_VERBOSE_ERROR=y
++CONFIG_SATA_PMP=y
++
++#
++# Controllers with non-SFF native interface
++#
++CONFIG_SATA_AHCI_PLATFORM=y
++# CONFIG_ATA_SFF is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_MII is not set
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++
++#
++# CAIF transport drivers
++#
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_DM9000 is not set
++# CONFIG_DNET is not set
++CONFIG_NET_VENDOR_FARADAY=y
++CONFIG_FTGMAC100=y
++CONFIG_FTGMAC100_DRIVER_0_MASTER=y
++# CONFIG_FTMAC_TINY is not set
++# CONFIG_FTMAC110 is not set
++# CONFIG_NET_VENDOR_INTEL is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++# CONFIG_NET_VENDOR_STMICRO is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++CONFIG_ICPLUS_PHY=y
++CONFIG_REALTEK_PHY=y
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_SERIO_PS2MULT is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=4
++CONFIG_SERIAL_8250_RUNTIME_UARTS=4
++CONFIG_SERIAL_UART1_IP=y
++CONFIG_SERIAL_UART2_IP=y
++# CONFIG_SERIAL_UART3_IP is not set
++# CONFIG_SERIAL_UART4_IP is not set
++# CONFIG_SERIAL_UART5_IP is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX3107 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++# CONFIG_SERIAL_XILINX_PS_UART is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_HVC_DCC is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_GM_FTI2C010=y
++CONFIG_I2C_INTERRUPT_MODE=y
++CONFIG_I2C0_IP=y
++CONFIG_I2C1_IP=y
++# CONFIG_I2C2_IP is not set
++# CONFIG_I2C3_IP is not set
++# CONFIG_I2C4_IP is not set
++# CONFIG_I2C5_IP is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++# CONFIG_SPI_BITBANG is not set
++# CONFIG_SPI_GPIO is not set
++# CONFIG_SPI_OC_TINY is not set
++# CONFIG_SPI_PXA2XX_PCI is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++CONFIG_SPI_FTSPI020=y
++# CONFIG_FTSPI020_USE_AHBDMA is not set
++# CONFIG_FTSPI020_USE_AXIDMA is not set
++
++#
++# SPI Protocol Masters
++#
++# CONFIG_SPI_SPIDEV is not set
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++
++#
++# Enable Device Drivers -> PPS to see the PTP clock options.
++#
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++CONFIG_GPIO_FTGPIO010=y
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_S5M_CORE is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_WMT_GE_ROPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++CONFIG_FB_TILEBLITTING=y
++
++#
++# Frame buffer hardware drivers
++#
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_SMSCUFX is not set
++# CONFIG_FB_UDL is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_BROADSHEET is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++# CONFIG_LOGO is not set
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++# CONFIG_USB_ARCH_HAS_XHCI is not set
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DEVICEFS is not set
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_GM_FOTG2XX=y
++# CONFIG_GM_FOTG2XX_PHY_TEST is not set
++# CONFIG_GM_FOTG2XX_INFO is not set
++# CONFIG_GM_FOTG2XX_LOW_TIMING is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++# CONFIG_USB_EHCI_MV is not set
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++# CONFIG_USB_UAS is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++# CONFIG_TIMB_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_BALLOON is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_STAGING is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_IOMMU_SUPPORT=y
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT4_FS=y
++CONFIG_EXT4_FS_XATTR=y
++# CONFIG_EXT4_FS_POSIX_ACL is not set
++# CONFIG_EXT4_FS_SECURITY is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD2=y
++# CONFIG_JBD2_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++CONFIG_JOLIET=y
++# CONFIG_ZISOFS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_TMPFS_XATTR is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++# CONFIG_JFFS2_SUMMARY is not set
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++# CONFIG_LOGFS is not set
++CONFIG_CRAMFS=y
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_XATTR is not set
++CONFIG_SQUASHFS_ZLIB=y
++# CONFIG_SQUASHFS_LZO is not set
++CONFIG_SQUASHFS_XZ=y
++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set
++CONFIG_SQUASHFS_EMBEDDED=y
++CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_PSTORE is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_SECTION_MISMATCH=y
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++CONFIG_DETECT_HUNG_TASK=y
++CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
++# 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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++CONFIG_DEBUG_PREEMPT=y
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# 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_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=y
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=y
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=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
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=y
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=y
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++CONFIG_CRYPTO_MD4=y
++CONFIG_CRYPTO_MD5=y
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_CRC_CCITT=y
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_XZ_DEC=y
++CONFIG_XZ_DEC_X86=y
++CONFIG_XZ_DEC_POWERPC=y
++CONFIG_XZ_DEC_IA64=y
++CONFIG_XZ_DEC_ARM=y
++CONFIG_XZ_DEC_ARMTHUMB=y
++CONFIG_XZ_DEC_SPARC=y
++CONFIG_XZ_DEC_BCJ=y
++# CONFIG_XZ_DEC_TEST is not set
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
++# CONFIG_AVERAGE is not set
++# CONFIG_CORDIC is not set
+diff --git a/arch/arm/configs/a320_defconfig b/arch/arm/configs/a320_defconfig
+new file mode 100644
+index 00000000..a8474411
+--- /dev/null
++++ b/arch/arm/configs/a320_defconfig
+@@ -0,0 +1,1082 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.35
++# Thu Mar  8 16:07:35 2012
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_TIME=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_CONSTRUCTORS=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="arm-none-linux-gnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_BZIP2 is not set
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_TREE_PREEMPT_RCU is not set
++# CONFIG_TINY_RCU is not set
++# CONFIG_RCU_TRACE is not set
++CONFIG_RCU_FANOUT=32
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="~/linux-ramdisk/rootfs"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
++# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
++# CONFIG_INITRAMFS_COMPRESSION_LZO is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_OPROFILE is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_CLK=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_SLOW_WORK is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++CONFIG_INLINE_SPIN_UNLOCK=y
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++CONFIG_INLINE_READ_UNLOCK=y
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++CONFIG_INLINE_READ_UNLOCK_IRQ=y
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++CONFIG_INLINE_WRITE_UNLOCK=y
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++CONFIG_ARCH_FARADAY=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_STMP3XXX is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_NUC93X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P6440 is not set
++# CONFIG_ARCH_S5P6442 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++CONFIG_PLATFORM_A320=y
++# CONFIG_PLATFORM_A369 is not set
++# CONFIG_PLATFORM_AXI is not set
++# CONFIG_FARADAY_HIGH_PHYS_OFFSET is not set
++# CONFIG_PLATFORM_FIA321 is not set
++# CONFIG_FTAPBB020 is not set
++# CONFIG_FTDMAC020 is not set
++# CONFIG_FTDMAC030 is not set
++CONFIG_FTINTC010=y
++CONFIG_FTPMU010=y
++CONFIG_FTTMR010=y
++
++#
++# Processor Type
++#
++# CONFIG_CPU_FA626TE is not set
++# CONFIG_CPU_FMP626 is not set
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++CONFIG_CPU_FA526=y
++CONFIG_CPU_32v4=y
++CONFIG_CPU_ABRT_EV4=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIVT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_CPU_FA526_IDLE_FIXUP=y
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_COMMON_CLKDEV=y
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=999999
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,38400 mem=64M"
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++# CONFIG_INET_LRO is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++
++#
++# Some wireless drivers require a rate control algorithm
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_93CX6 is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_PROC_FS is not set
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++# CONFIG_BLK_DEV_SD is not set
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_LIBFC is not set
++# CONFIG_LIBFCOE is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=y
++CONFIG_VETH=y
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++CONFIG_DAVICOM_PHY=y
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_ETHOC is not set
++# CONFIG_SMC911X is not set
++# CONFIG_SMSC911X is not set
++# CONFIG_DNET is not set
++# CONFIG_IBM_NEW_EMAC_ZMII is not set
++# CONFIG_IBM_NEW_EMAC_RGMII is not set
++# CONFIG_IBM_NEW_EMAC_TAH is not set
++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
++# CONFIG_B44 is not set
++# CONFIG_KS8842 is not set
++# CONFIG_KS8851_MLL is not set
++CONFIG_NETDEV_1000=y
++CONFIG_NETDEV_10000=y
++CONFIG_WLAN=y
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_ATI_REMOTE is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_DEVKMEM=y
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++# CONFIG_I2C is not set
++# CONFIG_SPI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_MFD_SUPPORT=y
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=m
++# CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++# CONFIG_HID_PID is not set
++
++#
++# Special HID drivers
++#
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++# CONFIG_USB is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++
++#
++# Enable Host or Gadget support to see Inventra options
++#
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# 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
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++CONFIG_EXT2_FS_SECURITY=y
++CONFIG_EXT2_FS_XIP=y
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_FS_XIP=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++# CONFIG_MSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++# CONFIG_TMPFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_RPCSEC_GSS_KRB5 is not set
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_NLS is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++CONFIG_SYSCTL_SYSCALL_CHECK=y
++# CONFIG_PAGE_POISONING is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++# CONFIG_BOOT_TRACER is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_KMEMTRACE is not set
++# CONFIG_WORKQUEUE_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_ERRORS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_LL is not set
++# CONFIG_OC_ETM is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_DEFAULT_SECURITY_SELINUX is not set
++# CONFIG_DEFAULT_SECURITY_SMACK is not set
++# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_MANAGER2 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_FIND_LAST_BIT=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
+diff --git a/arch/arm/configs/a369_defconfig b/arch/arm/configs/a369_defconfig
+new file mode 100644
+index 00000000..cfd5521d
+--- /dev/null
++++ b/arch/arm/configs/a369_defconfig
+@@ -0,0 +1,1134 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.36
++# Wed Mar 28 15:15:36 2012
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_CONSTRUCTORS=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE="arm-none-linux-gnueabi-"
++CONFIG_LOCALVERSION=""
++CONFIG_LOCALVERSION_AUTO=y
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_BSD_PROCESS_ACCT_V3=y
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TREE_RCU=y
++# CONFIG_TINY_RCU is not set
++# CONFIG_RCU_TRACE is not set
++CONFIG_RCU_FANOUT=32
++# CONFIG_RCU_FANOUT_EXACT is not set
++# CONFIG_TREE_RCU_TRACE is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_CGROUPS is not set
++CONFIG_SYSFS_DEPRECATED=y
++CONFIG_SYSFS_DEPRECATED_V2=y
++# CONFIG_RELAY is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++CONFIG_USER_NS=y
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="~/linux-ramdisk/rootfs"
++CONFIG_INITRAMFS_ROOT_UID=0
++CONFIG_INITRAMFS_ROOT_GID=0
++CONFIG_RD_GZIP=y
++# CONFIG_RD_BZIP2 is not set
++# CONFIG_RD_LZMA is not set
++# CONFIG_RD_LZO is not set
++CONFIG_INITRAMFS_COMPRESSION_NONE=y
++# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_COMPAT_BRK=y
++CONFIG_SLAB=y
++# CONFIG_SLUB is not set
++# CONFIG_SLOB is not set
++CONFIG_PROFILING=y
++# CONFIG_OPROFILE is not set
++CONFIG_HAVE_OPROFILE=y
++# CONFIG_KPROBES is not set
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_CLK=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_BLOCK=y
++CONFIG_LBDAF=y
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++CONFIG_INLINE_SPIN_UNLOCK=y
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++CONFIG_INLINE_READ_UNLOCK=y
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++CONFIG_INLINE_READ_UNLOCK_IRQ=y
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++CONFIG_INLINE_WRITE_UNLOCK=y
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++CONFIG_ARCH_FARADAY=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_MXC is not set
++# CONFIG_ARCH_STMP3XXX is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_LPC32XX is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_NUC93X is not set
++# CONFIG_ARCH_TEGRA is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P6440 is not set
++# CONFIG_ARCH_S5P6442 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_S5PV310 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++# CONFIG_PLATFORM_A320 is not set
++CONFIG_PLATFORM_A369=y
++# CONFIG_PLATFORM_AXI is not set
++# CONFIG_FARADAY_HIGH_PHYS_OFFSET is not set
++CONFIG_FTAHBB020=y
++# CONFIG_FTAPBB020 is not set
++CONFIG_FTDMAC020=y
++# CONFIG_FTDMAC030 is not set
++CONFIG_FTINTC010=y
++CONFIG_FTINTC010EX=y
++CONFIG_FTPWMTMR010=y
++CONFIG_FTSCU010=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_FA626TE=y
++# CONFIG_CPU_FMP626 is not set
++# CONFIG_CPU_FA726TE is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_FA526 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5T=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIPT=y
++CONFIG_CPU_CACHE_FA=y
++CONFIG_CPU_COPY_FA=y
++CONFIG_CPU_TLB_FA=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++CONFIG_ARM_THUMB=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_BPREDICT_DISABLE is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_COMMON_CLKDEV=y
++
++#
++# Bus support
++#
++# CONFIG_PCI is not set
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_PREEMPT_COUNT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++# CONFIG_HIGHMEM is not set
++# CONFIG_SPARSE_IRQ is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_FORCE_MAX_ZONEORDER=11
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++# CONFIG_CC_STACKPROTECTOR is not set
++# CONFIG_DEPRECATED_PARAM_STRUCT is not set
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttyS0,38400 mem=512M"
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++# CONFIG_AUTO_ZRELADDR is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_FPE_NWFPE is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++# CONFIG_INET_LRO is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++# CONFIG_CFG80211 is not set
++# CONFIG_LIB80211 is not set
++
++#
++# CFG80211 needs to be enabled for MAC80211
++#
++
++#
++# Some wireless drivers require a rate control algorithm
++#
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH=""
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++# CONFIG_DEBUG_DEVRES is not set
++# CONFIG_SYS_HYPERVISOR is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++# CONFIG_MTD is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++CONFIG_BLK_DEV_RAM_SIZE=16384
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++# CONFIG_EEPROM_93CX6 is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++# CONFIG_SCSI_PROC_FS is not set
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++# CONFIG_BLK_DEV_SD is not set
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP is not set
++# CONFIG_ISCSI_BOOT_SYSFS is not set
++# CONFIG_LIBFC is not set
++# CONFIG_LIBFCOE is not set
++# CONFIG_SCSI_DEBUG is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++CONFIG_MACVLAN=y
++# CONFIG_MACVTAP is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=y
++CONFIG_VETH=y
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++CONFIG_MARVELL_PHY=y
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_ETHOC is not set
++# CONFIG_SMC911X is not set
++# CONFIG_SMSC911X is not set
++# CONFIG_DNET is not set
++# CONFIG_IBM_NEW_EMAC_ZMII is not set
++# CONFIG_IBM_NEW_EMAC_RGMII is not set
++# CONFIG_IBM_NEW_EMAC_TAH is not set
++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
++# CONFIG_B44 is not set
++# CONFIG_KS8842 is not set
++# CONFIG_KS8851_MLL is not set
++CONFIG_NETDEV_1000=y
++CONFIG_NETDEV_10000=y
++CONFIG_WLAN=y
++# CONFIG_HOSTAP is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++
++#
++# CAIF transport drivers
++#
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++CONFIG_INPUT_MISC=y
++# CONFIG_INPUT_AD714X is not set
++# CONFIG_INPUT_ATI_REMOTE is not set
++# CONFIG_INPUT_ATI_REMOTE2 is not set
++# CONFIG_INPUT_KEYSPAN_REMOTE is not set
++# CONFIG_INPUT_POWERMATE is not set
++# CONFIG_INPUT_YEALINK is not set
++# CONFIG_INPUT_CM109 is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_ADXL34X is not set
++
++#
++# Hardware I/O ports
++#
++CONFIG_SERIO=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_LIBPS2 is not set
++# CONFIG_SERIO_RAW is not set
++# CONFIG_SERIO_ALTERA_PS2 is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_DEVKMEM=y
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++
++#
++# Serial drivers
++#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_NR_UARTS=3
++CONFIG_SERIAL_8250_RUNTIME_UARTS=3
++# CONFIG_SERIAL_8250_EXTENDED is not set
++CONFIG_SERIAL_8250_FTUART010=y
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=m
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++# CONFIG_I2C is not set
++# CONFIG_SPI is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++# CONFIG_W1 is not set
++# CONFIG_POWER_SUPPLY is not set
++# CONFIG_HWMON is not set
++# CONFIG_THERMAL is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_MFD_SUPPORT=y
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_T7L66XB is not set
++# CONFIG_MFD_TC6387XB is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_MEDIA_SUPPORT is not set
++
++#
++# Graphics support
++#
++# CONFIG_DRM is not set
++# CONFIG_VGASTATE is not set
++CONFIG_VIDEO_OUTPUT_CONTROL=m
++# CONFIG_FB is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++# CONFIG_SOUND is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++# CONFIG_HID_PID is not set
++
++#
++# Special HID drivers
++#
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
++# CONFIG_USB is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++
++#
++# Enable Host or Gadget support to see Inventra options
++#
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_MMC is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_NEW_LEDS is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++# CONFIG_RTC_CLASS is not set
++# CONFIG_DMADEVICES is not set
++CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH=y
++CONFIG_DMA_ENGINE=y
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_STAGING is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++CONFIG_EXT2_FS_XATTR=y
++CONFIG_EXT2_FS_POSIX_ACL=y
++CONFIG_EXT2_FS_SECURITY=y
++CONFIG_EXT2_FS_XIP=y
++# CONFIG_EXT3_FS is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_FS_XIP=y
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++CONFIG_FS_POSIX_ACL=y
++# CONFIG_XFS_FS is not set
++# CONFIG_GFS2_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++# CONFIG_MSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++# CONFIG_TMPFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++# CONFIG_CONFIGFS_FS is not set
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_RPCSEC_GSS_KRB5 is not set
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CEPH_FS is not set
++CONFIG_CIFS=y
++# CONFIG_CIFS_STATS is not set
++CONFIG_CIFS_WEAK_PW_HASH=y
++# CONFIG_CIFS_XATTR is not set
++# CONFIG_CIFS_DEBUG2 is not set
++# CONFIG_CIFS_EXPERIMENTAL is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ASCII is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_HARDLOCKUP_DETECTOR is not set
++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
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO_REDUCED is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_DEBUG_LIST=y
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_CPU_STALL_DETECTOR is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++CONFIG_SYSCTL_SYSCALL_CHECK=y
++# CONFIG_PAGE_POISONING is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
++CONFIG_TRACING_SUPPORT=y
++CONFIG_FTRACE=y
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_ENABLE_DEFAULT_TRACERS is not set
++CONFIG_BRANCH_PROFILE_NONE=y
++# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
++# CONFIG_PROFILE_ALL_BRANCHES is not set
++# CONFIG_STACK_TRACER is not set
++# CONFIG_BLK_DEV_IO_TRACE is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++CONFIG_ARM_UNWIND=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_ERRORS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_LL is not set
++# CONFIG_OC_ETM is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_MANAGER2 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_FIND_LAST_BIT=y
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
+diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
+new file mode 100644
+index 00000000..935897f1
+--- /dev/null
++++ b/arch/arm/include/asm/arch_timer.h
+@@ -0,0 +1,31 @@
++#ifndef __ASMARM_ARCH_TIMER_H
++#define __ASMARM_ARCH_TIMER_H
++
++#include <linux/ioport.h>
++
++struct arch_timer {
++	struct resource	res[2];
++};
++
++#ifdef CONFIG_ARM_ARCH_TIMER
++int arch_timer_register(struct arch_timer *);
++int arch_timer_sched_clock_init(void);
++int arch_timer_of_register(void);
++#else
++static inline int arch_timer_register(struct arch_timer *at)
++{
++	return -ENXIO;
++}
++
++static inline int arch_timer_of_register(void)
++{
++	return -ENXIO;
++}
++
++static inline int arch_timer_sched_clock_init(void)
++{
++	return -ENXIO;
++}
++#endif
++
++#endif
+diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
+index 23371b17..1947e2b4 100644
+--- a/arch/arm/include/asm/assembler.h
++++ b/arch/arm/include/asm/assembler.h
+@@ -213,7 +213,7 @@
+ 	.else
+ 	ALT_SMP(W(dmb))
+ 	.endif
+-#elif __LINUX_ARM_ARCH__ == 6
++#elif __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_CPU_FMP626)
+ 	ALT_SMP(mcr	p15, 0, r0, c7, c10, 5)	@ dmb
+ #else
+ #error Incompatible SMP platform
+diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
+index 86976d03..625e98a9 100644
+--- a/arch/arm/include/asm/atomic.h
++++ b/arch/arm/include/asm/atomic.h
+@@ -147,6 +147,146 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+ 	: "cc");
+ }
+ 
++#elif defined(CONFIG_CPU_FMP626)
++
++/*
++ * Faraday FMP626 UP and SMP safe atomic ops.  We use load exclusive and
++ * store exclusive to ensure that these are atomic.  We may loop
++ * to ensure that the update happens.  Writing to 'v->counter'
++ * without using the following operations WILL break the atomic
++ * nature of these ops.
++ */
++static inline void atomic_add(int i, atomic_t *v)
++{
++	unsigned long tmp;
++	int result;
++
++	__asm__ __volatile__("@ atomic_add\n"
++"1:	ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	add	%0, %0, %4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++"	stc	p13, c0, [%3], {2}	@ strex to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "Ir" (i)
++	: "cc");
++}
++
++static inline int atomic_add_return(int i, atomic_t *v)
++{
++	unsigned long tmp;
++	int result;
++
++	smp_mb();
++
++	__asm__ __volatile__("@ atomic_add_return\n"
++"1:	ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	add	%0, %0, %4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++"	stc	p13, c0, [%3], {2}	@ strex to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "Ir" (i)
++	: "cc");
++
++	smp_mb();
++
++	return result;
++}
++
++static inline void atomic_sub(int i, atomic_t *v)
++{
++	unsigned long tmp;
++	int result;
++
++	__asm__ __volatile__("@ atomic_sub\n"
++"1:	ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	sub	%0, %0, %4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++"	stc	p13, c0, [%3], {2}	@ strex to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "Ir" (i)
++	: "cc");
++}
++
++static inline int atomic_sub_return(int i, atomic_t *v)
++{
++	unsigned long tmp;
++	int result;
++
++	smp_mb();
++
++	__asm__ __volatile__("@ atomic_sub_return\n"
++"1:	ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	sub	%0, %0, %4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++"	stc	p13, c0, [%3], {2}	@ strex to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "Ir" (i)
++	: "cc");
++
++	smp_mb();
++
++	return result;
++}
++
++static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
++{
++	unsigned long oldval, res;
++
++	smp_mb();
++
++	do {
++		__asm__ __volatile__("@ atomic_cmpxchg\n"
++		"ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++		"mrc	p13, 0, %1, c0, c0, 0	@ ldrex\n"
++		"mov	%0, #0\n"
++		"teq	%1, %4\n"
++		"mcreq	p13, 0, %5, c0, c0, 0	@ data for strex\n"
++		"stceq	p13, c0, [%3], {2}	@ strex to address\n"
++		"mrceq	p13, 0, %0, c0, c0, 2	@ strex status\n"
++		    : "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter)
++		    : "r" (&ptr->counter), "Ir" (old), "r" (new)
++		    : "cc");
++	} while (res);
++
++	smp_mb();
++
++	return oldval;
++}
++
++static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
++{
++	unsigned long tmp, tmp2;
++
++	__asm__ __volatile__("@ atomic_clear_mask\n"
++"1:	ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	bic	%0, %0, %4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++"	stc	p13, c0, [%3], {2}	@ strex to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (tmp), "=&r" (tmp2), "+Qo" (*addr)
++	: "r" (addr), "Ir" (mask)
++	: "cc");
++}
++
+ #else /* ARM_ARCH_6 */
+ 
+ #ifdef CONFIG_SMP
+@@ -241,6 +381,7 @@ typedef struct {
+ 
+ #define ATOMIC64_INIT(i) { (i) }
+ 
++#ifndef CONFIG_CPU_FMP626
+ static inline u64 atomic64_read(atomic64_t *v)
+ {
+ 	u64 result;
+@@ -448,6 +589,262 @@ static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
+ 
+ 	return ret;
+ }
++#else	/* CONFIG_CPU_FMP626 */
++static inline u64 atomic64_read(atomic64_t *v)
++{
++	u64 result;
++
++	__asm__ __volatile__("@ atomic64_read\n"
++"	ldc	p13, c0, [%1], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++	: "=&r" (result)
++	: "r" (&v->counter), "Qo" (v->counter)
++	);
++
++	return result;
++}
++
++static inline void atomic64_set(atomic64_t *v, u64 i)
++{
++	u64 tmp;
++
++	__asm__ __volatile__("@ atomic64_set\n"
++"1:	ldc	p13, c0, [%2], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++"	mcr	p13, 0, %3, c0, c0, 0	@ data for strexd\n"
++"	mcr	p13, 0, %H3, c0, c0, 1	@ data for strexd\n"
++"	stc	p13, c0, [%2], {3}	@ strexd to address\n"
++"	mrc	p13, 0, %0, c0, c0, 2	@ strexd status\n"
++"	teq	%0, #0\n"
++"	bne	1b"
++	: "=&r" (tmp), "=Qo" (v->counter)
++	: "r" (&v->counter), "r" (i)
++	: "cc");
++}
++
++static inline void atomic64_add(u64 i, atomic64_t *v)
++{
++	u64 result;
++	unsigned long tmp;
++
++	__asm__ __volatile__("@ atomic64_add\n"
++"1:	ldc	p13, c0, [%3], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++"	adds	%0, %0, %4\n"
++"	adc	%H0, %H0, %H4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strexd\n"
++"	mcr	p13, 0, %H0, c0, c0, 1	@ data for strexd\n"
++"	stc	p13, c0, [%3], {3}	@ strexd to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strexd status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "r" (i)
++	: "cc");
++}
++
++static inline u64 atomic64_add_return(u64 i, atomic64_t *v)
++{
++	u64 result;
++	unsigned long tmp;
++
++	smp_mb();
++
++	__asm__ __volatile__("@ atomic64_add_return\n"
++"1:	ldc	p13, c0, [%3], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++"	adds	%0, %0, %4\n"
++"	adc	%H0, %H0, %H4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strexd\n"
++"	mcr	p13, 0, %H0, c0, c0, 1	@ data for strexd\n"
++"	stc	p13, c0, [%3], {3}	@ strexd to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strexd status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "r" (i)
++	: "cc");
++
++	smp_mb();
++
++	return result;
++}
++
++static inline void atomic64_sub(u64 i, atomic64_t *v)
++{
++	u64 result;
++	unsigned long tmp;
++
++	__asm__ __volatile__("@ atomic64_sub\n"
++"1:	ldc	p13, c0, [%3], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++"	subs	%0, %0, %4\n"
++"	sbc	%H0, %H0, %H4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strexd\n"
++"	mcr	p13, 0, %H0, c0, c0, 1	@ data for strexd\n"
++"	stc	p13, c0, [%3], {3}	@ strexd to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strexd status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "r" (i)
++	: "cc");
++}
++
++static inline u64 atomic64_sub_return(u64 i, atomic64_t *v)
++{
++	u64 result;
++	unsigned long tmp;
++
++	smp_mb();
++
++	__asm__ __volatile__("@ atomic64_sub_return\n"
++"1:	ldc	p13, c0, [%3], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++"	subs	%0, %0, %4\n"
++"	sbc	%H0, %H0, %H4\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strexd\n"
++"	mcr	p13, 0, %H0, c0, c0, 1	@ data for strexd\n"
++"	stc	p13, c0, [%3], {3}	@ strexd to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strexd status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "r" (i)
++	: "cc");
++
++	smp_mb();
++
++	return result;
++}
++
++static inline u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old, u64 new)
++{
++	u64 oldval;
++	unsigned long res;
++
++	smp_mb();
++
++	do {
++		__asm__ __volatile__("@ atomic64_cmpxchg\n"
++		"ldc	p13, c0, [%3], {3}	@ set address for ldrexd\n"
++		"mrc	p13, 0, %1, c0, c0, 0	@ ldrexd\n"
++		"mrc	p13, 0, %H1, c0, c0, 1	@ ldrexd\n"
++		"mov	%0, #0\n"
++		"teq	%1, %4\n"
++		"teqeq	%H1, %H4\n"
++		"mcreq	p13, 0, %5, c0, c0, 0	@ data for strexd\n"
++		"mcreq	p13, 0, %H5, c0, c0, 1	@ data for strexd\n"
++		"stceq	p13, c0, [%3], {3}	@ strexd to address\n"
++		"mrceq	p13, 0, %0, c0, c0, 2	@ strexd status\n"
++		: "=&r" (res), "=&r" (oldval), "+Qo" (ptr->counter)
++		: "r" (&ptr->counter), "r" (old), "r" (new)
++		: "cc");
++	} while (res);
++
++	smp_mb();
++
++	return oldval;
++}
++
++static inline u64 atomic64_xchg(atomic64_t *ptr, u64 new)
++{
++	u64 result;
++	unsigned long tmp;
++
++	smp_mb();
++
++	__asm__ __volatile__("@ atomic64_xchg\n"
++"1:	ldc	p13, c0, [%3], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++"	mcr	p13, 0, %4, c0, c0, 0	@ data for strexd\n"
++"	mcr	p13, 0, %H4, c0, c0, 1	@ data for strexd\n"
++"	stc	p13, c0, [%3], {3}	@ strexd to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strexd status\n"
++"	teq	%1, #0\n"
++"	bne	1b"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (ptr->counter)
++	: "r" (&ptr->counter), "r" (new)
++	: "cc");
++
++	smp_mb();
++
++	return result;
++}
++
++static inline u64 atomic64_dec_if_positive(atomic64_t *v)
++{
++	u64 result;
++	unsigned long tmp;
++
++	smp_mb();
++
++	__asm__ __volatile__("@ atomic64_dec_if_positive\n"
++"1:	ldc	p13, c0, [%3], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++"	subs	%0, %0, #1\n"
++"	sbc	%H0, %H0, #0\n"
++"	teq	%H0, #0\n"
++"	bmi	2f\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strexd\n"
++"	mcr	p13, 0, %H0, c0, c0, 1	@ data for strexd\n"
++"	stc	p13, c0, [%3], {3}	@ strexd to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strexd status\n"
++"	teq	%1, #0\n"
++"	bne	1b\n"
++"2:"
++	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter)
++	: "cc");
++
++	smp_mb();
++
++	return result;
++}
++
++static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
++{
++	u64 val;
++	unsigned long tmp;
++	int ret = 1;
++
++	smp_mb();
++
++	__asm__ __volatile__("@ atomic64_add_unless\n"
++"1:	ldc	p13, c0, [%4], {3}	@ set address for ldrexd\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexd\n"
++"	mrc	p13, 0, %H0, c0, c0, 1	@ ldrexd\n"
++"	teq	%0, %5\n"
++"	teqeq	%H0, %H5\n"
++"	moveq	%1, #0\n"
++"	beq	2f\n"
++"	adds	%0, %0, %6\n"
++"	adc	%H0, %H0, %H6\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strexd\n"
++"	mcr	p13, 0, %H0, c0, c0, 1	@ data for strexd\n"
++"	stc	p13, c0, [%4], {3}	@ strexd to address\n"
++"	mrc	p13, 0, %2, c0, c0, 2	@ strexd status\n"
++"	teq	%2, #0\n"
++"	bne	1b\n"
++"2:"
++	: "=&r" (val), "+r" (ret), "=&r" (tmp), "+Qo" (v->counter)
++	: "r" (&v->counter), "r" (u), "r" (a)
++	: "cc");
++
++	if (ret)
++		smp_mb();
++
++	return ret;
++}
++#endif	/* CONFIG_CPU_FMP626 */
+ 
+ #define atomic64_add_negative(a, v)	(atomic64_add_return((a), (v)) < 0)
+ #define atomic64_inc(v)			atomic64_add(1LL, (v))
+diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
+index d5d8d5c7..1252a267 100644
+--- a/arch/arm/include/asm/cacheflush.h
++++ b/arch/arm/include/asm/cacheflush.h
+@@ -249,7 +249,7 @@ extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr
+  * Harvard caches are synchronised for the user space address range.
+  * This is used for the ARM private sys_cacheflush system call.
+  */
+-#define flush_cache_user_range(vma,start,end) \
++#define flush_cache_user_range(start,end) \
+ 	__cpuc_coherent_user_range((start) & PAGE_MASK, PAGE_ALIGN(end))
+ 
+ /*
+diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
+index 0e9ce8d9..7639dee1 100644
+--- a/arch/arm/include/asm/elf.h
++++ b/arch/arm/include/asm/elf.h
+@@ -130,8 +130,5 @@ struct mm_struct;
+ extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+ #define arch_randomize_brk arch_randomize_brk
+ 
+-extern int vectors_user_mapping(void);
+-#define arch_setup_additional_pages(bprm, uses_interp) vectors_user_mapping()
+-#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+ 
+ #endif
+diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
+index 7e308743..0f96aba9 100644
+--- a/arch/arm/include/asm/glue-cache.h
++++ b/arch/arm/include/asm/glue-cache.h
+@@ -41,11 +41,35 @@
+ # define MULTI_CACHE 1
+ #endif
+ 
+-#if defined(CONFIG_CPU_FA526)
++#if defined(CONFIG_CPU_FA526) || defined(CONFIG_CPU_FA626TE)
+ # ifdef _CACHE
+ #  define MULTI_CACHE 1
+ # else
+-#  define _CACHE fa
++#  ifdef CONFIG_PLATFORM_GM8210
++#   define _CACHE fmem
++#  else 
++#   define _CACHE fa
++#  endif 
++# endif
++#endif
++
++#if defined(CONFIG_CPU_FMP626)
++# ifdef _CACHE
++#  define MULTI_CACHE 1
++# else
++#  define _CACHE fmp626
++# endif
++#endif
++
++#if defined(CONFIG_CPU_FA726TE)
++# ifdef _CACHE
++#  define MULTI_CACHE 1
++# else
++#  ifdef CONFIG_PLATFORM_GM8210
++#   define _CACHE fmem
++#  else 
++#   define _CACHE fa726te
++#  endif 
+ # endif
+ #endif
+ 
+diff --git a/arch/arm/include/asm/glue-proc.h b/arch/arm/include/asm/glue-proc.h
+index e2be7f14..10c52720 100644
+--- a/arch/arm/include/asm/glue-proc.h
++++ b/arch/arm/include/asm/glue-proc.h
+@@ -104,6 +104,41 @@
+ # endif
+ #endif
+ 
++# ifdef CONFIG_CPU_FA626TE
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   ifdef CONFIG_PLATFORM_GM8210
++#       define CPU_NAME cpu_fmem
++#   else
++#       define CPU_NAME cpu_fa626te
++#   endif
++#  endif
++# endif
++
++# ifdef CONFIG_CPU_FMP626
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   define CPU_NAME cpu_fmp626
++#  endif
++# endif
++
++# ifdef CONFIG_CPU_FA726TE
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   ifdef CONFIG_PLATFORM_GM8210
++#       define CPU_NAME cpu_fmem
++#   else
++#       define CPU_NAME cpu_fa726te
++#   endif
++#  endif
++# endif
++
+ #ifdef CONFIG_CPU_ARM925T
+ # ifdef CPU_NAME
+ #  undef  MULTI_CPU
+diff --git a/arch/arm/include/asm/gpio.h b/arch/arm/include/asm/gpio.h
+index c402e9b3..6fe501bc 100644
+--- a/arch/arm/include/asm/gpio.h
++++ b/arch/arm/include/asm/gpio.h
+@@ -6,7 +6,7 @@
+ #endif
+ 
+ /* not all ARM platforms necessarily support this API ... */
+-#include <mach/gpio.h>
++//#include <mach/gpio.h>
+ 
+ #ifndef __ARM_GPIOLIB_COMPLEX
+ /* Note: this may rely upon the value of ARCH_NR_GPIOS set in mach/gpio.h */
+diff --git a/arch/arm/include/asm/hardware/arm_timer.h b/arch/arm/include/asm/hardware/arm_timer.h
+index c0f4e7bf..d6030ff5 100644
+--- a/arch/arm/include/asm/hardware/arm_timer.h
++++ b/arch/arm/include/asm/hardware/arm_timer.h
+@@ -9,7 +9,12 @@
+  *
+  * Integrator AP has 16-bit timers, Integrator CP, Versatile and Realview
+  * can have 16-bit or 32-bit selectable via a bit in the control register.
++ *
++ * Every SP804 contains two identical timers.
+  */
++#define TIMER_1_BASE	0x00
++#define TIMER_2_BASE	0x20
++
+ #define TIMER_LOAD	0x00			/* ACVR rw */
+ #define TIMER_VALUE	0x04			/* ACVR ro */
+ #define TIMER_CTRL	0x08			/* ACVR rw */
+diff --git a/arch/arm/include/asm/hardware/cache-ftl2cc031.h b/arch/arm/include/asm/hardware/cache-ftl2cc031.h
+new file mode 100644
+index 00000000..f935d9b9
+--- /dev/null
++++ b/arch/arm/include/asm/hardware/cache-ftl2cc031.h
+@@ -0,0 +1,104 @@
++/*
++ * arch/arm/include/asm/hardware/cache-ftl2cc031.h
++ *
++ * Copyright (C) 2010-2012 Faraday Limited
++ *
++ * 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.
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARM_HARDWARE_FTL2CC031_H
++#define __ASM_ARM_HARDWARE_FTL2CC031_H
++
++#define L2X0_CTRL               0x000   
++#define L2X0_AUX_CTRL           0x008
++
++#define L2X0_EVENT_CNT0_CTRL    0x010
++#define L2X0_EVENT_CNT1_CTRL    0x014
++#define L2X0_EVENT_CNT1_VAL	0x018
++#define L2X0_EVENT_CNT0_VAL	0x01C
++#define L2X0_RAW_INTR_SRC	0x020
++#define L2X0_MASKED_INTR_SRC    0x024
++#define L2X0_INTR_MASK		0x028
++#define L2X0_INTR_CLEAR		0x02C
++
++#define L2X0_CACHE_MAINTENAN_PA		0x040
++#define L2X0_CACHE_MAINTENAN_CNT	0x044
++#define L2X0_LINE_WAY_IDX		0x048
++#define L2X0_WAY_IDX			0x04C
++#define L2X0_CACHE_MAINTENANCE		0x050
++#define L2X0_LOCKDOWN_LINE	0x060
++#define L2X0_LOCKDOWN_WAY_I	0x064
++#define L2X0_LOCKDOWN_WAY_D	0x068
++#define L2X0_PREFETCH_CTRL	0x070
++
++#define L2X0_LINE_DATA_0	0x080
++#define L2X0_LINE_DATA_1	0x084
++#define L2X0_LINE_DATA_2	0x088
++#define L2X0_LINE_DATA_3	0x08C
++#define L2X0_LINE_DATA_4	0x090
++#define L2X0_LINE_DATA_5	0x094
++#define L2X0_LINE_DATA_6	0x098
++#define L2X0_LINE_DATA_7	0x09C
++#define L2X0_LINE_TAG		0x0A0
++#define L2X0_LINE_DATA_PARITY	0x0A4
++
++#define L2X0_CACHE_REVISION	0x200
++
++
++/////////////////////////////////////////////////////////////
++#define CTRL_TAG_INIT		(1 << 1)
++#define CTRL_L2CC_EN		(1 << 0)
++
++#define AUX_WAYNUM_16		(1 << 19)
++#define AUX_WAYSIZE(x)		((x & 0x7) << 16)
++#define AUX_FWALLOC		(1 << 13)
++#define AUX_NOT_FWALLOC		(1 << 12)
++#define AUX_SHA_ATTRI_EN	(1 << 10)
++#define AUX_EXC_CACHE_EN	(1 << 9)
++#define AUX_PAR_CHK_EN		(1 << 8)
++
++#define AUX_WAYSIZE_MASK	(0x7 << 16)
++
++#define WAYSIZE_16KB		0x0
++#define WAYSIZE_32KB		0x1
++#define WAYSIZE_64KB		0x2
++#define WAYSIZE_128KB		0x3
++#define WAYSIZE_256KB		0x4
++#define WAYSIZE_512KB		0x5
++
++// L2X0_CACHE_MAINTENANCE field
++#define L2X0_CACHE_SYNC		1
++#define L2X0_INV_PA		2
++#define L2X0_INV_LINE_WAY	3	// specify which way + which index
++#define L2X0_INV_WAY		4	// specify which way
++#define L2X0_CLEAN_PA		5
++#define L2X0_CLEAN_LINE_WAY	6
++#define L2X0_CLEAN_WAY		7
++#define L2X0_CLEAN_INV_PA	8
++#define L2X0_CLEAN_INV_LINE_WAY	9
++#define L2X0_CLEAN_INV_WAY	10
++#define L2X0_UNLOCK_WAY		11
++#define L2X0_TAG_WRITE		12
++#define L2X0_TAG_READ		13
++#define L2X0_DATA_WRITE		14
++#define L2X0_DATA_READ		15
++ 
++// new added function
++#define MASK_PA                   0xFFFFFFE0   // specify physical address   
++
++#ifndef __ASSEMBLY__
++extern void __init ftl2cc031_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
++#endif
++
++#endif
+diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
+index c6a18424..f77ffc1e 100644
+--- a/arch/arm/include/asm/localtimer.h
++++ b/arch/arm/include/asm/localtimer.h
+@@ -11,47 +11,24 @@
+ #define __ASM_ARM_LOCALTIMER_H
+ 
+ #include <linux/errno.h>
+-#include <linux/interrupt.h>
+ 
+ struct clock_event_device;
+ 
+-/*
+- * Setup a per-cpu timer, whether it be a local timer or dummy broadcast
+- */
+-void percpu_timer_setup(void);
++struct local_timer_ops {
++	int  (*setup)(struct clock_event_device *);
++	void (*stop)(struct clock_event_device *);
++};
+ 
+ #ifdef CONFIG_LOCAL_TIMERS
+-
+-#ifdef CONFIG_HAVE_ARM_TWD
+-
+-#include "smp_twd.h"
+-
+-#define local_timer_stop(c)	twd_timer_stop((c))
+-
+-#else
+-
+-/*
+- * Stop the local timer
+- */
+-void local_timer_stop(struct clock_event_device *);
+-
+-#endif
+-
+ /*
+- * Setup a local timer interrupt for a CPU.
++ * Register a local timer driver
+  */
+-int local_timer_setup(struct clock_event_device *);
+-
++int local_timer_register(struct local_timer_ops *);
+ #else
+-
+-static inline int local_timer_setup(struct clock_event_device *evt)
++static inline int local_timer_register(struct local_timer_ops *ops)
+ {
+ 	return -ENXIO;
+ }
+-
+-static inline void local_timer_stop(struct clock_event_device *evt)
+-{
+-}
+ #endif
+ 
+ #endif
+diff --git a/arch/arm/include/asm/locks.h b/arch/arm/include/asm/locks.h
+index ef4c8977..b23e9cf7 100644
+--- a/arch/arm/include/asm/locks.h
++++ b/arch/arm/include/asm/locks.h
+@@ -137,6 +137,150 @@
+ 	: "ip", "lr", "cc");			\
+ 	})
+ 
++#elif defined(CONFIG_CPU_FMP626)
++
++#define __down_op(ptr,fail)			\
++	({					\
++	__asm__ __volatile__(			\
++	"@ down_op\n"				\
++"1:	ldc	p13, c0, [%0], {2}	@ set address for ldrex\n"	\
++"	mrc	p13, 0, lr, c0, c0, 0	@ ldrex\n"			\
++"	sub	lr, lr, %1\n"			\
++"	mcr	p13, 0, lr, c0, c0, 0	@ data for strex\n"		\
++"	stc	p13, c0, [%0], {2}	@ strex to address\n"		\
++"	mrc	p13, 0, ip, c0, c0, 2	@ strex status\n"		\
++"	teq	ip, #0\n"			\
++"	bne	1b\n"				\
++"	teq	lr, #0\n"			\
++"	movmi	ip, %0\n"			\
++"	blmi	" #fail				\
++	:					\
++	: "r" (ptr), "I" (1)			\
++	: "ip", "lr", "cc");			\
++	smp_mb();				\
++	})
++
++#define __down_op_ret(ptr,fail)			\
++	({					\
++		unsigned int ret;		\
++	__asm__ __volatile__(			\
++	"@ down_op_ret\n"			\
++"1:	ldc	p13, c0, [%1], {2}	@ set address for ldrex\n"	\
++"	mrc	p13, 0, lr, c0, c0, 0	@ ldrex\n"			\
++"	sub	lr, lr, %2\n"			\
++"	mcr	p13, 0, lr, c0, c0, 0	@ data for strex\n"		\
++"	stc	p13, c0, [%1], {2}	@ strex to address\n"		\
++"	mrc	p13, 0, ip, c0, c0, 2	@ strex status\n"		\
++"	teq	ip, #0\n"			\
++"	bne	1b\n"				\
++"	teq	lr, #0\n"			\
++"	movmi	ip, %1\n"			\
++"	movpl	ip, #0\n"			\
++"	blmi	" #fail "\n"			\
++"	mov	%0, ip"				\
++	: "=&r" (ret)				\
++	: "r" (ptr), "I" (1)			\
++	: "ip", "lr", "cc");			\
++	smp_mb();				\
++	ret;					\
++	})
++
++#define __up_op(ptr,wake)			\
++	({					\
++	smp_mb();				\
++	__asm__ __volatile__(			\
++	"@ up_op\n"				\
++"1:	ldc	p13, c0, [%0], {2}	@ set address for ldrex\n"	\
++"	mrc	p13, 0, lr, c0, c0, 0	@ ldrex\n"			\
++"	add	lr, lr, %1\n"			\
++"	mcr	p13, 0, lr, c0, c0, 0	@ data for strex\n"		\
++"	stc	p13, c0, [%0], {2}	@ strex to address\n"		\
++"	mrc	p13, 0, ip, c0, c0, 2	@ strex status\n"		\
++"	teq	ip, #0\n"			\
++"	bne	1b\n"				\
++"	cmp	lr, #0\n"			\
++"	movle	ip, %0\n"			\
++"	blle	" #wake				\
++	:					\
++	: "r" (ptr), "I" (1)			\
++	: "ip", "lr", "cc");			\
++	})
++
++/*
++ * The value 0x01000000 supports up to 128 processors and
++ * lots of processes.  BIAS must be chosen such that sub'ing
++ * BIAS once per CPU will result in the long remaining
++ * negative.
++ */
++#define RW_LOCK_BIAS      0x01000000
++#define RW_LOCK_BIAS_STR "0x01000000"
++
++#define __down_op_write(ptr,fail)		\
++	({					\
++	__asm__ __volatile__(			\
++	"@ down_op_write\n"			\
++"1:	ldc	p13, c0, [%0], {2}	@ set address for ldrex\n"	\
++"	mrc	p13, 0, lr, c0, c0, 0	@ ldrex\n"			\
++"	sub	lr, lr, %1\n"			\
++"	mcr	p13, 0, lr, c0, c0, 0	@ data for strex\n"		\
++"	stc	p13, c0, [%0], {2}	@ strex to address\n"		\
++"	mrc	p13, 0, ip, c0, c0, 2	@ strex status\n"		\
++"	teq	ip, #0\n"			\
++"	bne	1b\n"				\
++"	teq	lr, #0\n"			\
++"	movne	ip, %0\n"			\
++"	blne	" #fail				\
++	:					\
++	: "r" (ptr), "I" (RW_LOCK_BIAS)		\
++	: "ip", "lr", "cc");			\
++	smp_mb();				\
++	})
++
++#define __up_op_write(ptr,wake)			\
++	({					\
++	smp_mb();				\
++	__asm__ __volatile__(			\
++	"@ up_op_write\n"			\
++"1:	ldc	p13, c0, [%0], {2}	@ set address for ldrex\n"	\
++"	mrc	p13, 0, lr, c0, c0, 0	@ ldrex\n"			\
++"	adds	lr, lr, %1\n"			\
++"	mcr	p13, 0, lr, c0, c0, 0	@ data for strex\n"		\
++"	stc	p13, c0, [%0], {2}	@ strex to address\n"		\
++"	mrc	p13, 0, ip, c0, c0, 2	@ strex status\n"		\
++"	teq	ip, #0\n"			\
++"	bne	1b\n"				\
++"	movcs	ip, %0\n"			\
++"	blcs	" #wake				\
++	:					\
++	: "r" (ptr), "I" (RW_LOCK_BIAS)		\
++	: "ip", "lr", "cc");			\
++	})
++
++#define __down_op_read(ptr,fail)		\
++	__down_op(ptr, fail)
++
++#define __up_op_read(ptr,wake)			\
++	({					\
++	smp_mb();				\
++	__asm__ __volatile__(			\
++	"@ up_op_read\n"			\
++"1:	ldc	p13, c0, [%0], {2}	@ set address for ldrex\n"	\
++"	mrc	p13, 0, lr, c0, c0, 0	@ ldrex\n"			\
++"	add	lr, lr, %1\n"			\
++"	mcr	p13, 0, lr, c0, c0, 0	@ data for strex\n"		\
++"	stc	p13, c0, [%0], {2}	@ strex to address\n"		\
++"	mrc	p13, 0, ip, c0, c0, 2	@ strex status\n"		\
++"	teq	ip, #0\n"			\
++"	bne	1b\n"				\
++"	teq	lr, #0\n"			\
++"	moveq	ip, %0\n"			\
++"	bleq	" #wake				\
++	:					\
++	: "r" (ptr), "I" (1)			\
++	: "ip", "lr", "cc");			\
++	})
++
++
+ #else
+ 
+ #define __down_op(ptr,fail)			\
+diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h
+index 71605d9f..bce9ec40 100644
+--- a/arch/arm/include/asm/mmu_context.h
++++ b/arch/arm/include/asm/mmu_context.h
+@@ -18,6 +18,7 @@
+ #include <asm/cacheflush.h>
+ #include <asm/cachetype.h>
+ #include <asm/proc-fns.h>
++#include <asm-generic/mm_hooks.h>
+ 
+ void __check_kvm_seq(struct mm_struct *mm);
+ 
+@@ -42,45 +43,104 @@ void __check_kvm_seq(struct mm_struct *mm);
+ #define ASID_FIRST_VERSION	(1 << ASID_BITS)
+ 
+ extern unsigned int cpu_last_asid;
+-#ifdef CONFIG_SMP
+-DECLARE_PER_CPU(struct mm_struct *, current_mm);
+-#endif
+ 
+ void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void __new_context(struct mm_struct *mm);
++void cpu_set_reserved_ttbr0(void);
+ 
+-static inline void check_context(struct mm_struct *mm)
++static inline void switch_new_context(struct mm_struct *mm)
+ {
+-	/*
+-	 * This code is executed with interrupts enabled. Therefore,
+-	 * mm->context.id cannot be updated to the latest ASID version
+-	 * on a different CPU (and condition below not triggered)
+-	 * without first getting an IPI to reset the context. The
+-	 * alternative is to take a read_lock on mm->context.id_lock
+-	 * (after changing its type to rwlock_t).
+-	 */
+-	if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS))
+-		__new_context(mm);
++	unsigned long flags;
+ 
++	__new_context(mm);
++
++	local_irq_save(flags);
++	cpu_switch_mm(mm->pgd, mm);
++	local_irq_restore(flags);
++}
++
++static inline void check_and_switch_context(struct mm_struct *mm,
++					    struct task_struct *tsk)
++{
+ 	if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq))
+ 		__check_kvm_seq(mm);
++
++	/*
++	 * Required during context switch to avoid speculative page table
++	 * walking with the wrong TTBR.
++	 */
++	cpu_set_reserved_ttbr0();
++
++	if (!((mm->context.id ^ cpu_last_asid) >> ASID_BITS))
++		/*
++		 * The ASID is from the current generation, just switch to the
++		 * new pgd. This condition is only true for calls from
++		 * context_switch() and interrupts are already disabled.
++		 */
++		cpu_switch_mm(mm->pgd, mm);
++	else if (irqs_disabled())
++		/*
++		 * Defer the new ASID allocation until after the context
++		 * switch critical region since __new_context() cannot be
++		 * called with interrupts disabled (it sends IPIs).
++		 */
++		set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM);
++	else
++		/*
++		 * That is a direct call to switch_mm() or activate_mm() with
++		 * interrupts enabled and a new context.
++		 */
++		switch_new_context(mm);
+ }
+ 
+ #define init_new_context(tsk,mm)	(__init_new_context(tsk,mm),0)
+ 
+-#else
+-
+-static inline void check_context(struct mm_struct *mm)
++#define finish_arch_post_lock_switch \
++	finish_arch_post_lock_switch
++static inline void finish_arch_post_lock_switch(void)
+ {
++	if (test_and_clear_thread_flag(TIF_SWITCH_MM))
++		switch_new_context(current->mm);
++}
++
++#else	/* !CONFIG_CPU_HAS_ASID */
++
+ #ifdef CONFIG_MMU
++
++static inline void check_and_switch_context(struct mm_struct *mm,
++					    struct task_struct *tsk)
++{
+ 	if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq))
+ 		__check_kvm_seq(mm);
+-#endif
++
++	if (irqs_disabled())
++		/*
++		 * cpu_switch_mm() needs to flush the VIVT caches. To avoid
++		 * high interrupt latencies, defer the call and continue
++		 * running with the old mm. Since we only support UP systems
++		 * on non-ASID CPUs, the old mm will remain valid until the
++		 * finish_arch_post_lock_switch() call.
++		 */
++		set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM);
++	else
++		cpu_switch_mm(mm->pgd, mm);
++}
++
++#define finish_arch_post_lock_switch \
++	finish_arch_post_lock_switch
++static inline void finish_arch_post_lock_switch(void)
++{
++	if (test_and_clear_thread_flag(TIF_SWITCH_MM)) {
++		struct mm_struct *mm = current->mm;
++		cpu_switch_mm(mm->pgd, mm);
++	}
+ }
+ 
++#endif	/* CONFIG_MMU */
++
+ #define init_new_context(tsk,mm)	0
+ 
+-#endif
++#endif	/* CONFIG_CPU_HAS_ASID */
+ 
+ #define destroy_context(mm)		do { } while(0)
+ 
+@@ -118,12 +178,15 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ 		__flush_icache_all();
+ #endif
+ 	if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
+-#ifdef CONFIG_SMP
++#if 0
++#if defined(CONFIG_CPU_HAS_ASID) && defined(CONFIG_SMP)
+ 		struct mm_struct **crt_mm = &per_cpu(current_mm, cpu);
+ 		*crt_mm = next;
+ #endif
+ 		check_context(next);
+ 		cpu_switch_mm(next->pgd, next);
++#endif
++		check_and_switch_context(next, tsk);
+ 		if (cache_is_vivt())
+ 			cpumask_clear_cpu(cpu, mm_cpumask(prev));
+ 	}
+@@ -133,32 +196,4 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ #define deactivate_mm(tsk,mm)	do { } while (0)
+ #define activate_mm(prev,next)	switch_mm(prev, next, NULL)
+ 
+-/*
+- * We are inserting a "fake" vma for the user-accessible vector page so
+- * gdb and friends can get to it through ptrace and /proc/<pid>/mem.
+- * But we also want to remove it before the generic code gets to see it
+- * during process exit or the unmapping of it would  cause total havoc.
+- * (the macro is used as remove_vma() is static to mm/mmap.c)
+- */
+-#define arch_exit_mmap(mm) \
+-do { \
+-	struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \
+-	if (high_vma) { \
+-		BUG_ON(high_vma->vm_next);  /* it should be last */ \
+-		if (high_vma->vm_prev) \
+-			high_vma->vm_prev->vm_next = NULL; \
+-		else \
+-			mm->mmap = NULL; \
+-		rb_erase(&high_vma->vm_rb, &mm->mm_rb); \
+-		mm->mmap_cache = NULL; \
+-		mm->map_count--; \
+-		remove_vma(high_vma); \
+-	} \
+-} while (0)
+-
+-static inline void arch_dup_mmap(struct mm_struct *oldmm,
+-				 struct mm_struct *mm)
+-{
+-}
+-
+ #endif
+diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h
+index 93226cf2..7cff6260 100644
+--- a/arch/arm/include/asm/mutex.h
++++ b/arch/arm/include/asm/mutex.h
+@@ -8,9 +8,132 @@
+ #ifndef _ASM_MUTEX_H
+ #define _ASM_MUTEX_H
+ 
+-#if __LINUX_ARM_ARCH__ < 6
++#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_CPU_FMP626)
+ /* On pre-ARMv6 hardware the swp based implementation is the most efficient. */
+ # include <asm-generic/mutex-xchg.h>
++#elif defined(CONFIG_CPU_FMP626)
++/*
++ * Attempting to lock a mutex on ARMv6+ can be done with a bastardized
++ * atomic decrement (it is not a reliable atomic decrement but it satisfies
++ * the defined semantics for our purpose, while being smaller and faster
++ * than a real atomic decrement or atomic swap.  The idea is to attempt
++ * decrementing the lock value only once.  If once decremented it isn't zero,
++ * or if its store-back fails due to a dispute on the exclusive store, we
++ * simply bail out immediately through the slow path where the lock will be
++ * reattempted until it succeeds.
++ */
++static inline void
++__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
++{
++	int __ex_flag, __res;
++
++	__asm__ (
++
++	"	ldc	p13, c0, [%2], {2}	@ set address for ldrex\n"
++	"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++	"	sub	%0, %0, #1\n"
++	"	mcr	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++	"	stc	p13, c0, [%2], {2}	@ strex to address\n"
++	"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++
++		: "=&r" (__res), "=&r" (__ex_flag)
++		: "r" (&(count)->counter)
++		: "cc","memory" );
++
++	__res |= __ex_flag;
++	if (unlikely(__res != 0))
++		fail_fn(count);
++}
++
++static inline int
++__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
++{
++	int __ex_flag, __res;
++
++	__asm__ (
++
++	"	ldc	p13, c0, [%2], {2}	@ set address for ldrex\n"
++	"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++	"	sub	%0, %0, #1\n"
++	"	mcr	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++	"	stc	p13, c0, [%2], {2}	@ strex to address\n"
++	"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++
++		: "=&r" (__res), "=&r" (__ex_flag)
++		: "r" (&(count)->counter)
++		: "cc","memory" );
++
++	__res |= __ex_flag;
++	if (unlikely(__res != 0))
++		__res = fail_fn(count);
++	return __res;
++}
++
++/*
++ * Same trick is used for the unlock fast path. However the original value,
++ * rather than the result, is used to test for success in order to have
++ * better generated assembly.
++ */
++static inline void
++__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
++{
++	int __ex_flag, __res, __orig;
++
++	__asm__ (
++
++	"	ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++	"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++	"	add	%1, %0, #1\n"
++	"	mcr	p13, 0, %1, c0, c0, 0	@ data for strex\n"
++	"	stc	p13, c0, [%3], {2}	@ strex to address\n"
++	"	mrc	p13, 0, %2, c0, c0, 2	@ strex status\n"
++
++		: "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
++		: "r" (&(count)->counter)
++		: "cc","memory" );
++
++	__orig |= __ex_flag;
++	if (unlikely(__orig != 0))
++		fail_fn(count);
++}
++
++/*
++ * If the unlock was done on a contended lock, or if the unlock simply fails
++ * then the mutex remains locked.
++ */
++#define __mutex_slowpath_needs_to_unlock()	1
++
++/*
++ * For __mutex_fastpath_trylock we use another construct which could be
++ * described as a "single value cmpxchg".
++ *
++ * This provides the needed trylock semantics like cmpxchg would, but it is
++ * lighter and less generic than a true cmpxchg implementation.
++ */
++static inline int
++__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
++{
++	int __ex_flag, __res, __orig;
++
++	__asm__ (
++
++	"1:	ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++	"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++	"	subs	%1, %0, #1\n"
++	"	mcreq	p13, 0, %1, c0, c0, 0	@ data for strex\n"
++	"	stceq	p13, c0, [%3], {2}	@ strex to address\n"
++	"	mrceq	p13, 0, %2, c0, c0, 2	@ strex status\n"
++	"	movlt	%0, #0\n"
++	"	cmpeq	%2, #0\n"
++	"	bgt	1b\n"
++
++		: "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
++		: "r" (&count->counter)
++		: "cc", "memory" );
++
++	return __orig;
++}
++
+ #else
+ 
+ /*
+diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
+index 97b440c2..39482679 100644
+--- a/arch/arm/include/asm/page.h
++++ b/arch/arm/include/asm/page.h
+@@ -77,11 +77,7 @@
+ #endif
+ 
+ #ifdef CONFIG_CPU_COPY_FA
+-# ifdef _USER
+-#  define MULTI_USER 1
+-# else
+-#  define _USER fa
+-# endif
++# define MULTI_USER 1
+ #endif
+ 
+ #ifdef CONFIG_CPU_SA1100
+@@ -151,6 +147,8 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
+ #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
+ extern void copy_page(void *to, const void *from);
+ 
++#define __HAVE_ARCH_GATE_AREA 1
++
+ #ifdef CONFIG_ARM_LPAE
+ #include <asm/pgtable-3level-types.h>
+ #else
+diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
+index 99cfe360..a55fa66d 100644
+--- a/arch/arm/include/asm/perf_event.h
++++ b/arch/arm/include/asm/perf_event.h
+@@ -24,8 +24,10 @@ enum arm_perf_pmu_ids {
+ 	ARM_PERF_PMU_ID_V6MP,
+ 	ARM_PERF_PMU_ID_CA8,
+ 	ARM_PERF_PMU_ID_CA9,
++ 	ARM_PERF_PMU_ID_FMP626,
+ 	ARM_PERF_PMU_ID_CA5,
+ 	ARM_PERF_PMU_ID_CA15,
++	ARM_PERF_PMU_ID_CA7,
+ 	ARM_NUM_PMU_IDS,
+ };
+ 
+diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
+index cb8d6389..84ba5727 100644
+--- a/arch/arm/include/asm/processor.h
++++ b/arch/arm/include/asm/processor.h
+@@ -84,7 +84,7 @@ extern void release_thread(struct task_struct *);
+ 
+ unsigned long get_wchan(struct task_struct *p);
+ 
+-#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
++#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327) || defined(CONFIG_CPU_FMP626)
+ #define cpu_relax()			smp_mb()
+ #else
+ #define cpu_relax()			barrier()
+diff --git a/arch/arm/include/asm/serial.h b/arch/arm/include/asm/serial.h
+index ebb04909..9424185b 100644
+--- a/arch/arm/include/asm/serial.h
++++ b/arch/arm/include/asm/serial.h
+@@ -14,6 +14,16 @@
+ #ifndef __ASM_SERIAL_H
+ #define __ASM_SERIAL_H
+ 
++#if defined(CONFIG_ARCH_FARADAY)
++#include <mach/serial.h>
++#endif
++
++#if (defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP))
++#include <mach/serial.h>
++#endif
++
++#ifndef BASE_BAUD
+ #define BASE_BAUD	(1843200 / 16)
++#endif
+ 
+ #endif
+diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
+index ef9ffba9..0f01f467 100644
+--- a/arch/arm/include/asm/smp_twd.h
++++ b/arch/arm/include/asm/smp_twd.h
+@@ -18,11 +18,28 @@
+ #define TWD_TIMER_CONTROL_PERIODIC	(1 << 1)
+ #define TWD_TIMER_CONTROL_IT_ENABLE	(1 << 2)
+ 
+-struct clock_event_device;
++#include <linux/ioport.h>
+ 
+-extern void __iomem *twd_base;
++struct twd_local_timer {
++	struct resource	res[2];
++};
+ 
+-void twd_timer_setup(struct clock_event_device *);
+-void twd_timer_stop(struct clock_event_device *);
++#define DEFINE_TWD_LOCAL_TIMER(name,base,irq)	\
++struct twd_local_timer name __initdata = {	\
++	.res	= {				\
++		DEFINE_RES_MEM(base, 0x10),	\
++		DEFINE_RES_IRQ(irq),		\
++	},					\
++};
++
++int twd_local_timer_register(struct twd_local_timer *);
++
++#ifdef CONFIG_HAVE_ARM_TWD
++void twd_local_timer_of_register(void);
++#else
++static inline void twd_local_timer_of_register(void)
++{
++}
++#endif
+ 
+ #endif
+diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
+index 65fa3c88..7bc0fc66 100644
+--- a/arch/arm/include/asm/spinlock.h
++++ b/arch/arm/include/asm/spinlock.h
+@@ -1,7 +1,7 @@
+ #ifndef __ASM_SPINLOCK_H
+ #define __ASM_SPINLOCK_H
+ 
+-#if __LINUX_ARM_ARCH__ < 6
++#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_CPU_FMP626)
+ #error SMP not supported on pre-ARMv6 CPUs
+ #endif
+ 
+@@ -49,6 +49,12 @@ static inline void dsb_sev(void)
+ 		"dsb\n"
+ 		SEV
+ 	);
++#elif defined(CONFIG_CPU_FMP626)
++	__asm__ __volatile__ (
++		"mcr	p15, 0, %0, c7, c10, 4\n"
++		"cdp	p13, 0, c0, c0, c0, 1	@ set event\n"
++		: : "r" (0)
++	);
+ #else
+ 	__asm__ __volatile__ (
+ 		"mcr p15, 0, %0, c7, c10, 4\n"
+@@ -76,6 +82,51 @@ static inline void dsb_sev(void)
+ 
+ #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+ 
++#ifdef CONFIG_CPU_FMP626
++static inline void arch_spin_lock(arch_spinlock_t *lock)
++{
++	unsigned long tmp;
++
++	__asm__ __volatile__(
++"1:	ldc	p13, c0, [%1], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	teq	%0, #0\n"
++"	cdpne	p13, 0, c0, c0, c0, 0	@ wait for event\n"
++"	mcreq	p13, 0, %2, c0, c0, 0	@ data for strex\n"
++"	stceq	p13, c0, [%1], {2}	@ strex to address\n"
++"	mrceq	p13, 0, %0, c0, c0, 2	@ strex status\n"
++"	teqeq	%0, #0\n"
++"	bne	1b"
++	: "=&r" (tmp)
++	: "r" (&lock->lock), "r" (1)
++	: "cc");
++
++	smp_mb();
++}
++
++static inline int arch_spin_trylock(arch_spinlock_t *lock)
++{
++	unsigned long tmp;
++
++	__asm__ __volatile__(
++"	ldc	p13, c0, [%1], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	teq	%0, #0\n"
++"	mcreq	p13, 0, %2, c0, c0, 0	@ data for strex\n"
++"	stceq	p13, c0, [%1], {2}	@ strex to address\n"
++"	mrceq	p13, 0, %0, c0, c0, 2	@ strex status\n"
++	: "=&r" (tmp)
++	: "r" (&lock->lock), "r" (1)
++	: "cc");
++
++	if (tmp == 0) {
++		smp_mb();
++		return 1;
++	} else {
++		return 0;
++	}
++}
++#else
+ static inline void arch_spin_lock(arch_spinlock_t *lock)
+ {
+ 	unsigned long tmp;
+@@ -113,6 +164,7 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
+ 		return 0;
+ 	}
+ }
++#endif
+ 
+ static inline void arch_spin_unlock(arch_spinlock_t *lock)
+ {
+@@ -135,6 +187,51 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
+  * just write zero since the lock is exclusively held.
+  */
+ 
++#ifdef CONFIG_CPU_FMP626
++static inline void arch_write_lock(arch_rwlock_t *rw)
++{
++	unsigned long tmp;
++
++	__asm__ __volatile__(
++"1:	ldc	p13, c0, [%1], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	teq	%0, #0\n"
++"	cdpne	p13, 0, c0, c0, c0, 0	@ wait for event\n"
++"	mcreq	p13, 0, %2, c0, c0, 0	@ data for strex\n"
++"	stceq	p13, c0, [%1], {2}	@ strex to address\n"
++"	mrceq	p13, 0, %0, c0, c0, 2	@ strex status\n"
++"	teq	%0, #0\n"
++"	bne	1b"
++	: "=&r" (tmp)
++	: "r" (&rw->lock), "r" (0x80000000)
++	: "cc");
++
++	smp_mb();
++}
++
++static inline int arch_write_trylock(arch_rwlock_t *rw)
++{
++	unsigned long tmp;
++
++	__asm__ __volatile__(
++"1:	ldc	p13, c0, [%1], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	teq	%0, #0\n"
++"	mcreq	p13, 0, %2, c0, c0, 0	@ data for strex\n"
++"	stceq	p13, c0, [%1], {2}	@ strex to address\n"
++"	mrceq	p13, 0, %0, c0, c0, 2	@ strex status\n"
++	: "=&r" (tmp)
++	: "r" (&rw->lock), "r" (0x80000000)
++	: "cc");
++
++	if (tmp == 0) {
++		smp_mb();
++		return 1;
++	} else {
++		return 0;
++	}
++}
++#else
+ static inline void arch_write_lock(arch_rwlock_t *rw)
+ {
+ 	unsigned long tmp;
+@@ -172,6 +269,7 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
+ 		return 0;
+ 	}
+ }
++#endif
+ 
+ static inline void arch_write_unlock(arch_rwlock_t *rw)
+ {
+@@ -201,6 +299,70 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
+  * currently active.  However, we know we won't have any write
+  * locks.
+  */
++#ifdef CONFIG_CPU_FMP626
++static inline void arch_read_lock(arch_rwlock_t *rw)
++{
++	unsigned long tmp, tmp2;
++
++	__asm__ __volatile__(
++"1:	ldc	p13, c0, [%2], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	adds	%0, %0, #1\n"
++"	mcrpl	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++"	stcpl	p13, c0, [%2], {2}	@ strex to address\n"
++"	mrcpl	p13, 0, %1, c0, c0, 2	@ strex status\n"
++"	cdpmi	p13, 0, c0, c0, c0, 0	@ wait for event\n"
++"	rsbpls	%0, %1, #0\n"
++"	bmi	1b"
++	: "=&r" (tmp), "=&r" (tmp2)
++	: "r" (&rw->lock)
++	: "cc");
++
++	smp_mb();
++}
++
++static inline void arch_read_unlock(arch_rwlock_t *rw)
++{
++	unsigned long tmp, tmp2;
++
++	smp_mb();
++
++	__asm__ __volatile__(
++"1:	ldc	p13, c0, [%2], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	sub	%0, %0, #1\n"
++"	mcr	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++"	stc	p13, c0, [%2], {2}	@ strex to address\n"
++"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++"	teq	%1, #0\n"
++"	bne	1b\n"
++	: "=&r" (tmp), "=&r" (tmp2)
++	: "r" (&rw->lock)
++	: "cc");
++
++	if (tmp == 0)
++		dsb_sev();
++}
++
++static inline int arch_read_trylock(arch_rwlock_t *rw)
++{
++	unsigned long tmp, tmp2 = 1;
++
++	__asm__ __volatile__(
++"1:	ldc	p13, c0, [%2], {2}	@ set address for ldrex\n"
++"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++"	adds	%0, %0, #1\n"
++"	mcrpl	p13, 0, %0, c0, c0, 0	@ data for strex\n"
++"	stcpl	p13, c0, [%2], {2}	@ strex to address\n"
++"	mrcpl	p13, 0, %1, c0, c0, 2	@ strex status\n"
++	: "=&r" (tmp), "+r" (tmp2)
++	: "r" (&rw->lock)
++	: "cc");
++
++	smp_mb();
++	return tmp2 == 0;
++}
++#else
+ static inline void arch_read_lock(arch_rwlock_t *rw)
+ {
+ 	unsigned long tmp, tmp2;
+@@ -254,6 +416,7 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
+ 	smp_mb();
+ 	return tmp2 == 0;
+ }
++#endif
+ 
+ /* read_can_lock - would read_trylock() succeed? */
+ #define arch_read_can_lock(x)		((x)->lock < 0x80000000)
+diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
+index e4c96cc6..5575ac0f 100644
+--- a/arch/arm/include/asm/system.h
++++ b/arch/arm/include/asm/system.h
+@@ -130,27 +130,48 @@ extern unsigned int user_debug;
+ #define sev()	__asm__ __volatile__ ("sev" : : : "memory")
+ #define wfe()	__asm__ __volatile__ ("wfe" : : : "memory")
+ #define wfi()	__asm__ __volatile__ ("wfi" : : : "memory")
++#elif defined(CONFIG_CPU_FMP626)
++#define sev()	__asm__ __volatile__ ("cdp p13, 0, c0, c0, c0, 1" : : : "memory")
++#define wfe()	__asm__ __volatile__ ("cdp p13, 0, c0, c0, c0, 0" : : : "memory")
++#define wfi()	__asm__ __volatile__ ("mcr p15, 0, %0, c7, c0, 4" \
++				      : : "r" (0): "memory")
+ #endif
+ 
+ #if __LINUX_ARM_ARCH__ >= 7
+ #define isb() __asm__ __volatile__ ("isb" : : : "memory")
+ #define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
+ #define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
+-#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
++#elif defined(CONFIG_CPU_XSC3) || defined(CONFIG_CPU_FMP626) || __LINUX_ARM_ARCH__ == 6
+ #define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
+ 				    : : "r" (0) : "memory")
+ #define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+ 				    : : "r" (0) : "memory")
+ #define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
+ 				    : : "r" (0) : "memory")
+-#elif defined(CONFIG_CPU_FA526)
++#elif defined(CONFIG_CPU_FA526) || defined(CONFIG_CPU_FA626TE)
++#ifdef CONFIG_PLATFORM_GM8210
++#define isb()   do { unsigned int value;    \
++                    __asm__ __volatile__ ("mrc p15, 0, %0, c0, c0, 0\t\n": "=r"(value)); \
++                    if (((value >> 4) & 0xFFF) == 0x726) __asm__ __volatile__ ("" : : : "memory");   \
++                    else __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory");  \
++                } while(0)
++#else
+ #define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
+ 				    : : "r" (0) : "memory")
++#endif /* CONFIG_PLATFORM_GM8210 */				    
+ #define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+ 				    : : "r" (0) : "memory")
+ #define dmb() __asm__ __volatile__ ("" : : : "memory")
+ #else
++#ifdef CONFIG_PLATFORM_GM8210
++#define isb()   do { unsigned int value;    \
++                    __asm__ __volatile__ ("mrc p15, 0, %0, c0, c0, 0\t\n": "=r"(value)); \
++                    if (((value >> 4) & 0xFFF) == 0x726) __asm__ __volatile__ ("" : : : "memory");   \
++                    else __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory");  \
++                } while(0)
++#else
+ #define isb() __asm__ __volatile__ ("" : : : "memory")
++#endif /* CONFIG_PLATFORM_GM8210 */
+ #define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+ 				    : : "r" (0) : "memory")
+ #define dmb() __asm__ __volatile__ ("" : : : "memory")
+@@ -225,13 +246,6 @@ static inline void set_copro_access(unsigned int val)
+ 	isb();
+ }
+ 
+-/*
+- * switch_mm() may do a full cache flush over the context switch,
+- * so enable interrupts over the context switch to avoid high
+- * latency.
+- */
+-#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
+-
+ /*
+  * switch_to(prev, next) should switch from task `prev' to `next'
+  * `prev' will never be the same as `next'.  schedule() itself
+@@ -270,7 +284,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
+ #ifdef swp_is_buggy
+ 	unsigned long flags;
+ #endif
+-#if __LINUX_ARM_ARCH__ >= 6
++#if __LINUX_ARM_ARCH__ >= 6 || defined(CONFIG_CPU_FMP626)
+ 	unsigned int tmp;
+ #endif
+ 
+@@ -298,6 +312,33 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
+ 			: "r" (x), "r" (ptr)
+ 			: "memory", "cc");
+ 		break;
++#elif defined(CONFIG_CPU_FMP626)
++	case 1:
++		asm volatile("@	__xchg1\n"
++		"1:	ldc	p13, c0, [%3], {0}	@ set address for ldrexb\n"
++		"	mrc	p13, 0, %0, c0, c0, 0	@ ldrexb\n"
++		"	mcr	p13, 0, %2, c0, c0, 0	@ data for strexb\n"
++		"	stc	p13, c0, [%3], {0}	@ strexb to address\n"
++		"	mrc	p13, 0, %1, c0, c0, 2	@ strexb status\n"
++		"	teq	%1, #0\n"
++		"	bne	1b"
++			: "=&r" (ret), "=&r" (tmp)
++			: "r" (x), "r" (ptr)
++			: "memory", "cc");
++		break;
++	case 4:
++		asm volatile("@	__xchg4\n"
++		"1:	ldc	p13, c0, [%3], {2}	@ set address for ldrex\n"
++		"	mrc	p13, 0, %0, c0, c0, 0	@ ldrex\n"
++		"	mcr	p13, 0, %2, c0, c0, 0	@ data for strex\n"
++		"	stc	p13, c0, [%3], {2}	@ strex to address\n"
++		"	mrc	p13, 0, %1, c0, c0, 2	@ strex status\n"
++		"	teq	%1, #0\n"
++		"	bne	1b"
++			: "=&r" (ret), "=&r" (tmp)
++			: "r" (x), "r" (ptr)
++			: "memory", "cc");
++		break;
+ #elif defined(swp_is_buggy)
+ #ifdef CONFIG_SMP
+ #error SMP is not supported on this platform
+@@ -347,7 +388,7 @@ void cpu_idle_wait(void);
+ 
+ #include <asm-generic/cmpxchg-local.h>
+ 
+-#if __LINUX_ARM_ARCH__ < 6
++#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_CPU_FMP626)
+ /* min ARCH < ARMv6 */
+ 
+ #ifdef CONFIG_SMP
+@@ -381,6 +422,7 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+ 	unsigned long oldval, res;
+ 
+ 	switch (size) {
++#ifndef CONFIG_CPU_FMP626
+ #ifndef CONFIG_CPU_V6	/* min ARCH >= ARMv6K */
+ 	case 1:
+ 		do {
+@@ -419,6 +461,53 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+ 				: "memory", "cc");
+ 		} while (res);
+ 		break;
++#else	/* CONFIG_CPU_FMP626 */
++	case 1:
++		do {
++			asm volatile("@ __cmpxchg1\n"
++			"	ldc	p13, c0, [%2], {0}	@ set address for ldrexb\n"
++			"	mrc	p13, 0, %1, c0, c0, 0	@ ldrexb\n"
++			"	mov	%0, #0\n"
++			"	teq	%1, %3\n"
++			"	mcreq	p13, 0, %4, c0, c0, 0	@ data for strexb\n"
++			"	stceq	p13, c0, [%2], {0}	@ strexb to address\n"
++			"	mrceq	p13, 0, %0, c0, c0, 2	@ strexb status\n"
++				: "=&r" (res), "=&r" (oldval)
++				: "r" (ptr), "Ir" (old), "r" (new)
++				: "memory", "cc");
++		} while (res);
++		break;
++	case 2:
++		do {
++			asm volatile("@ __cmpxchg1\n"
++			"	ldc	p13, c0, [%2], {1}	@ set address for ldrexh\n"
++			"	mrc	p13, 0, %1, c0, c0, 0	@ ldrexh\n"
++			"	mov	%0, #0\n"
++			"	teq	%1, %3\n"
++			"	mcreq	p13, 0, %4, c0, c0, 0	@ data for strexh\n"
++			"	stceq	p13, c0, [%2], {1}	@ strexh to address\n"
++			"	mrceq	p13, 0, %0, c0, c0, 2	@ strexh status\n"
++				: "=&r" (res), "=&r" (oldval)
++				: "r" (ptr), "Ir" (old), "r" (new)
++				: "memory", "cc");
++		} while (res);
++		break;
++	case 4:
++		do {
++			asm volatile("@ __cmpxchg4\n"
++			"	ldc	p13, c0, [%2], {2}	@ set address for ldrex\n"
++			"	mrc	p13, 0, %1, c0, c0, 0	@ ldrex\n"
++			"	mov	%0, #0\n"
++			"	teq	%1, %3\n"
++			"	mcreq	p13, 0, %4, c0, c0, 0	@ data for strex\n"
++			"	stceq	p13, c0, [%2], {2}	@ strex to address\n"
++			"	mrceq	p13, 0, %0, c0, c0, 2	@ strex status\n"
++				: "=&r" (res), "=&r" (oldval)
++				: "r" (ptr), "Ir" (old), "r" (new)
++				: "memory", "cc");
++		} while (res);
++		break;
++#endif	/* CONFIG_CPU_FMP626 */
+ 	default:
+ 		__bad_cmpxchg(ptr, size);
+ 		oldval = 0;
+@@ -452,7 +541,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
+ 	unsigned long ret;
+ 
+ 	switch (size) {
+-#ifdef CONFIG_CPU_V6	/* min ARCH == ARMv6 */
++#if defined(CONFIG_CPU_V6) && !defined(CONFIG_CPU_FMP626)/* min ARCH == ARMv6 */
+ 	case 1:
+ 	case 2:
+ 		ret = __cmpxchg_local_generic(ptr, old, new, size);
+@@ -471,13 +560,11 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
+ 				       (unsigned long)(n),		\
+ 				       sizeof(*(ptr))))
+ 
+-#ifndef CONFIG_CPU_V6	/* min ARCH >= ARMv6K */
++#if !defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_FMP626)/* min ARCH >= ARMv6K */
++  
++#ifndef CONFIG_CPU_FMP626
+ 
+-/*
+- * Note : ARMv7-M (currently unsupported by Linux) does not support
+- * ldrexd/strexd. If ARMv7-M is ever supported by the Linux kernel, it should
+- * not be allowed to use __cmpxchg64.
+- */
++#else	/* CONFIG_CPU_FMP626 */
+ static inline unsigned long long __cmpxchg64(volatile void *ptr,
+ 					     unsigned long long old,
+ 					     unsigned long long new)
+@@ -490,11 +577,16 @@ static inline unsigned long long __cmpxchg64(volatile void *ptr,
+ 	do {
+ 		asm volatile(
+ 		"	@ __cmpxchg8\n"
+-		"	ldrexd	%1, %H1, [%2]\n"
++		"	ldc	p13, c0, [%2], {3}	@ set address for ldrexd\n"
++		"	mrc	p13, 0, %1, c0, c0, 0	@ ldrexd\n"
++		"	mrc	p13, 0, %H1, c0, c0, 1	@ ldrexd\n"
+ 		"	mov	%0, #0\n"
+ 		"	teq	%1, %3\n"
+ 		"	teqeq	%H1, %H3\n"
+-		"	strexdeq %0, %4, %H4, [%2]\n"
++		"	mcreq	p13, 0, %4, c0, c0, 0	@ data for strexd\n"
++		"	mcreq	p13, 0, %H4, c0, c0, 1	@ data for strexd\n"
++		"	stceq	p13, c0, [%2], {3}	@ strexd to address\n"
++		"	mrceq	p13, 0, %0, c0, c0, 2	@ strexd status\n"
+ 			: "=&r" (res), "=&r" (oldval)
+ 			: "r" (ptr), "Ir" (__old), "r" (__new)
+ 			: "memory", "cc");
+@@ -503,32 +595,20 @@ static inline unsigned long long __cmpxchg64(volatile void *ptr,
+ 	return oldval;
+ }
+ 
+-static inline unsigned long long __cmpxchg64_mb(volatile void *ptr,
+-						unsigned long long old,
+-						unsigned long long new)
+-{
+-	unsigned long long ret;
+-
+-	smp_mb();
+-	ret = __cmpxchg64(ptr, old, new);
+-	smp_mb();
+-
+-	return ret;
+-}
+-
+-#define cmpxchg64(ptr,o,n)						\
+-	((__typeof__(*(ptr)))__cmpxchg64_mb((ptr),			\
+-					    (unsigned long long)(o),	\
+-					    (unsigned long long)(n)))
+-
+-#define cmpxchg64_local(ptr,o,n)					\
+-	((__typeof__(*(ptr)))__cmpxchg64((ptr),				\
+-					 (unsigned long long)(o),	\
+-					 (unsigned long long)(n)))
+-
+-#else /* min ARCH = ARMv6 */
+-
+-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
++#define cmpxchg64(ptr, o, n)                                           \
++       ((__typeof__(*(ptr)))atomic64_cmpxchg(container_of((ptr),       \
++                                               atomic64_t,             \
++                                               counter),               \
++                                             (unsigned long)(o),       \
++                                             (unsigned long)(n)))
++
++#define cmpxchg64_local(ptr, o, n)                                     \
++       ((__typeof__(*(ptr)))local64_cmpxchg(container_of((ptr),        \
++                                               local64_t,              \
++                                               a),                     \
++                                            (unsigned long)(o),        \
++                                            (unsigned long)(n)))
++#endif /* CONFIG_CPU_FMP626 */
+ 
+ #endif
+ 
+diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
+index d4c24d41..68388eb4 100644
+--- a/arch/arm/include/asm/thread_info.h
++++ b/arch/arm/include/asm/thread_info.h
+@@ -118,6 +118,13 @@ extern void iwmmxt_task_switch(struct thread_info *);
+ extern void vfp_sync_hwstate(struct thread_info *);
+ extern void vfp_flush_hwstate(struct thread_info *);
+ 
++struct user_vfp;
++struct user_vfp_exc;
++
++extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *,
++					   struct user_vfp_exc __user *);
++extern int vfp_restore_user_hwstate(struct user_vfp __user *,
++				    struct user_vfp_exc __user *);
+ #endif
+ 
+ /*
+@@ -146,6 +153,7 @@ extern void vfp_flush_hwstate(struct thread_info *);
+ #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
+ #define TIF_RESTORE_SIGMASK	20
+ #define TIF_SECCOMP		21
++#define TIF_SWITCH_MM		22	/* deferred switch_mm */
+ 
+ #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
+ #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
+diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
+index 60843eb0..d7cd09a3 100644
+--- a/arch/arm/include/asm/tls.h
++++ b/arch/arm/include/asm/tls.h
+@@ -7,6 +7,8 @@
+ 
+ 	.macro set_tls_v6k, tp, tmp1, tmp2
+ 	mcr	p15, 0, \tp, c13, c0, 3		@ set TLS register
++	mov	\tmp1, #0
++	mcr	p15, 0, \tmp1, c13, c0, 2	@ clear user r/w TLS register
+ 	.endm
+ 
+ 	.macro set_tls_v6, tp, tmp1, tmp2
+@@ -15,6 +17,8 @@
+ 	mov	\tmp2, #0xffff0fff
+ 	tst	\tmp1, #HWCAP_TLS		@ hardware TLS available?
+ 	mcrne	p15, 0, \tp, c13, c0, 3		@ yes, set TLS register
++	movne	\tmp1, #0
++	mcrne	p15, 0, \tmp1, c13, c0, 2	@ clear user r/w TLS register
+ 	streq	\tp, [\tmp2, #-15]		@ set TLS value at 0xffff0ff0
+ 	.endm
+ 
+@@ -32,7 +36,7 @@
+ #define tls_emu		0
+ #define has_tls_reg		(elf_hwcap & HWCAP_TLS)
+ #define set_tls		set_tls_v6
+-#elif defined(CONFIG_CPU_32v6K)
++#elif defined(CONFIG_CPU_32v6K) || defined(CONFIG_CPU_FMP626)
+ #define tls_emu		0
+ #define has_tls_reg		1
+ #define set_tls		set_tls_v6k
+diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
+index 43b740d0..518cea4f 100644
+--- a/arch/arm/kernel/Makefile
++++ b/arch/arm/kernel/Makefile
+@@ -34,6 +34,7 @@ obj-$(CONFIG_HAVE_SCHED_CLOCK)	+= sched_clock.o
+ obj-$(CONFIG_SMP)		+= smp.o smp_tlb.o
+ obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
+ obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
++obj-$(CONFIG_ARM_ARCH_TIMER)	+= arch_timer.o
+ obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
+ obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o
+ obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
+new file mode 100644
+index 00000000..30db0293
+--- /dev/null
++++ b/arch/arm/kernel/arch_timer.c
+@@ -0,0 +1,372 @@
++/*
++ *  linux/arch/arm/kernel/arch_timer.c
++ *
++ *  Copyright (C) 2011 ARM Ltd.
++ *  All Rights Reserved
++ *
++ * 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 <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/smp.h>
++#include <linux/cpu.h>
++#include <linux/jiffies.h>
++#include <linux/clockchips.h>
++#include <linux/interrupt.h>
++#include <linux/of_irq.h>
++#include <linux/io.h>
++
++#include <asm/cputype.h>
++#include <asm/localtimer.h>
++#include <asm/arch_timer.h>
++#include <asm/sched_clock.h>
++
++static unsigned long arch_timer_rate;
++static int arch_timer_ppi;
++static int arch_timer_ppi2;
++
++static struct clock_event_device __percpu **arch_timer_evt;
++
++/*
++ * Architected system timer support.
++ */
++
++#define ARCH_TIMER_CTRL_ENABLE		(1 << 0)
++#define ARCH_TIMER_CTRL_IT_MASK		(1 << 1)
++#define ARCH_TIMER_CTRL_IT_STAT		(1 << 2)
++
++#define ARCH_TIMER_REG_CTRL		0
++#define ARCH_TIMER_REG_FREQ		1
++#define ARCH_TIMER_REG_TVAL		2
++
++static void arch_timer_reg_write(int reg, u32 val)
++{
++	switch (reg) {
++	case ARCH_TIMER_REG_CTRL:
++		asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
++		break;
++	case ARCH_TIMER_REG_TVAL:
++		asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
++		break;
++	}
++
++	isb();
++}
++
++static u32 arch_timer_reg_read(int reg)
++{
++	u32 val;
++
++	switch (reg) {
++	case ARCH_TIMER_REG_CTRL:
++		asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
++		break;
++	case ARCH_TIMER_REG_FREQ:
++		asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
++		break;
++	case ARCH_TIMER_REG_TVAL:
++		asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
++		break;
++	default:
++		BUG();
++	}
++
++	return val;
++}
++
++static irqreturn_t arch_timer_handler(int irq, void *dev_id)
++{
++	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
++	unsigned long ctrl;
++
++	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
++	if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
++		ctrl |= ARCH_TIMER_CTRL_IT_MASK;
++		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
++		evt->event_handler(evt);
++		return IRQ_HANDLED;
++	}
++
++	return IRQ_NONE;
++}
++
++static void arch_timer_disable(void)
++{
++	unsigned long ctrl;
++
++	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
++	ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
++	arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
++}
++
++static void arch_timer_set_mode(enum clock_event_mode mode,
++				struct clock_event_device *clk)
++{
++	switch (mode) {
++	case CLOCK_EVT_MODE_UNUSED:
++	case CLOCK_EVT_MODE_SHUTDOWN:
++		arch_timer_disable();
++		break;
++	default:
++		break;
++	}
++}
++
++static int arch_timer_set_next_event(unsigned long evt,
++				     struct clock_event_device *unused)
++{
++	unsigned long ctrl;
++
++	ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
++	ctrl |= ARCH_TIMER_CTRL_ENABLE;
++	ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
++
++	arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
++	arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
++
++	return 0;
++}
++
++static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
++{
++	/* Be safe... */
++	arch_timer_disable();
++
++	clk->features = CLOCK_EVT_FEAT_ONESHOT;
++	clk->name = "arch_sys_timer";
++	clk->rating = 450;
++	clk->set_mode = arch_timer_set_mode;
++	clk->set_next_event = arch_timer_set_next_event;
++	clk->irq = arch_timer_ppi;
++
++	clockevents_config_and_register(clk, arch_timer_rate,
++					0xf, 0x7fffffff);
++
++	*__this_cpu_ptr(arch_timer_evt) = clk;
++	printk("arch_timer_setup: irq = %d\n", clk->irq);
++	enable_percpu_irq(clk->irq, 0);
++	if (arch_timer_ppi2)
++		enable_percpu_irq(arch_timer_ppi2, 0);
++
++	return 0;
++}
++
++/* Is the optional system timer available? */
++static int local_timer_is_architected(void)
++{
++	return (cpu_architecture() >= CPU_ARCH_ARMv7) &&
++	       ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
++}
++
++static int arch_timer_available(void)
++{
++	unsigned long freq;
++
++	if (!local_timer_is_architected())
++		return -ENXIO;
++
++	if (arch_timer_rate == 0) {
++		arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0);
++		freq = arch_timer_reg_read(ARCH_TIMER_REG_FREQ);
++
++		/* Check the timer frequency. */
++		if (freq == 0) {
++			pr_warn("Architected timer frequency not available\n");
++			return -EINVAL;
++		}
++
++		arch_timer_rate = freq;
++	}
++
++	pr_info_once("Architected local timer running at %lu.%02luMHz.\n",
++		     arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100);
++	return 0;
++}
++
++static inline cycle_t arch_counter_get_cntpct(void)
++{
++	u32 cvall, cvalh;
++
++	asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
++
++	return ((cycle_t) cvalh << 32) | cvall;
++}
++
++static inline cycle_t arch_counter_get_cntvct(void)
++{
++	u32 cvall, cvalh;
++
++	asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
++
++	return ((cycle_t) cvalh << 32) | cvall;
++}
++
++static u32 notrace arch_counter_get_cntvct32(void)
++{
++	cycle_t cntvct = arch_counter_get_cntvct();
++
++	/*
++	 * The sched_clock infrastructure only knows about counters
++	 * with at most 32bits. Forget about the upper 24 bits for the
++	 * time being...
++	 */
++	return (u32)(cntvct & (u32)~0);
++}
++
++static cycle_t arch_counter_read(struct clocksource *cs)
++{
++	return arch_counter_get_cntpct();
++}
++
++static struct clocksource clocksource_counter = {
++	.name	= "arch_sys_counter",
++	.rating	= 400,
++	.read	= arch_counter_read,
++	.mask	= CLOCKSOURCE_MASK(56),
++	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
++};
++
++#ifdef CONFIG_FTTMR010
++static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
++{
++	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
++		 clk->irq, smp_processor_id());
++	disable_percpu_irq(clk->irq);
++	if (arch_timer_ppi2)
++		disable_percpu_irq(arch_timer_ppi2);
++	arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
++}
++
++static struct local_timer_ops arch_timer_ops __cpuinitdata = {
++	.setup	= arch_timer_setup,
++	.stop	= arch_timer_stop,
++};
++#endif
++
++static struct clock_event_device arch_timer_global_evt;
++
++static int __init arch_timer_common_register(void)
++{
++	int err;
++
++	err = arch_timer_available();
++	if (err)
++		return err;
++
++	arch_timer_evt = alloc_percpu(struct clock_event_device *);
++	if (!arch_timer_evt)
++		return -ENOMEM;
++
++	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
++
++	err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
++				 "arch_timer", arch_timer_evt);
++	if (err) {
++		pr_err("arch_timer: can't register interrupt %d (%d)\n",
++		       arch_timer_ppi, err);
++		goto out_free;
++	}else
++		printk("register interrupt %d\n", arch_timer_ppi);
++
++	if (arch_timer_ppi2) {
++		err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler,
++					 "arch_timer", arch_timer_evt);
++		if (err) {
++			pr_err("arch_timer: can't register interrupt %d (%d)\n",
++			       arch_timer_ppi2, err);
++			arch_timer_ppi2 = 0;
++			goto out_free_irq;
++		}else
++			printk("register interrupt %d\n", arch_timer_ppi2);
++	}
++#ifdef CONFIG_FTTMR010
++	err = local_timer_register(&arch_timer_ops);
++	if (err) {
++		/*
++		 * We couldn't register as a local timer (could be
++		 * because we're on a UP platform, or because some
++		 * other local timer is already present...). Try as a
++		 * global timer instead.
++		 */
++		arch_timer_global_evt.cpumask = cpumask_of(0);
++		err = arch_timer_setup(&arch_timer_global_evt);
++	}
++#else
++	arch_timer_global_evt.cpumask = cpumask_of(0);//cpu_all_mask;
++	err = arch_timer_setup(&arch_timer_global_evt);
++#endif
++
++	if (err)
++		goto out_free_irq;
++
++	return 0;
++
++out_free_irq:
++	free_percpu_irq(arch_timer_ppi, arch_timer_evt);
++	if (arch_timer_ppi2)
++		free_percpu_irq(arch_timer_ppi2, arch_timer_evt);
++
++out_free:
++	free_percpu(arch_timer_evt);
++
++	return err;
++}
++
++int __init arch_timer_register(struct arch_timer *at)
++{
++	if (at->res[0].start <= 0 || !(at->res[0].flags & IORESOURCE_IRQ))
++		return -EINVAL;
++
++	arch_timer_ppi = at->res[0].start;
++
++	if (at->res[1].start > 0 || (at->res[1].flags & IORESOURCE_IRQ))
++		arch_timer_ppi2 = at->res[1].start;
++
++	return arch_timer_common_register();
++}
++
++#ifdef CONFIG_OF
++static const struct of_device_id arch_timer_of_match[] __initconst = {
++	{ .compatible	= "arm,armv7-timer",	},
++	{},
++};
++
++int __init arch_timer_of_register(void)
++{
++	struct device_node *np;
++	u32 freq;
++
++	np = of_find_matching_node(NULL, arch_timer_of_match);
++	if (!np) {
++		pr_err("arch_timer: can't find DT node\n");
++		return -ENODEV;
++	}
++
++	/* Try to determine the frequency from the device tree or CNTFRQ */
++	if (!of_property_read_u32(np, "clock-frequency", &freq))
++		arch_timer_rate = freq;
++
++	arch_timer_ppi = irq_of_parse_and_map(np, 0);
++	arch_timer_ppi2 = irq_of_parse_and_map(np, 1);
++	pr_info("arch_timer: found %s irqs %d %d\n",
++		np->name, arch_timer_ppi, arch_timer_ppi2);
++
++	return arch_timer_common_register();
++}
++#endif
++
++int __init arch_timer_sched_clock_init(void)
++{
++	int err;
++
++	err = arch_timer_available();
++	if (err)
++		return err;
++
++	setup_sched_clock(arch_counter_get_cntvct32, 32, arch_timer_rate);
++	return 0;
++}
+diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
+index be16a480..499acb23 100644
+--- a/arch/arm/kernel/entry-armv.S
++++ b/arch/arm/kernel/entry-armv.S
+@@ -376,7 +376,7 @@ ENDPROC(__pabt_svc)
+ 	.endm
+ 
+ 	.macro	kuser_cmpxchg_check
+-#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
++#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_CPU_FMP626) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+ #ifndef CONFIG_MMU
+ #warning "NPTL on non MMU needs fixing"
+ #else
+@@ -755,6 +755,32 @@ ENDPROC(__switch_to)
+ 	.globl	__kuser_helper_start
+ __kuser_helper_start:
+ 
++#if defined(CONFIG_CPU_FMP626)
++/*
++ * This is the body of __kuser_cmpxchg for FMP626
++ */
++
++__kuser_cmpxchg_fmp626:
++#ifdef CONFIG_SMP
++	mcr	p15, 0, r0, c7, c10, 5	@ dmb
++#endif
++1:	ldc	p13, c0, [r2], {2}	@ set address for ldrex
++	mrc	p13, 0, r3, c0, c0, 0	@ ldrex
++	subs	r3, r3, r0
++	mcreq	p13, 0, r1, c0, c0, 0	@ data for strex
++	stceq	p13, c0, [r2], {2}	@ strex to address
++	mrceq	p13, 0, r3, c0, c0, 2	@ strex status
++	teqeq	r3, #1
++	beq	1b
++	rsbs	r0, r3, #0
++#ifdef CONFIG_SMP
++	mcr	p15, 0, r0, c7, c10, 5	@ dmb
++#endif
++	usr_ret	lr
++
++	.align	5
++#endif
++
+ /*
+  * Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular
+  * kuser "slots", therefore 0xffff0f80 is not used as a valid entry point.
+@@ -792,6 +818,28 @@ __kuser_cmpxchg64:				@ 0xffff0f60
+ 	ldmfd	sp!, {r4, r5, r6, r7}
+ 	usr_ret	lr
+ 
++#elif defined(CONFIG_CPU_FMP626)
++
++	stmfd	sp!, {r4, r5, r6, r7}
++	ldrd	r4, r5, [r0]			@ load old val
++	ldrd	r6, r7, [r1]			@ load new val
++	ALT_SMP(mcr	p15, 0, r0, c7, c10, 5)	@ dmb
++1:      ldc	p13, c0, [r2], {3}		@ set address for ldrex
++	mrc	p13, 0, r0, c0, c0, 0		@ ldrex 1st word
++	mrc	p13, 0, r1, c0, c0, 1		@ ldrex 2nd word
++	eors	r3, r0, r4			@ compare with oldval (1)
++	eoreqs	r3, r1, r5			@ compare with oldval (2)
++	mcreq	p13, 0, r6, c0, c0, 0		@ strex 1st word
++	mcreq	p13, 0, r7, c0, c0, 0		@ strex 2nd word
++	stceq   p13, c0, [r2], {3}		@ strex to address
++	mrceq   p13, 0, r3, c0, c0, 2		@ strex status
++	teqeq	r3, #1				@ success?
++	beq	1b				@ if no then retry
++	ALT_SMP(mcr	p15, 0, r0, c7, c10, 5)	@ dmb
++	rsbs	r0, r3, #0			@ set returned val and C flag
++	ldmfd	sp!, {r4, r5, r6, r7}
++	bx	lr
++
+ #elif !defined(CONFIG_SMP)
+ 
+ #ifdef CONFIG_MMU
+@@ -869,6 +917,14 @@ __kuser_cmpxchg:				@ 0xffff0fc0
+ 	ldmfd	sp!, {r7, pc}
+ 1:	.word	__ARM_NR_cmpxchg
+ 
++#elif defined(CONFIG_CPU_FMP626)
++	/*
++	 * Each __kuser slot must be 8 instructions max.
++	 * Our implementation blows it up.
++	 * So we put it at the beginning of all user helpers.
++	 */
++	b	__kuser_cmpxchg_fmp626
++
+ #elif __LINUX_ARM_ARCH__ < 6
+ 
+ #ifdef CONFIG_MMU
+diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
+index 9a8531ea..316395fd 100644
+--- a/arch/arm/kernel/entry-header.S
++++ b/arch/arm/kernel/entry-header.S
+@@ -83,6 +83,9 @@
+ #elif defined(CONFIG_CPU_32v6K)
+ 	clrex					@ clear the exclusive monitor
+ 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
++#elif defined(CONFIG_CPU_FMP626)
++	cdp	p13, 0, c0, c0, c0, 2		@ Clear exclusive monitor
++	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
+ #else
+ 	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
+ #endif
+@@ -96,6 +99,8 @@
+ 	strex	r1, r2, [sp]			@ clear the exclusive monitor
+ #elif defined(CONFIG_CPU_32v6K)
+ 	clrex					@ clear the exclusive monitor
++#elif defined(CONFIG_CPU_FMP626)
++	cdp	p13, 0, c0, c0, c0, 2		@ Clear exclusive monitor
+ #endif
+ 	.if	\fast
+ 	ldmdb	sp, {r1 - lr}^			@ get calling r1 - lr
+diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
+index 6d579114..1765ec08 100644
+--- a/arch/arm/kernel/head.S
++++ b/arch/arm/kernel/head.S
+@@ -107,6 +107,13 @@ ENTRY(stext)
+ 	blo	__error_p			@ only classic page table format
+ #endif
+ 
++#if defined(CONFIG_MMU) && defined(CONFIG_ARM_V7)
++	mrc	p15, 0, r3, c0, c1, 4		@ read ID_MMFR0
++	and	r3, r3, #0xf			@ extract VMSA support
++ THUMB( it	eq )				@ force fixup-able long branch encoding
++	beq	__error_p			@ We have CONFIG_MMU and no MMU, so fail
++#endif
++
+ #ifndef CONFIG_XIP_KERNEL
+ 	adr	r3, 2f
+ 	ldmia	r3, {r4, r8}
+diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
+index 3efd82cc..9d8f0f0a 100644
+--- a/arch/arm/kernel/irq.c
++++ b/arch/arm/kernel/irq.c
+@@ -74,6 +74,13 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
+ 
+ 	irq_enter();
+ 
++#ifdef	CONFIG_CPU_FA526_IDLE_FIXUP
++	/* If in SVC mode and *PC == mcr p15,0,r0,c7,c0,4 */
++	if ((processor_mode(regs) == SVC_MODE) &&
++	    *(unsigned *)(regs->ARM_pc) == 0xee070f90) {
++		regs->ARM_pc += 4;
++	}
++#endif
+ 	/*
+ 	 * Some hardware gives randomly wrong interrupts.  Rather
+ 	 * than crashing, do something sensible.
+@@ -156,10 +163,10 @@ static bool migrate_one_irq(struct irq_desc *desc)
+ 	}
+ 
+ 	c = irq_data_get_irq_chip(d);
+-	if (c->irq_set_affinity)
+-		c->irq_set_affinity(d, affinity, true);
+-	else
++	if (!c->irq_set_affinity)
+ 		pr_debug("IRQ%u: unable to set affinity\n", d->irq);
++	else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret)
++		cpumask_copy(d->affinity, affinity);
+ 
+ 	return ret;
+ }
+@@ -181,10 +188,7 @@ void migrate_irqs(void)
+ 	local_irq_save(flags);
+ 
+ 	for_each_irq_desc(i, desc) {
+-		bool affinity_broken = false;
+-
+-		if (!desc)
+-			continue;
++		bool affinity_broken;
+ 
+ 		raw_spin_lock(&desc->lock);
+ 		affinity_broken = migrate_one_irq(desc);
+diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
+index 764bd456..3baba638 100644
+--- a/arch/arm/kernel/machine_kexec.c
++++ b/arch/arm/kernel/machine_kexec.c
+@@ -7,6 +7,7 @@
+ #include <linux/delay.h>
+ #include <linux/reboot.h>
+ #include <linux/io.h>
++#include <linux/irq.h>
+ #include <asm/pgtable.h>
+ #include <asm/pgalloc.h>
+ #include <asm/mmu_context.h>
+@@ -53,6 +54,29 @@ void machine_crash_nonpanic_core(void *unused)
+ 		cpu_relax();
+ }
+ 
++static void machine_kexec_mask_interrupts(void)
++{
++	unsigned int i;
++	struct irq_desc *desc;
++
++	for_each_irq_desc(i, desc) {
++		struct irq_chip *chip;
++
++		chip = irq_desc_get_chip(desc);
++		if (!chip)
++			continue;
++
++		if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data))
++			chip->irq_eoi(&desc->irq_data);
++
++		if (chip->irq_mask)
++			chip->irq_mask(&desc->irq_data);
++
++		if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data))
++			chip->irq_disable(&desc->irq_data);
++	}
++}
++
+ void machine_crash_shutdown(struct pt_regs *regs)
+ {
+ 	unsigned long msecs;
+diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
+index b2abfa18..3e0e54a0 100644
+--- a/arch/arm/kernel/perf_event.c
++++ b/arch/arm/kernel/perf_event.c
+@@ -734,6 +734,9 @@ init_hw_perf_events(void)
+ 		case 0xC0F0:	/* Cortex-A15 */
+ 			cpu_pmu = armv7_a15_pmu_init();
+ 			break;
++		case 0xC070:	/* Cortex-A7 */
++			cpu_pmu = armv7_a7_pmu_init();
++			break;
+ 		}
+ 	/* Intel CPUs [xscale]. */
+ 	} else if (0x69 == implementor) {
+@@ -746,6 +749,15 @@ init_hw_perf_events(void)
+ 			cpu_pmu = xscale2pmu_init();
+ 			break;
+ 		}
++#if 0
++	/* Faraday CPUs [FMP626]. */
++	} else if (0x66 == implementor) {
++		switch (part_number) {
++		case 0x6260:	/* FMP626 */
++			cpu_pmu = fmp626_pmu_init();
++			break;
++		}
++#endif
+ 	}
+ 
+ 	if (cpu_pmu) {
+diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
+index b78af0cc..8ddd87f5 100644
+--- a/arch/arm/kernel/perf_event_v6.c
++++ b/arch/arm/kernel/perf_event_v6.c
+@@ -30,7 +30,7 @@
+  * enable the interrupt.
+  */
+ 
+-#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K)
++#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_FMP626)
+ enum armv6_perf_types {
+ 	ARMV6_PERFCTR_ICACHE_MISS	    = 0x0,
+ 	ARMV6_PERFCTR_IBUF_STALL	    = 0x1,
+@@ -706,6 +706,35 @@ static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+ {
+ 	return &armv6mpcore_pmu;
+ }
++
++/*
++ * FMP626 is almost identical to single core ARMv6 with the exception
++ * that some of the events have different enumerations and that there is no
++ * *hack* to stop the programmable counters. To stop the counters we simply
++ * disable the interrupt reporting and update the event. When unthrottling we
++ * reset the period and enable the interrupt reporting.
++ */
++static const struct arm_pmu fmp626_pmu = {
++	.id			= ARM_PERF_PMU_ID_FMP626,
++	.name			= "fmp626",
++	.handle_irq		= armv6pmu_handle_irq,
++	.enable			= armv6pmu_enable_event,
++	.disable		= armv6mpcore_pmu_disable_event,
++	.read_counter		= armv6pmu_read_counter,
++	.write_counter		= armv6pmu_write_counter,
++	.get_event_idx		= armv6pmu_get_event_idx,
++	.start			= armv6pmu_start,
++	.stop			= armv6pmu_stop,
++	.map_event		= armv6mpcore_map_event,
++	.num_events		= 3,
++	.max_period		= (1LLU << 32) - 1,
++};
++
++static const struct arm_pmu *__init fmp626_pmu_init(void)
++{
++	return &fmp626_pmu;
++}
++
+ #else
+ static struct arm_pmu *__init armv6pmu_init(void)
+ {
+diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
+index 4d7095af..00755d82 100644
+--- a/arch/arm/kernel/perf_event_v7.c
++++ b/arch/arm/kernel/perf_event_v7.c
+@@ -609,6 +609,130 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
+ 	},
+ };
+ 
++/*
++ * Cortex-A7 HW events mapping
++ */
++static const unsigned armv7_a7_perf_map[PERF_COUNT_HW_MAX] = {
++	[PERF_COUNT_HW_CPU_CYCLES]		= ARMV7_PERFCTR_CPU_CYCLES,
++	[PERF_COUNT_HW_INSTRUCTIONS]		= ARMV7_PERFCTR_INSTR_EXECUTED,
++	[PERF_COUNT_HW_CACHE_REFERENCES]	= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
++	[PERF_COUNT_HW_CACHE_MISSES]		= ARMV7_PERFCTR_L1_DCACHE_REFILL,
++	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= ARMV7_PERFCTR_PC_WRITE,
++	[PERF_COUNT_HW_BRANCH_MISSES]		= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
++	[PERF_COUNT_HW_BUS_CYCLES]		= ARMV7_PERFCTR_BUS_CYCLES,
++	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND]	= HW_OP_UNSUPPORTED,
++	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= HW_OP_UNSUPPORTED,
++};
++
++static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
++					[PERF_COUNT_HW_CACHE_OP_MAX]
++					[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
++	[C(L1D)] = {
++		/*
++		 * The performance counters don't differentiate between read
++		 * and write accesses/misses so this isn't strictly correct,
++		 * but it's the best we can do. Writes and reads get
++		 * combined.
++		 */
++		[C(OP_READ)] = {
++			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_DCACHE_REFILL,
++		},
++		[C(OP_WRITE)] = {
++			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_DCACHE_REFILL,
++		},
++		[C(OP_PREFETCH)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++	},
++	[C(L1I)] = {
++		[C(OP_READ)] = {
++			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_ICACHE_ACCESS,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_ICACHE_REFILL,
++		},
++		[C(OP_WRITE)] = {
++			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L1_ICACHE_ACCESS,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L1_ICACHE_REFILL,
++		},
++		[C(OP_PREFETCH)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++	},
++	[C(LL)] = {
++		[C(OP_READ)] = {
++			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L2_CACHE_ACCESS,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L2_CACHE_REFILL,
++		},
++		[C(OP_WRITE)] = {
++			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_L2_CACHE_ACCESS,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_L2_CACHE_REFILL,
++		},
++		[C(OP_PREFETCH)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++	},
++	[C(DTLB)] = {
++		[C(OP_READ)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_DTLB_REFILL,
++		},
++		[C(OP_WRITE)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_DTLB_REFILL,
++		},
++		[C(OP_PREFETCH)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++	},
++	[C(ITLB)] = {
++		[C(OP_READ)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_ITLB_REFILL,
++		},
++		[C(OP_WRITE)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_ITLB_REFILL,
++		},
++		[C(OP_PREFETCH)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++	},
++	[C(BPU)] = {
++		[C(OP_READ)] = {
++			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_PC_BRANCH_PRED,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
++		},
++		[C(OP_WRITE)] = {
++			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_PC_BRANCH_PRED,
++			[C(RESULT_MISS)]	= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
++		},
++		[C(OP_PREFETCH)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++	},
++	[C(NODE)] = {
++		[C(OP_READ)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++		[C(OP_WRITE)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++		[C(OP_PREFETCH)] = {
++			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
++			[C(RESULT_MISS)]	= CACHE_OP_UNSUPPORTED,
++		},
++	},
++};
++
+ /*
+  * Perf Events' indices
+  */
+@@ -1104,6 +1228,12 @@ static int armv7_a15_map_event(struct perf_event *event)
+ 				&armv7_a15_perf_cache_map, 0xFF);
+ }
+ 
++static int armv7_a7_map_event(struct perf_event *event)
++{
++	return map_cpu_event(event, &armv7_a7_perf_map,
++				&armv7_a7_perf_cache_map, 0xFF);
++}
++
+ static struct arm_pmu armv7pmu = {
+ 	.handle_irq		= armv7pmu_handle_irq,
+ 	.enable			= armv7pmu_enable_event,
+@@ -1164,6 +1294,16 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
+ 	armv7pmu.set_event_filter = armv7pmu_set_event_filter;
+ 	return &armv7pmu;
+ }
++
++static struct arm_pmu *__init armv7_a7_pmu_init(void)
++{
++	armv7pmu.id		= ARM_PERF_PMU_ID_CA7;
++	armv7pmu.name		= "ARMv7 Cortex-A7";
++	armv7pmu.map_event	= armv7_a7_map_event;
++	armv7pmu.num_events	= armv7_read_num_pmnc_events();
++	armv7pmu.set_event_filter = armv7pmu_set_event_filter;
++	return &armv7pmu;
++}
+ #else
+ static struct arm_pmu *__init armv7_a8_pmu_init(void)
+ {
+@@ -1184,4 +1324,9 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
+ {
+ 	return NULL;
+ }
++
++static struct arm_pmu *__init armv7_a7_pmu_init(void)
++{
++	return NULL;
++}
+ #endif	/* CONFIG_CPU_V7 */
+diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
+index 971d65c2..e11b523d 100644
+--- a/arch/arm/kernel/process.c
++++ b/arch/arm/kernel/process.c
+@@ -526,22 +526,40 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
+ #ifdef CONFIG_MMU
+ /*
+  * The vectors page is always readable from user space for the
+- * atomic helpers and the signal restart code.  Let's declare a mapping
+- * for it so it is visible through ptrace and /proc/<pid>/mem.
++ * atomic helpers and the signal restart code. Insert it into the
++ * gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
+  */
++static struct vm_area_struct gate_vma;
+ 
+-int vectors_user_mapping(void)
++static int __init gate_vma_init(void)
+ {
+-	struct mm_struct *mm = current->mm;
+-	return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
+-				       VM_READ | VM_EXEC |
+-				       VM_MAYREAD | VM_MAYEXEC |
+-				       VM_ALWAYSDUMP | VM_RESERVED,
+-				       NULL);
++	gate_vma.vm_start	= 0xffff0000;
++	gate_vma.vm_end		= 0xffff0000 + PAGE_SIZE;
++	gate_vma.vm_page_prot	= PAGE_READONLY_EXEC;
++	gate_vma.vm_flags	= VM_READ | VM_EXEC |
++				  VM_MAYREAD | VM_MAYEXEC |
++				  VM_ALWAYSDUMP;
++	return 0;
++}
++arch_initcall(gate_vma_init);
++
++struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
++{
++	return &gate_vma;
++}
++
++int in_gate_area(struct mm_struct *mm, unsigned long addr)
++{
++	return (addr >= gate_vma.vm_start) && (addr < gate_vma.vm_end);
++}
++
++int in_gate_area_no_mm(unsigned long addr)
++{
++	return in_gate_area(NULL, addr);
+ }
+ 
+ const char *arch_vma_name(struct vm_area_struct *vma)
+ {
+-	return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;
++	return (vma == &gate_vma) ? "[vectors]" : NULL;
+ }
+ #endif
+diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
+index ede6443c..4fe2d598 100644
+--- a/arch/arm/kernel/ptrace.c
++++ b/arch/arm/kernel/ptrace.c
+@@ -257,7 +257,7 @@ static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
+ {
+ 	unsigned long tmp;
+ 
+-	if (off & 3 || off >= sizeof(struct user))
++	if (off & 3)
+ 		return -EIO;
+ 
+ 	tmp = 0;
+@@ -269,6 +269,8 @@ static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
+ 		tmp = tsk->mm->end_code;
+ 	else if (off < sizeof(struct pt_regs))
+ 		tmp = get_user_reg(tsk, off >> 2);
++	else if (off >= sizeof(struct user))
++		return -EIO;
+ 
+ 	return put_user(tmp, ret);
+ }
+diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
+index a255c396..3ad1099b 100644
+--- a/arch/arm/kernel/setup.c
++++ b/arch/arm/kernel/setup.c
+@@ -223,8 +223,14 @@ static const char *proc_arch[] = {
+ 
+ static int __get_cpu_architecture(void)
+ {
+-	int cpu_arch;
+-
++    int cpu_arch;
++    
++    if (((read_cpuid_id() >> 4) & 0xFFF) == 0x726) {
++        return CPU_ARCH_ARMv5TE;
++    }
++    
++    /* other cpus, FA626 should be CPU_ARCH_ARMv5TE as well 
++     */
+ 	if ((read_cpuid_id() & 0x0008f000) == 0) {
+ 		cpu_arch = CPU_ARCH_UNKNOWN;
+ 	} else if ((read_cpuid_id() & 0x0008f000) == 0x00007000) {
+@@ -296,6 +302,25 @@ static int cpu_has_aliasing_icache(unsigned int arch)
+ 
+ static void __init cacheid_init(void)
+ {
++#ifdef CONFIG_PLATFORM_GM8210    
++    int cpu_id;
++    
++    cpu_id = (read_cpuid_id() >> 4) & 0xFFF;
++    if (cpu_id == 0x726) {
++        cacheid = CACHEID_VIPT_NONALIASING;
++        goto out;
++    }
++    if (cpu_id == 0x626) {
++        cacheid = CACHEID_VIPT_ALIASING;
++        goto out;
++    }
++#endif /* CONFIG_PLATFORM_GM8210 */
++        
++#if defined(CONFIG_CPU_FA626TE)
++	cacheid = CACHEID_VIPT_ALIASING | CACHEID_VIPT_I_ALIASING;
++#elif defined(CONFIG_CPU_FA726TE) || defined(CONFIG_CPU_FMP626)
++	cacheid = CACHEID_VIPT_NONALIASING | CACHEID_VIPT_I_ALIASING;
++#else
+ 	unsigned int cachetype = read_cpuid_cachetype();
+ 	unsigned int arch = cpu_architecture();
+ 
+@@ -324,8 +349,10 @@ static void __init cacheid_init(void)
+ 	} else {
+ 		cacheid = CACHEID_VIVT;
+ 	}
++#endif
+ 
+-	printk("CPU: %s data cache, %s instruction cache\n",
++out:
++	printk(KERN_INFO "CPU %s data cache, %s instruction cache\n",
+ 		cache_is_vivt() ? "VIVT" :
+ 		cache_is_vipt_aliasing() ? "VIPT aliasing" :
+ 		cache_is_vipt_nonaliasing() ? "PIPT / VIPT nonaliasing" : "unknown",
+@@ -472,7 +499,7 @@ static void __init setup_processor(void)
+ 	cpu_cache = *list->cache;
+ #endif
+ 
+-	printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
++	printk(KERN_INFO "CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
+ 	       cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
+ 	       proc_arch[cpu_architecture()], cr_alignment);
+ 
+@@ -521,7 +548,21 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size)
+ 	 */
+ 	size -= start & ~PAGE_MASK;
+ 	bank->start = PAGE_ALIGN(start);
+-	bank->size  = size & PAGE_MASK;
++
++#ifndef CONFIG_LPAE
++	if (bank->start + size < bank->start) {
++		printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
++			"32-bit physical address space\n", (long long)start);
++		/*
++		 * To ensure bank->start + bank->size is representable in
++		 * 32 bits, we use ULONG_MAX as the upper limit rather than 4GB.
++		 * This means we lose a page after masking.
++		 */
++		size = ULONG_MAX - bank->start;
++	}
++#endif
++
++	bank->size = size & PAGE_MASK;
+ 
+ 	/*
+ 	 * Check whether this memory region has non-zero size or
+@@ -865,7 +906,10 @@ static struct machine_desc * __init setup_machine_tags(unsigned int nr)
+ 	}
+ 
+ 	if (__atags_pointer)
+-		tags = phys_to_virt(__atags_pointer);
++		/* when transfer argument, bank[1] = 0 */	
++		//tags = phys_to_virt(__atags_pointer);
++        //fmem_phys_to_virt is not ready.....
++		tags = (struct tag *)(__atags_pointer - PHYS_OFFSET + PAGE_OFFSET);
+ 	else if (mdesc->atag_offset)
+ 		tags = (void *)(PAGE_OFFSET + mdesc->atag_offset);
+ 
+diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
+index 9e617bd4..b02ce1da 100644
+--- a/arch/arm/kernel/signal.c
++++ b/arch/arm/kernel/signal.c
+@@ -179,44 +179,23 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
+ 
+ static int preserve_vfp_context(struct vfp_sigframe __user *frame)
+ {
+-	struct thread_info *thread = current_thread_info();
+-	struct vfp_hard_struct *h = &thread->vfpstate.hard;
+ 	const unsigned long magic = VFP_MAGIC;
+ 	const unsigned long size = VFP_STORAGE_SIZE;
+ 	int err = 0;
+ 
+-	vfp_sync_hwstate(thread);
+ 	__put_user_error(magic, &frame->magic, err);
+ 	__put_user_error(size, &frame->size, err);
+ 
+-	/*
+-	 * Copy the floating point registers. There can be unused
+-	 * registers see asm/hwcap.h for details.
+-	 */
+-	err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs,
+-			      sizeof(h->fpregs));
+-	/*
+-	 * Copy the status and control register.
+-	 */
+-	__put_user_error(h->fpscr, &frame->ufp.fpscr, err);
+-
+-	/*
+-	 * Copy the exception registers.
+-	 */
+-	__put_user_error(h->fpexc, &frame->ufp_exc.fpexc, err);
+-	__put_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
+-	__put_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);
++	if (err)
++		return -EFAULT;
+ 
+-	return err ? -EFAULT : 0;
++	return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc);
+ }
+ 
+ static int restore_vfp_context(struct vfp_sigframe __user *frame)
+ {
+-	struct thread_info *thread = current_thread_info();
+-	struct vfp_hard_struct *h = &thread->vfpstate.hard;
+ 	unsigned long magic;
+ 	unsigned long size;
+-	unsigned long fpexc;
+ 	int err = 0;
+ 
+ 	__get_user_error(magic, &frame->magic, err);
+@@ -227,33 +206,7 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame)
+ 	if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
+ 		return -EINVAL;
+ 
+-	vfp_flush_hwstate(thread);
+-
+-	/*
+-	 * Copy the floating point registers. There can be unused
+-	 * registers see asm/hwcap.h for details.
+-	 */
+-	err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs,
+-				sizeof(h->fpregs));
+-	/*
+-	 * Copy the status and control register.
+-	 */
+-	__get_user_error(h->fpscr, &frame->ufp.fpscr, err);
+-
+-	/*
+-	 * Sanitise and restore the exception registers.
+-	 */
+-	__get_user_error(fpexc, &frame->ufp_exc.fpexc, err);
+-	/* Ensure the VFP is enabled. */
+-	fpexc |= FPEXC_EN;
+-	/* Ensure FPINST2 is invalid and the exception flag is cleared. */
+-	fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
+-	h->fpexc = fpexc;
+-
+-	__get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
+-	__get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);
+-
+-	return err ? -EFAULT : 0;
++	return vfp_restore_user_hwstate(&frame->ufp, &frame->ufp_exc);
+ }
+ 
+ #endif
+diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
+index cdeb7275..3fcfe32e 100644
+--- a/arch/arm/kernel/smp.c
++++ b/arch/arm/kernel/smp.c
+@@ -246,6 +246,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
+ 	store_cpu_topology(cpuid);
+ }
+ 
++static void percpu_timer_setup(void);
++
+ /*
+  * This is the secondary CPU boot entry.  We're using this CPUs
+  * idle thread stack, but a set of temporary page tables.
+@@ -459,7 +461,23 @@ static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
+ 	clockevents_register_device(evt);
+ }
+ 
+-void __cpuinit percpu_timer_setup(void)
++static struct local_timer_ops *lt_ops;
++
++#ifdef CONFIG_LOCAL_TIMERS
++int local_timer_register(struct local_timer_ops *ops)
++{
++	if (!is_smp() || !setup_max_cpus)
++		return -ENXIO;
++
++	if (lt_ops)
++		return -EBUSY;
++
++	lt_ops = ops;
++	return 0;
++}
++#endif
++
++static void __cpuinit percpu_timer_setup(void)
+ {
+ 	unsigned int cpu = smp_processor_id();
+ 	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
+@@ -467,7 +485,7 @@ void __cpuinit percpu_timer_setup(void)
+ 	evt->cpumask = cpumask_of(cpu);
+ 	evt->broadcast = smp_timer_broadcast;
+ 
+-	if (local_timer_setup(evt))
++	if (!lt_ops || lt_ops->setup(evt))
+ 		broadcast_timer_setup(evt);
+ }
+ 
+@@ -482,7 +500,8 @@ static void percpu_timer_stop(void)
+ 	unsigned int cpu = smp_processor_id();
+ 	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
+ 
+-	local_timer_stop(evt);
++	if (lt_ops)
++		lt_ops->stop(evt);
+ }
+ #endif
+ 
+@@ -506,10 +525,6 @@ static void ipi_cpu_stop(unsigned int cpu)
+ 	local_fiq_disable();
+ 	local_irq_disable();
+ 
+-#ifdef CONFIG_HOTPLUG_CPU
+-	platform_cpu_kill(cpu);
+-#endif
+-
+ 	while (1)
+ 		cpu_relax();
+ }
+@@ -572,16 +587,25 @@ void smp_send_reschedule(int cpu)
+ 	smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
+ }
+ 
++#ifdef CONFIG_HOTPLUG_CPU
++static void smp_kill_cpus(cpumask_t *mask)
++{
++	unsigned int cpu;
++	for_each_cpu(cpu, mask)
++		platform_cpu_kill(cpu);
++}
++#else
++static void smp_kill_cpus(cpumask_t *mask) { }
++#endif
++
+ void smp_send_stop(void)
+ {
+ 	unsigned long timeout;
++	cpumask_t mask = cpu_online_map;
++	cpu_clear(smp_processor_id(), mask);
+ 
+-	if (num_online_cpus() > 1) {
+-		cpumask_t mask = cpu_online_map;
+-		cpu_clear(smp_processor_id(), mask);
+-
++	if (num_online_cpus() > 1)
+ 		smp_cross_call(&mask, IPI_CPU_STOP);
+-	}
+ 
+ 	/* Wait up to one second for other CPUs to stop */
+ 	timeout = USEC_PER_SEC;
+@@ -590,6 +614,8 @@ void smp_send_stop(void)
+ 
+ 	if (num_online_cpus() > 1)
+ 		pr_warning("SMP: failed to stop secondary CPUs\n");
++
++	smp_kill_cpus(&mask);
+ }
+ 
+ /*
+diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
+index 8f5dd796..b9f015e8 100644
+--- a/arch/arm/kernel/smp_scu.c
++++ b/arch/arm/kernel/smp_scu.c
+@@ -11,6 +11,7 @@
+ #include <linux/init.h>
+ #include <linux/io.h>
+ 
++#include <asm/smp_plat.h>
+ #include <asm/smp_scu.h>
+ #include <asm/cacheflush.h>
+ #include <asm/cputype.h>
+@@ -74,7 +75,7 @@ void scu_enable(void __iomem *scu_base)
+ int scu_power_mode(void __iomem *scu_base, unsigned int mode)
+ {
+ 	unsigned int val;
+-	int cpu = smp_processor_id();
++	int cpu = cpu_logical_map(smp_processor_id());
+ 
+ 	if (mode > 3 || mode == 1 || cpu > 3)
+ 		return -EINVAL;
+diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
+index 7a79b245..fef42b21 100644
+--- a/arch/arm/kernel/smp_twd.c
++++ b/arch/arm/kernel/smp_twd.c
+@@ -18,20 +18,23 @@
+ #include <linux/smp.h>
+ #include <linux/jiffies.h>
+ #include <linux/clockchips.h>
+-#include <linux/irq.h>
++#include <linux/interrupt.h>
+ #include <linux/io.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
+ 
+ #include <asm/smp_twd.h>
+ #include <asm/localtimer.h>
+ #include <asm/hardware/gic.h>
+ 
+ /* set up by the platform code */
+-void __iomem *twd_base;
++static void __iomem *twd_base;
+ 
+ static struct clk *twd_clk;
+ static unsigned long twd_timer_rate;
+ 
+ static struct clock_event_device __percpu **twd_evt;
++static int twd_ppi;
+ 
+ static void twd_set_mode(enum clock_event_mode mode,
+ 			struct clock_event_device *clk)
+@@ -77,7 +80,7 @@ static int twd_set_next_event(unsigned long evt,
+  * If a local timer interrupt has occurred, acknowledge and return 1.
+  * Otherwise, return 0.
+  */
+-int twd_timer_ack(void)
++static int twd_timer_ack(void)
+ {
+ 	if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
+ 		__raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
+@@ -87,7 +90,7 @@ int twd_timer_ack(void)
+ 	return 0;
+ }
+ 
+-void twd_timer_stop(struct clock_event_device *clk)
++static void twd_timer_stop(struct clock_event_device *clk)
+ {
+ 	twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+ 	disable_percpu_irq(clk->irq);
+@@ -222,28 +225,10 @@ static struct clk *twd_get_clock(void)
+ /*
+  * Setup the local clock events for a CPU.
+  */
+-void __cpuinit twd_timer_setup(struct clock_event_device *clk)
++static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
+ {
+ 	struct clock_event_device **this_cpu_clk;
+ 
+-	if (!twd_evt) {
+-		int err;
+-
+-		twd_evt = alloc_percpu(struct clock_event_device *);
+-		if (!twd_evt) {
+-			pr_err("twd: can't allocate memory\n");
+-			return;
+-		}
+-
+-		err = request_percpu_irq(clk->irq, twd_handler,
+-					 "twd", twd_evt);
+-		if (err) {
+-			pr_err("twd: can't register interrupt %d (%d)\n",
+-			       clk->irq, err);
+-			return;
+-		}
+-	}
+-
+ 	if (!twd_clk)
+ 		twd_clk = twd_get_clock();
+ 
+@@ -260,6 +245,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
+ 	clk->rating = 350;
+ 	clk->set_mode = twd_set_mode;
+ 	clk->set_next_event = twd_set_next_event;
++	clk->irq = twd_ppi;
+ 
+ 	this_cpu_clk = __this_cpu_ptr(twd_evt);
+ 	*this_cpu_clk = clk;
+@@ -267,4 +253,95 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
+ 	clockevents_config_and_register(clk, twd_timer_rate,
+ 					0xf, 0xffffffff);
+ 	enable_percpu_irq(clk->irq, 0);
++
++	return 0;
++}
++
++static struct local_timer_ops twd_lt_ops __cpuinitdata = {
++	.setup	= twd_timer_setup,
++	.stop	= twd_timer_stop,
++};
++
++static int __init twd_local_timer_common_register(void)
++{
++	int err;
++
++	twd_evt = alloc_percpu(struct clock_event_device *);
++	if (!twd_evt) {
++		err = -ENOMEM;
++		goto out_free;
++	}
++
++	err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
++	if (err) {
++		pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err);
++		goto out_free;
++	}
++
++	err = local_timer_register(&twd_lt_ops);
++	if (err)
++		goto out_irq;
++
++	return 0;
++
++out_irq:
++	free_percpu_irq(twd_ppi, twd_evt);
++out_free:
++	iounmap(twd_base);
++	twd_base = NULL;
++	free_percpu(twd_evt);
++
++	return err;
+ }
++
++int __init twd_local_timer_register(struct twd_local_timer *tlt)
++{
++	if (twd_base || twd_evt)
++		return -EBUSY;
++
++	twd_ppi	= tlt->res[1].start;
++
++	twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
++	if (!twd_base)
++		return -ENOMEM;
++
++	return twd_local_timer_common_register();
++}
++
++#ifdef CONFIG_OF
++const static struct of_device_id twd_of_match[] __initconst = {
++	{ .compatible = "arm,cortex-a9-twd-timer",	},
++	{ .compatible = "arm,cortex-a5-twd-timer",	},
++	{ .compatible = "arm,arm11mp-twd-timer",	},
++	{ },
++};
++
++void __init twd_local_timer_of_register(void)
++{
++	struct device_node *np;
++	int err;
++
++	np = of_find_matching_node(NULL, twd_of_match);
++	if (!np) {
++		err = -ENODEV;
++		goto out;
++	}
++
++	twd_ppi = irq_of_parse_and_map(np, 0);
++	if (!twd_ppi) {
++		err = -EINVAL;
++		goto out;
++	}
++
++	twd_base = of_iomap(np, 0);
++	if (!twd_base) {
++		err = -ENOMEM;
++		goto out;
++	}
++
++	err = twd_local_timer_common_register();
++
++out:
++	WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
++}
++#endif
+diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c
+index 1794cc3b..073601ed 100644
+--- a/arch/arm/kernel/suspend.c
++++ b/arch/arm/kernel/suspend.c
+@@ -10,28 +10,7 @@
+ extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
+ extern void cpu_resume_mmu(void);
+ 
+-/*
+- * This is called by __cpu_suspend() to save the state, and do whatever
+- * flushing is required to ensure that when the CPU goes to sleep we have
+- * the necessary data available when the caches are not searched.
+- */
+-void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
+-{
+-	*save_ptr = virt_to_phys(ptr);
+-
+-	/* This must correspond to the LDM in cpu_resume() assembly */
+-	*ptr++ = virt_to_phys(idmap_pgd);
+-	*ptr++ = sp;
+-	*ptr++ = virt_to_phys(cpu_do_resume);
+-
+-	cpu_do_suspend(ptr);
+-
+-	flush_cache_all();
+-	outer_clean_range(*save_ptr, *save_ptr + ptrsz);
+-	outer_clean_range(virt_to_phys(save_ptr),
+-			  virt_to_phys(save_ptr) + sizeof(*save_ptr));
+-}
+-
++#ifdef CONFIG_MMU
+ /*
+  * Hide the first two arguments to __cpu_suspend - these are an implementation
+  * detail which platform code shouldn't have to know about.
+@@ -58,3 +37,32 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+ 
+ 	return ret;
+ }
++#else
++int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
++{
++	return __cpu_suspend(arg, fn);
++}
++#define	idmap_pgd	NULL
++#endif
++
++/*
++ * This is called by __cpu_suspend() to save the state, and do whatever
++ * flushing is required to ensure that when the CPU goes to sleep we have
++ * the necessary data available when the caches are not searched.
++ */
++void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
++{
++	*save_ptr = virt_to_phys(ptr);
++
++	/* This must correspond to the LDM in cpu_resume() assembly */
++	*ptr++ = virt_to_phys(idmap_pgd);
++	*ptr++ = sp;
++	*ptr++ = virt_to_phys(cpu_do_resume);
++
++	cpu_do_suspend(ptr);
++
++	flush_cache_all();
++	outer_clean_range(*save_ptr, *save_ptr + ptrsz);
++	outer_clean_range(virt_to_phys(save_ptr),
++			  virt_to_phys(save_ptr) + sizeof(*save_ptr));
++}
+diff --git a/arch/arm/kernel/thumbee.c b/arch/arm/kernel/thumbee.c
+index 9cb7aaca..3471f63a 100644
+--- a/arch/arm/kernel/thumbee.c
++++ b/arch/arm/kernel/thumbee.c
+@@ -20,6 +20,7 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ 
++#include <asm/cputype.h>
+ #include <asm/thread_notify.h>
+ 
+ /*
+@@ -66,8 +67,7 @@ static int __init thumbee_init(void)
+ 	if (cpu_arch < CPU_ARCH_ARMv7)
+ 		return 0;
+ 
+-	/* processor feature register 0 */
+-	asm("mrc	p15, 0, %0, c0, c1, 0\n" : "=r" (pfr0));
++	pfr0 = read_cpuid_ext(CPUID_EXT_PFR0);
+ 	if ((pfr0 & 0x0000f000) != 0x00001000)
+ 		return 0;
+ 
+diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
+index f84dfe67..a31187b5 100644
+--- a/arch/arm/kernel/traps.c
++++ b/arch/arm/kernel/traps.c
+@@ -491,7 +491,9 @@ do_cache_op(unsigned long start, unsigned long end, int flags)
+ 		if (end > vma->vm_end)
+ 			end = vma->vm_end;
+ 
+-		flush_cache_user_range(vma, start, end);
++		up_read(&mm->mmap_sem);
++		flush_cache_user_range(start, end);
++		return;
+ 	}
+ 	up_read(&mm->mmap_sem);
+ }
+@@ -786,7 +788,7 @@ static void __init kuser_get_tls_init(unsigned long vectors)
+ 
+ void __init early_trap_init(void)
+ {
+-#if defined(CONFIG_CPU_USE_DOMAINS)
++#if defined(CONFIG_CPU_USE_DOMAINS) || !defined(CONFIG_MMU)
+ 	unsigned long vectors = CONFIG_VECTORS_BASE;
+ #else
+ 	unsigned long vectors = (unsigned long)vectors_page;
+@@ -819,6 +821,6 @@ void __init early_trap_init(void)
+ 	memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
+ 	       syscall_restart_code, sizeof(syscall_restart_code));
+ 
+-	flush_icache_range(vectors, vectors + PAGE_SIZE);
++	flush_icache_range(CONFIG_VECTORS_BASE, CONFIG_VECTORS_BASE+PAGE_SIZE);
+ 	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
+ }
+diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h
+index d6408d1e..0c1efe7f 100644
+--- a/arch/arm/lib/bitops.h
++++ b/arch/arm/lib/bitops.h
+@@ -43,6 +43,51 @@ UNWIND(	.fnstart	)
+ 	movne	r0, #1
+ 2:	bx	lr
+ UNWIND(	.fnend		)
++ENDPROC(\name		)
++	.endm
++#elif defined(CONFIG_CPU_FMP626)
++	.macro	bitop, name, instr
++ENTRY(	\name		)
++UNWIND(	.fnstart	)
++	mov	r2, #1
++	and	r3, r0, #7		@ Get bit offset
++	add	r1, r1, r0, lsr #3	@ Get byte offset
++	mov	r3, r2, lsl r3
++1:	ldc	p13, c0, [r1], {0}	@ set address for ldrexb
++	mrc	p13, 0, r2, c0, c0, 0	@ ldrexb
++	\instr	r2, r2, r3
++	mcr	p13, 0, r2, c0, c0, 0	@ data for strexb
++	stc	p13, c0, [r1], {0}	@ strexb to address
++	mrc	p13, 0, r0, c0, c0, 2	@ strexb status
++	cmp	r0, #0
++	bne	1b
++	mov	pc, lr
++UNWIND(	.fnend		)
++ENDPROC(\name		)
++	.endm
++
++	.macro	testop, name, instr, store
++ENTRY(	\name		)
++UNWIND(	.fnstart	)
++	and	r3, r0, #7		@ Get bit offset
++	mov	r2, #1
++	add	r1, r1, r0, lsr #3	@ Get byte offset
++	mov	r3, r2, lsl r3		@ create mask
++	smp_dmb
++1:	ldc	p13, c0, [r1], {0}	@ set address for ldrexb
++	mrc	p13, 0, r2, c0, c0, 0	@ ldrexb
++	ands	r0, r2, r3		@ save old value of bit
++	\instr	r2, r2, r3		@ toggle bit
++	mcr	p13, 0, r2, c0, c0, 0	@ data for strexb
++	stc	p13, c0, [r1], {0}	@ strexb to address
++	mrc	p13, 0, ip, c0, c0, 2	@ strexb status
++	smp_dmb
++	cmp	ip, #0
++	bne	1b
++	cmp	r0, #0
++	movne	r0, #1
++2:	mov	pc, lr
++UNWIND(	.fnend		)
+ ENDPROC(\name		)
+ 	.endm
+ #else
+diff --git a/arch/arm/mach-GM-Duo/Kconfig b/arch/arm/mach-GM-Duo/Kconfig
+new file mode 100644
+index 00000000..2373d51b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/Kconfig
+@@ -0,0 +1,52 @@
++#
++# arch/arm/mach-GM-Duo/Kconfig
++#
++
++#
++# GM Platform Types Selection
++#
++choice
++	prompt "Platform Selection"
++	default PLATFORM_GM8210
++	depends on ARCH_GM_DUO
++
++
++config PLATFORM_GM8210
++	bool "GM8210 series platform"
++	select USB_ARCH_HAS_EHCI if CONFIG_USB_SUPPORT
++    select FIQ
++    help
++      GM GM8210 is a platform based on GM's ARM9 compatible processor
++
++endchoice
++
++config FORCE_MAX_ZONEORDER
++    int
++    depends on ARCH_GM_DUO
++    default "12"
++
++config FTDMAC020
++    tristate "Supports DMAC020 controller"
++    select DMA_ENGINE
++    default y
++
++config FTDMAC030
++    tristate "Supports DMAC030 controller"
++    select DMA_ENGINE
++    depends on PLATFORM_AXIDMA
++    default y
++
++config FTAPBB020
++    tristate "Supports APB DMA"
++    select DMA_ENGINE
++    default n
++
++#
++# Platform dependent options
++#
++menu "GM Platform Options"
++    depends on ARCH_GM_DUO
++
++source "arch/arm/mach-GM-Duo/platform-GM8210/Kconfig"
++
++endmenu
+diff --git a/arch/arm/mach-GM-Duo/Makefile b/arch/arm/mach-GM-Duo/Makefile
+new file mode 100644
+index 00000000..4e525826
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/Makefile
+@@ -0,0 +1,39 @@
++#
++# Makefile for the linux kernel.
++
++# obj-y += xxx.o
++obj-y += ftpmu010.o fttmr010.o fmem.o dma_gm.o gm_jiffies.o
++obj-$(CONFIG_FTDMAC020) += ftdmac020.o
++obj-$(CONFIG_FTDMAC030) += ftdmac030.o
++obj-$(CONFIG_FTAPBB020) += ftapbb020.o
++
++obj-$(CONFIG_GM8312)   += ftintc010.o ftpmu010_pcie.o
++obj-$(CONFIG_PLATFORM_GM8210)   += ftintc030.o proc-fmem.o
++
++GM-platform-$(CONFIG_PLATFORM_GM8210)		:= platform-GM8210
++#
++# Default platform directory set to GM8210
++# TODO: Make this an error, should never happen unless the Kconfig or Makefile is wrong
++ifeq ($(GM-platform-y),)
++GM-platform-y := platform-GM8210-M
++endif
++PLATFORM_DIR   := $(GM-platform-y)
++
++core-y		+=  arch/arm/mach-GM-Duo/$(PLATFORM_DIR)/
++
++define create-platform-symlink
++	mkdir -p arch/arm/mach-GM-Duo/include/mach;					\
++	if [ -L $@ ]; then								\
++		platformlink=`readlink $@`;						\
++	fi;										\
++	if [ ! -e $@ ] || [ $$platformlink != $(PLATFORM_DIR) ]; then			\
++		touch arch/arm/mach-GM-Duo/include/mach/$(PLATFORM_DIR)/*;		\
++	fi;										\
++	echo '  SYMLINK $@ -> arch/arm/mach-GM-Duo/include/mach/$(PLATFORM_DIR)';	\
++	ln -fsn $(PLATFORM_DIR) $@;
++endef
++
++arch/arm/mach-GM-Duo/include/mach/platform: FORCE
++	$(Q)$(create-platform-symlink)
++
++prepare: arch/arm/mach-GM-Duo/include/mach/platform
+diff --git a/arch/arm/mach-GM-Duo/Makefile.boot b/arch/arm/mach-GM-Duo/Makefile.boot
+new file mode 100644
+index 00000000..14968f60
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/Makefile.boot
+@@ -0,0 +1,11 @@
++zreladdr_fa726-y := 0x01008000
++zreladdr_fa626-y := 0x10008000
++
++# previous fa726 define
++#zreladdr-y		:= 0x01008000
++#params_phys-y	:= 0x01000100
++#initrd_phys-y	:= 0x01900000
++# previous fa626 define
++#zreladdr-y		:= 0x10008000
++#params_phys-y	:= 0x10000100
++#initrd_phys-y	:= 0x10900000
+diff --git a/arch/arm/mach-GM-Duo/dma_gm.c b/arch/arm/mach-GM-Duo/dma_gm.c
+new file mode 100644
+index 00000000..4b0c10fa
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/dma_gm.c
+@@ -0,0 +1,259 @@
++/*
++ * GM DMA memory operation (MEM_TO_MEM)
++ *
++ * Copyright (C) 2012 Faraday Technology Corp.
++ *
++ * Author : Shuao-kai Li <easonli@faraday-tech.com>
++ *
++ * 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; version 2 of the License.
++ */
++#include <linux/dmaengine.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/dma-mapping.h>
++#include <linux/hardirq.h>
++#include <linux/export.h>
++#include <mach/ftapbb020.h>
++#include <mach/ftdmac020.h>
++#include <mach/ftdmac030.h>
++#include <mach/dma_gm.h>
++
++struct dma_gm {
++	struct dma_chan	*chan;
++	struct dma_async_tx_descriptor *desc;
++//	struct dma_slave_config slave; /* It's useless now */
++	enum dma_status dma_st;
++	dma_cap_mask_t mask;
++	dma_cookie_t cookie;
++	wait_queue_head_t dma_wait_queue;
++};
++
++#define err(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ##args)
++
++static void dma_callback(void *param)
++{
++	struct dma_gm *gm = (struct dma_gm *)param;
++	gm->dma_st = DMA_SUCCESS;
++#if 1/*don't use interruptible mode*/
++    wake_up(&gm->dma_wait_queue);
++#else    
++	wake_up_interruptible(&gm->dma_wait_queue);
++#endif
++}
++
++static void dma_wait(struct dma_gm *gm)
++{
++	int status;
++#if 1/*don't use interruptible mode*/
++    status = wait_event_timeout(gm->dma_wait_queue,
++                            gm->dma_st == DMA_SUCCESS,
++                            60 * HZ);
++#else
++	status = wait_event_interruptible_timeout(gm->dma_wait_queue,
++						gm->dma_st == DMA_SUCCESS,
++						60 * HZ);
++#endif
++	if (status == 0) {
++		err("Timeout in DMA\n");
++	}
++}
++
++int dma_memcpy(enum dma_kind style, dma_addr_t dest, dma_addr_t src, size_t len)
++{
++	struct dma_gm gm_chan;
++	int ret = 0, flag = 0;
++
++	if (in_interrupt())
++		panic("Fatal exception in interrupt");
++
++	memset(&gm_chan, 0, sizeof(gm_chan));
++	init_waitqueue_head(&gm_chan.dma_wait_queue);
++	dma_cap_zero(gm_chan.mask);
++	dma_cap_set(DMA_MEMCPY, gm_chan.mask);
++
++	switch (style) {
++#if defined(CONFIG_FTAPBB020)
++		case APB_DMA:
++		{
++			struct ftapbb020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.common.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			slave.common.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftapbb020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC020)
++		case AHB_DMA:
++		{
++			struct ftdmac020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.handshake = -1;
++
++			/* Use BUS 1 for shared cpu bus loading */
++			slave.src_sel = 1;
++			slave.dst_sel = 1;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC030)
++		case AXI_DMA:
++		{
++			struct ftdmac030_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.handshake = -1;
++
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac030_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++		default:
++			err("No such DMA bus\n");
++			return -ENXIO;
++		break;
++	}
++
++	/* filter fn has already set dma_slave_config. */
++	//dmaengine_slave_config(gm_chan.chan, &gm_chan.slave);
++
++	flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	gm_chan.desc = dmaengine_prep_dma_memcpy(gm_chan.chan, dest, src, len, flag);
++	if (!gm_chan.desc) {
++		err("Set DMA failed!!\n");
++		ret = -EIO;
++		goto fail;
++	}
++	gm_chan.cookie = dmaengine_submit(gm_chan.desc);
++	if (dma_submit_error(gm_chan.cookie)) {
++		err("DMA submit failed\n");
++		dmaengine_terminate_all(gm_chan.chan);
++		ret = -EIO;
++		goto fail;
++	}
++	gm_chan.desc->callback = dma_callback;
++	gm_chan.desc->callback_param = &gm_chan;
++	gm_chan.dma_st = DMA_IN_PROGRESS;
++	dma_async_issue_pending(gm_chan.chan);
++	dma_wait(&gm_chan);
++fail:
++	dma_release_channel(gm_chan.chan);
++	return ret;
++}
++EXPORT_SYMBOL(dma_memcpy);
++
++int dma_memset(enum dma_kind style, dma_addr_t dest, int value, size_t len)
++{
++	struct dma_gm gm_chan;
++	int ret = 0, flag = 0;
++
++	if (in_interrupt())
++		panic("Fatal exception in interrupt");
++
++	memset(&gm_chan, 0, sizeof(gm_chan));
++	init_waitqueue_head(&gm_chan.dma_wait_queue);
++	dma_cap_zero(gm_chan.mask);
++	dma_cap_set(DMA_MEMSET, gm_chan.mask);
++
++	switch (style) {
++#if defined(CONFIG_FTAPBB020)
++		case APB_DMA:
++		{
++			struct ftapbb020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.common.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			slave.common.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftapbb020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC020)
++		case AHB_DMA:
++		{
++			struct ftdmac020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.handshake = -1;
++
++			/* Use BUS 1 for shared cpu bus loading */
++			slave.src_sel = 1;
++			slave.dst_sel = 1;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC030)
++		case AXI_DMA:
++		{
++			struct ftdmac030_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.handshake = -1;
++
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac030_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++		default:
++			err("No such DMA bus\n");
++			return -ENXIO;
++		break;
++	}
++
++	/* filter fn has already set dma_slave_config. */
++	//dmaengine_slave_config(gm_chan.chan, &gm_chan.slave);
++
++	flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	gm_chan.desc = dmaengine_prep_dma_memset(gm_chan.chan, dest, value, len, flag);
++	if (!gm_chan.desc) {
++		err("Set DMA failed!!\n");
++		ret = -EIO;
++		goto fail;
++	}
++
++	gm_chan.cookie = dmaengine_submit(gm_chan.desc);
++	if (dma_submit_error(gm_chan.cookie)) {
++		err("DMA submit failed\n");
++		dmaengine_terminate_all(gm_chan.chan);
++		ret = -EIO;
++		goto fail;
++	}
++
++	gm_chan.desc->callback = dma_callback;
++	gm_chan.desc->callback_param = &gm_chan;
++	gm_chan.dma_st = DMA_IN_PROGRESS;
++	dma_async_issue_pending(gm_chan.chan);
++	dma_wait(&gm_chan);
++fail:
++	dma_release_channel(gm_chan.chan);
++	return ret;
++}
++EXPORT_SYMBOL(dma_memset);
+diff --git a/arch/arm/mach-GM-Duo/fmem.c b/arch/arm/mach-GM-Duo/fmem.c
+new file mode 100644
+index 00000000..29623509
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/fmem.c
+@@ -0,0 +1,1264 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/sort.h>
++#include <linux/mmzone.h>
++#include <linux/memory.h>
++#include <linux/kallsyms.h>
++#include <linux/nodemask.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <asm/signal.h>
++#include <asm/cputype.h>
++#include <asm/setup.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include <asm/tlbflush.h>
++#include <asm/glue-cache.h>
++#include <asm/outercache.h>
++#include <linux/proc_fs.h>
++#include <linux/platform_device.h>
++#include <mach/fmem.h>
++#include <mach/platform/board.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++void debug_printk(const char *f, ...);
++static int __init sanity_check_memhole(u32 *base);
++
++/* MACROs defintion
++ */
++#define ALLOC_BSZ         SZ_8M
++#define POOL_LIST(x)      g_page_info.list[x]
++#define POOL_NODE_SZ(x)   g_page_info.node_sz[x]
++#define POOL_PHY_START(x) g_page_info.phy_start[x]
++#define MAX_PAGE_NUM      128 /* 1G bytes */
++#define CACHE_ALIGN_MASK  0x1F  //cache line with 32 bytes
++
++/*
++ * Local variables declaration
++ */
++static g_page_info_t    g_page_info;
++static struct meminfo mem_info, gmmem_info;
++u32 page_array[2][MAX_PAGE_NUM] __initdata;
++u32 reserve_blk_cnt[2] __initdata;
++u32 nonlinear_cpuaddr_flush = 0;
++u32 cpuaddr_flush = 0;
++u32 va_not_32align = 0, length_not_32align = 0;
++u32 debug_counter = 0;
++
++#define FA726_START_ADDR    0x1000000
++
++unsigned long phys_offset = FA726_START_ADDR;  //16M as the start address
++EXPORT_SYMBOL(phys_offset);
++
++#define DEBUG_WRONG_CACHE_API   0x0
++#define DEBUG_WRONG_CACHE_VA    0x1
++#define DEBUG_WRONG_CACHE_LEN   0x2
++
++/* proc function
++ */
++static struct proc_dir_entry *fmem_proc_root = NULL;
++static struct proc_dir_entry *resolve_proc = NULL;
++static struct proc_dir_entry *counter_proc = NULL;
++
++static int cpu_id = 0;
++
++#ifdef CONFIG_PLATFORM_GM8210
++/* pcie data abort */
++static int fmem_pcie_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
++{
++    static unsigned long last_fail_addr = 0, fail_cnt = 0;
++    u32 paddr = 0;
++
++    /* user mode return unhandled */
++    if ((regs->ARM_cpsr & 0xf) == 0)
++        return 1;
++
++    paddr = fmem_lookup_pa((u32)addr);
++    if (paddr == 0xFFFFFFFF)
++        return 1;
++
++    if (paddr >= 0xA0000000) {
++        if (last_fail_addr == addr) {
++            fail_cnt ++;
++        } else {
++            last_fail_addr = addr;
++            fail_cnt = 0;
++        }
++
++        /* fail to rescue */
++        if (fail_cnt >= 1000)
++            return 1;
++
++        printk("%s, vaddr:0x%x(paddr:0x%x), fsr:0x%x, external abort on non-linefetch! \n",
++                                                 __func__, (u32)addr, paddr, fsr);
++        return 0;
++    }
++
++    return 1;
++}
++#endif /* CONFIG_PLATFORM_GM8210 */
++
++static inline int __get_cpu_id(void)
++{
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++/* counter info
++ */
++static int proc_read_counter(char *page, char **start, off_t off, int count, int *eof,
++                                    void *data)
++{
++    int len = 0;
++
++    len += sprintf(page + len, "linear cpu_addr flush: %d \n", cpuaddr_flush);
++    len += sprintf(page + len, "non-linear cpu_addr flush: %d \n", nonlinear_cpuaddr_flush);
++    len += sprintf(page + len, "vaddr not cache alignment: %d \n", va_not_32align);
++    len += sprintf(page + len, "len not cache alignment: %d \n", length_not_32align);
++    len += sprintf(page + len, "debug_counter = 0x%x \n", debug_counter);
++
++    return len;
++}
++
++/* debug counter */
++int proc_write_debug_counter(struct file *file, const char *buffer, unsigned long count, void *data)
++{
++    unsigned char value[30];
++
++    if (copy_from_user(value, buffer, count))
++        return 0;
++
++    sscanf(value, "%x\n", &debug_counter);
++
++
++    printk("debug counter: 0x%x \n", debug_counter);
++
++    return count;
++}
++
++/* address resolve
++ */
++int proc_resolve_pa(struct file *file, const char *buffer, unsigned long count, void *data)
++{
++    unsigned char value[30];
++    unsigned int vaddr;
++    phys_addr_t  paddr;
++
++    if (copy_from_user(value, buffer, count))
++        return 0;
++
++    sscanf(value, "%x\n", &vaddr);
++    paddr = fmem_lookup_pa(vaddr);
++
++    printk("Resolve vaddr: 0x%x ---> paddr: 0x%x \n", vaddr, paddr);
++
++    return count;
++}
++
++void fmem_proc_init(void)
++{
++    struct proc_dir_entry *p;
++
++    p = create_proc_entry("fmem", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (p == NULL) {
++        printk("%s, fail! \n", __func__);
++        return;
++    }
++
++    fmem_proc_root = p;
++
++    /* resolve, va->pa
++     */
++    resolve_proc = create_proc_entry("resolve", S_IRUGO, fmem_proc_root);
++    if (resolve_proc == NULL)
++        panic("FMEM: Fail to create proc resolve_proc!\n");
++    resolve_proc->read_proc = NULL;
++    resolve_proc->write_proc = proc_resolve_pa;
++
++    /* counter
++     */
++    counter_proc = create_proc_entry("counter", S_IRUGO, fmem_proc_root);
++    if (counter_proc == NULL)
++        panic("FMEM: Fail to create proc counter_proc!\n");
++    counter_proc->read_proc = (read_proc_t *)proc_read_counter;
++    counter_proc->write_proc = proc_write_debug_counter;
++}
++
++/*
++ * PAGE Functions
++ */
++static int __init page_array_cmp(const void *_a, const void *_b)
++{
++    u32 data_a, data_b;
++	int cmp;
++
++	data_a = *(u32 *)_a;    /* the address of page */
++	data_b = *(u32 *)_b;
++
++	cmp = page_to_phys((struct page *)data_a) - page_to_phys((struct page *)data_b);
++
++	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
++}
++
++static int __init meminfo_cmp(const void *_a, const void *_b)
++{
++	const struct membank *a = _a, *b = _b;
++	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
++
++	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
++}
++
++/* Parse early memory
++ */
++static void __init parse_early_mem(char *p)
++{
++	unsigned long size, nr_bank;
++	phys_addr_t start;
++	char *endp;
++
++	start = PHYS_OFFSET;
++	size  = memparse(p, &endp);
++	if (*endp == '@')
++		start = memparse(endp + 1, NULL);
++
++    nr_bank = mem_info.nr_banks;
++    mem_info.bank[nr_bank].start = start;
++    mem_info.bank[nr_bank].size  = size;
++    mem_info.nr_banks ++;
++}
++
++/* Parse early GM memory
++ */
++static void __init parse_early_gmmem(char *p)
++{
++	unsigned long size, nr_bank;
++	char *endp;
++
++	size  = memparse(p, &endp);
++    nr_bank = gmmem_info.nr_banks;
++    gmmem_info.bank[nr_bank].size  = size;
++
++    gmmem_info.nr_banks ++;
++}
++
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++/* This function calculates the max MAX_PHYSMEM_BITS in memory.h
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required to address
++ * the last byte of memory.
++ */
++unsigned int fmem_max_physmem_bits(void)
++{
++    unsigned int max_physmem_bits;
++    unsigned long phyaddr;
++    int nr_banks;
++
++    nr_banks = mem_info.nr_banks;
++	phyaddr = bank_pfn_end(&mem_info.bank[nr_banks - 1]) << PAGE_SHIFT;
++
++	max_physmem_bits = get_order(phyaddr) + PAGE_SHIFT;
++
++
++    return max_physmem_bits;
++}
++#endif /* CONFIG_ARCH_SPARSEMEM_ENABLE */
++
++/* calculate how many blocks in the page array
++ */
++static int __init get_early_memblk_count(u32 *page_array)
++{
++    int i = 0;
++
++    do {
++        if (!page_array[i])
++            break;
++        i ++;
++    } while (1);
++
++    return i;
++}
++
++/* Purpose: to get whole pages from buddy system as possible for the 2nd DDR.
++ * This function is called early once the buddy system is ready.
++ */
++void __init fmem_early_init(void)
++{
++    struct page *page;
++    dma_addr_t  pfn;
++    int i, idx, order, size, ddr0_cnt;
++
++    memset(&reserve_blk_cnt[0], 0, sizeof(reserve_blk_cnt));
++
++    order = get_order(ALLOC_BSZ);
++
++    if (order > MAX_ORDER)
++        panic("%s, max order: %d, alloc order: %d \n", __func__, MAX_ORDER, order);
++
++    /* do nothing for single bank */
++    if (mem_info.nr_banks == 1)
++        goto ddr0_alloc;
++
++    idx = 1;
++    i = 0;
++    do {
++        /* allocate the first page and store all page pointer inside */
++        page = alloc_pages_node(1, GFP_ATOMIC, order);
++        if (!page)
++            panic("%s, get null page for ddr%d! \n", __func__, idx);
++
++        page_array[idx][i] = (u32)page;
++        /* check if the physical of the allocated page is smaller than the 2nd bank */
++        pfn = __phys_to_pfn(page_to_phys(page));
++        if (pfn < bank_pfn_start(&mem_info.bank[1])) {
++            page_array[idx][i] = 0x0;
++            __free_pages(page, order);
++            break;
++        }
++        /* keep page pointer */
++        page_array[idx][i] = (u32)page;
++
++        i ++;
++        if (i >= MAX_PAGE_NUM)
++            panic("%s, MAX_PAGE_NUM: %d is too small for ddr%d! \n", __func__, MAX_PAGE_NUM, idx);
++    } while (1);
++
++    //keep total blocks
++    reserve_blk_cnt[idx] = i;
++
++    /* sort the pages in ascendant order */
++    sort(page_array[idx], i, sizeof(u32), page_array_cmp, NULL);
++
++ddr0_alloc:
++    idx = 0;
++    /* allocate memory for node 0 */
++    size = gmmem_info.bank[0].size ? gmmem_info.bank[0].size : DDR0_FMEM_SIZE;
++    ddr0_cnt = (size + ALLOC_BSZ - 1) >> (order + PAGE_SHIFT);
++    //keep total blocks
++    reserve_blk_cnt[idx] = ddr0_cnt;
++
++    i = 0;
++    do {
++        page = alloc_pages_node(0, GFP_ATOMIC, order);
++        if (page == NULL) {
++            page_array[idx][i] = 0x0;
++            printk("%s, requested memory size: 0x%x is too large! \n", __func__, size);
++            break;
++        }
++
++        page_array[idx][i] = (u32)page;
++        i ++;
++        if (i >= MAX_PAGE_NUM)
++            panic("%s, MAX_PAGE_NUM: %d is too small for ddr%d! \n", __func__, MAX_PAGE_NUM, idx);
++    } while (-- ddr0_cnt);
++
++    /* sort the pages */
++    sort(page_array[idx], i, sizeof(u32), page_array_cmp, NULL);
++
++    return;
++}
++
++/*
++ * Parse the memory tag from command line
++ */
++void __init fmem_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    char key[] = "mem=", *from, *command_line = NULL;
++    struct tag  *t = tag;
++    char gm_key[] = "gmmem=";
++    int  i, tag_found = 0;
++
++    memset(&mem_info, 0, sizeof(mem_info));
++    memset(&gmmem_info, 0, sizeof(gmmem_info));
++
++    if (tag->hdr.tag == ATAG_CORE) {
++        for (; t->hdr.size; t = tag_next(t)) {
++            if (t->hdr.tag == ATAG_CMDLINE) {
++                command_line = &t->u.cmdline.cmdline[0];
++                from = command_line;
++                tag_found = 1;
++                break;
++            }
++        }
++    }
++
++    /* not found the boot argument parameters from UBOOT */
++    if (!tag_found) {
++        command_line = *cmdline;
++        from = *cmdline;
++    }
++
++    for (i = 0; i < strlen(command_line) - strlen(key); i ++) {
++        if (memcmp(from, key, strlen(key)) == 0) {
++			from += strlen(key);
++			parse_early_mem(from);
++		}
++		else if (memcmp(from, gm_key, strlen(gm_key)) == 0)	{
++		    from += strlen(gm_key);
++			parse_early_gmmem(from);
++		}
++		else
++			from ++;
++    }
++
++
++    sort(&mem_info.bank, mem_info.nr_banks, sizeof(mem_info.bank[0]), meminfo_cmp, NULL);
++}
++
++/*
++ * @brief get the page with largest physical address and the page with smallest physical address.
++ * @function void get_first_last_page(struct list_head *glist, page_node_t ** small_page,
++                         page_node_t ** large_page)
++ * @return None.
++ */
++void get_first_last_page(struct list_head *glist, page_node_t ** small_page,
++                         page_node_t ** large_page)
++{
++    struct list_head *list;
++    /* the list was sorted in ascendant sequence.
++     * Get the page node with the smallest physical address
++     */
++    list = glist->next;
++    *small_page = (page_node_t *)list_entry(list, page_node_t, list);
++    /* get the page node with the largest physical address */
++    list = glist->prev;
++    *large_page = (page_node_t *)list_entry(list, page_node_t, list);
++}
++
++/*
++ * @brief return the memory to the kernel from frammap
++ *
++ * @function int fmem_give_pages(int node_id, unsigned int give_sz)
++ * @param node_id is the real node id instead of chunk id
++ * @param node_id is the size you want to return to the kernel
++ * @return the real size that gives to the kernel
++ */
++int fmem_give_pages(int bank, unsigned int give_sz)
++{
++    unsigned int ret_sz, size, tmp_sz;
++    page_node_t *large_page, *small_page;
++    struct page *page;
++    u32 phyaddr;
++
++    if (give_sz == 0)
++        return 0;
++
++    ret_sz = 0;
++
++    do {
++        get_first_last_page(&POOL_LIST(bank), &small_page, &large_page);
++        size = (give_sz > large_page->size) ? large_page->size : give_sz;
++        tmp_sz = size;
++
++        /* calculate the last page. Because the page address is embedded in section. So
++         * I am not sure whether we can get the page address by shift.
++         */
++        phyaddr = page_to_phys(large_page->page) + large_page->size - PAGE_SIZE;
++
++        do {
++            page = phys_to_page(phyaddr);
++            ClearPageReserved(page);
++            __free_page(page);
++
++            /* No matter wether the page is freed, we need to decrease the page size
++             */
++            large_page->size -= PAGE_SIZE;
++            phyaddr -= PAGE_SIZE;
++        } while (tmp_sz -= PAGE_SIZE);
++
++        /* free memory */
++        if (!large_page->size) {
++            list_del(&large_page->list);
++            kfree(large_page);
++        }
++
++        give_sz -= size;
++        POOL_NODE_SZ(bank) -= size;
++        ret_sz += size;
++    } while (give_sz != 0);
++
++    return ret_sz;
++}
++EXPORT_SYMBOL(fmem_give_pages);
++
++/*
++ * @brief This function allocates ahead the memory in advance before fragementation happen
++ *
++ * @function int __init fmem_init(void)
++ * @param none
++ * @return none
++ */
++int __init fmem_init(void)
++{
++    int i, bank, order;
++    struct page *page;
++    page_node_t *page_node;
++    u32 mem_sz[2], size, phyaddr;
++    u32 phys_end;
++
++    if (phys_end)   {}
++    /* sanity check */
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        if (bank_phys_start(&mem_info.bank[bank]) & ((0x1 << SECTION_SIZE_BITS) - 1)) {
++            panic("%s, the start address 0x%x in bank%d is not aligned to section size: 0x%x! \n",
++                __func__, bank_phys_start(&mem_info.bank[bank]), bank, (0x1 << SECTION_SIZE_BITS));
++        }
++    }
++    bank = mem_info.nr_banks - 1;
++    phys_end = bank_phys_end(&mem_info.bank[bank]);
++    if ((get_order(phys_end) + PAGE_SHIFT) != MAX_PHYSMEM_BITS)
++        panic("%s, the memory end address is 0x%x, MAX_PHYSMEM_BITS should be %d(current: %d)! \n",
++            __func__, phys_end, get_order(phys_end) + PAGE_SHIFT, MAX_PHYSMEM_BITS);
++#endif
++
++    /* macro test */
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        phyaddr = bank_phys_start(&mem_info.bank[bank]);
++        if (phyaddr != (__virt_to_phys(__phys_to_virt(phyaddr))))
++            panic("%s, macro porting has bug! \n", __func__);
++    }
++
++    order = get_order(ALLOC_BSZ);
++
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        sanity_check_memhole(page_array[bank]);
++        /* count the active node */
++        g_page_info.nr_node++;
++
++        /*
++         * Note: The arguments from boot command line is higher than the MACRO defintion in memory.h.
++         */
++        mem_sz[bank] = gmmem_info.bank[bank].size ?
++                        gmmem_info.bank[bank].size : bank > 0 ? DDR1_FMEM_SIZE : DDR0_FMEM_SIZE;
++
++        /* update 2nd DDR information.
++         * If DDR1_FMEM_SIZE = -1 which means to allocate whole memory.
++         */
++        if ((bank > 0) && (DDR1_FMEM_SIZE == -1) && (mem_sz[bank] == DDR1_FMEM_SIZE))
++            mem_sz[bank] = get_early_memblk_count(page_array[bank]) * ALLOC_BSZ;
++    }
++
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        INIT_LIST_HEAD(&POOL_LIST(bank));
++        POOL_NODE_SZ(bank) = 0;
++
++        /* allocate page_node for each page
++         */
++        for (i = 0; i < reserve_blk_cnt[bank]; i++) {
++            page_node = (page_node_t *)kzalloc(sizeof(page_node_t), GFP_KERNEL);
++            if (page_node == NULL)
++                panic("%s: No memory for kmalloc! \n", __func__);
++            INIT_LIST_HEAD(&page_node->list);
++            page_node->page = (struct page *)page_array[bank][i];
++            page_node->phy_start = page_to_phys(page_node->page);
++            page_node->size = ALLOC_BSZ;
++
++            /* can't be swap out and mmap issue which can be mapped to reserved pages only */
++            page = page_node->page;
++            size = page_node->size;
++            phyaddr = page_node->phy_start;
++            do {
++                /* seperate the group pages into individual page and do the reservation prevent
++                 * those pages from being swapped out.
++                 */
++                init_page_count(page);
++                SetPageReserved(page);
++                phyaddr += PAGE_SIZE;
++                page = phys_to_page(phyaddr);
++            } while (size -= PAGE_SIZE);
++
++            POOL_NODE_SZ(bank) += page_node->size;
++
++            /* add to the global DDR list */
++            list_add_tail(&page_node->list, &POOL_LIST(bank));
++        }
++
++        /* free the rest memory */
++        if (reserve_blk_cnt[bank]) {
++            int ret;
++            u32 free_sz;
++
++            //record the start address of this pool
++            POOL_PHY_START(bank) = page_to_phys((struct page *)page_array[bank][0]);
++            free_sz = reserve_blk_cnt[bank] * ALLOC_BSZ - mem_sz[bank];
++            if (free_sz != 0) {
++                ret = fmem_give_pages(bank, free_sz);
++                if (ret != free_sz)
++                    panic("%s, bug in bank%d! \n", __func__, bank);
++            }
++            printk("FMEM: %d pages(0x%x bytes) from bank%d are reserved for Frammap. \n",
++                mem_sz[bank] >> PAGE_SHIFT, mem_sz[bank], bank);
++        }
++    }
++
++    printk("FMEM: Logical memory ends up at 0x%x, init_mm:0x%x(0x%x), PAGE_OFFSET:0x%x(phys:0x%x), \n",
++                (u32)high_memory, (u32)init_mm.pgd, (u32)__pa((void *)init_mm.pgd),
++                (u32)PAGE_OFFSET, (u32)__pa((void *)PAGE_OFFSET));
++
++    if (1) {
++        volatile unsigned int val;
++
++        int cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++        if (cpu_id == 0x726) {
++            __asm__ __volatile__ ("mrc p15, 0, %0, c15, c0, 0\t\n":"=r"(val));
++
++            printk("FMEM: FA726 Test and Debug Register: 0x%x \n", val);
++        }
++    }
++
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++    printk("FMEM: SECTION_SIZE_BITS: %d, MAX_PHYSMEM_BITS: %d \n", SECTION_SIZE_BITS, MAX_PHYSMEM_BITS);
++    if (MAX_PHYSMEM_BITS != fmem_max_physmem_bits())
++        panic("%s, the correct MAX_PHYSMEM_BITS(%d) should be changed to %d! \n", __func__,
++                MAX_PHYSMEM_BITS, fmem_max_physmem_bits());
++#endif
++
++    fmem_proc_init();
++
++#ifdef CONFIG_PLATFORM_GM8210
++    /* hook pcie function */
++    hook_fault_code(8, fmem_pcie_abort_handler, SIGBUS, 0, "external abort on non-linefetch");
++    hook_fault_code(10, fmem_pcie_abort_handler, SIGBUS, 0, "external abort on non-linefetch");
++    printk("Fmem hooks external data-abort handler. \n");
++#endif
++
++    return 0;
++}
++
++core_initcall(fmem_init);
++
++/*
++ * @brief check if the address contains holes
++ *
++ * @function static sanity_check_memhole
++ *
++ * @param base of the first page
++ * @return 0 on success, !0 on error
++ */
++static int __init sanity_check_memhole(u32 *base)
++{
++    struct page *page;
++    dma_addr_t phy_addr, next_phy_addr;
++    int i = 0;
++
++    /* get first page */
++    page = (struct page *)base[0];
++    phy_addr = page_to_phys(page);
++    next_phy_addr = phy_addr + ALLOC_BSZ;
++
++    do {
++        i ++;
++        page = (struct page *)base[i];
++        if (page == NULL)
++            break;
++
++        phy_addr = page_to_phys(page);
++        if (phy_addr != next_phy_addr) {
++            /* dump the content */
++            printk("%s, the expected physical is 0x%x, but get 0x%x \n", __func__, next_phy_addr,
++                    phy_addr);
++            panic("%s, physical address has holes! \n", __func__);
++        }
++        next_phy_addr = phy_addr + ALLOC_BSZ;
++    } while (1);
++
++    return 0;
++}
++
++/*
++ * @brief allocate the memory from linux kernel.
++ * @function void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id)
++ * @parameter size indicates the memory size going to allocate
++ * @parameter dma_handle indicates the physical address
++ * @parameter flags indicates type of this allocated memory is cachable or non-cacheable or ....
++ * @parameter ddr_id indicates which DDR the users want to allocate.
++ * @return virutal memory if success or NULL for fail.
++ */
++void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id)
++{
++    struct page *page;
++    void *cpu_addr = NULL;
++    struct page *end;
++
++    if (ddr_id >= mem_info.nr_banks)
++        return NULL;
++
++    size = PAGE_ALIGN(size);
++    if (size > ALLOC_BSZ) {
++        printk("The allocated memory size 0x%x exceeds 0x%x bytes! \n", size, ALLOC_BSZ);
++        return NULL;
++    }
++
++    page = alloc_pages_node(ddr_id, GFP_KERNEL, get_order(size));
++    if (!page) {
++        printk("alloc_pages fail! (requested %#x)", size);
++        goto no_page;
++    }
++
++    *dma_handle = page_to_phys(page);
++    if ((*dma_handle < bank_phys_start(&mem_info.bank[ddr_id])) ||
++            (*dma_handle > bank_phys_end(&mem_info.bank[ddr_id]))) {
++        __free_pages(page, get_order(size));
++        goto no_page;
++    }
++
++    if ((flags == PAGE_COPY) || (flags == PAGE_SHARED))
++        //cpu_addr = ioremap_cached(*dma_handle, size);
++        cpu_addr = __va(*dma_handle);
++    else if (flags == pgprot_writecombine(pgprot_kernel))
++        cpu_addr = ioremap_wc(*dma_handle, size);
++    else
++        cpu_addr = ioremap_nocache(*dma_handle, size);
++
++    if (cpu_addr) {
++        end = page + (1 << get_order(size));
++        do {
++            init_page_count(page);
++            SetPageReserved(page);
++            page++;
++            size -= PAGE_SIZE;
++        } while (size != 0);
++
++        /*
++         * Free the otherwise unused pages.
++         */
++        while (page < end) {
++            init_page_count(page);
++            if (!PageReserved(page) && put_page_testzero(page))
++                __free_page(page);
++            page++;
++        }
++    } else {
++        __free_pages(page, get_order(size));
++        printk("__ioremap fail! (phy %#x)", *dma_handle);
++    }
++
++  no_page:
++    return cpu_addr;
++}
++EXPORT_SYMBOL(fmem_alloc_ex);
++
++/*
++ * @brief free the memory which was allocated by fmem_alloc_ex().
++ * @function void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle)
++ * @parameter size indicates the memory size going to free
++ * @parameter cpu_addr indicates the virtual memory going to free
++ * @parameter handle indicates the physical memory going to free
++ * @return None.
++ */
++void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle)
++{
++    struct page *page = pfn_to_page(handle >> PAGE_SHIFT);
++    struct page *pg;
++    unsigned int sz;
++
++    pg = page;
++    sz = size;
++
++    if ((u32)__va(handle) != (u32)cpu_addr)
++        __iounmap(cpu_addr);
++
++    size = PAGE_ALIGN(size);
++
++    do {
++        ClearPageReserved(page);
++        if (!PageReserved(page) && put_page_testzero(page))
++            __free_page(page);
++        page++;
++    } while (size -= PAGE_SIZE);
++}
++EXPORT_SYMBOL(fmem_free_ex);
++
++/**
++ * @brief to resolve the virtual address (including direct mapping, ioremap or user space address to
++ *      its real physical address.
++ *
++ * @parm vaddr indicates any virtual address
++ *
++ * @return  >= 0 for success, 0xFFFFFFFF for fail
++ */
++phys_addr_t fmem_lookup_pa(unsigned int vaddr)
++{
++    pgd_t *pgdp;
++    pmd_t *pmdp;
++    pud_t *pudp;
++    pte_t *ptep;
++    phys_addr_t paddr = 0xFFFFFFFF;
++
++    /* for speed up */
++    if (virt_addr_valid(vaddr))
++        return (phys_addr_t)__pa(vaddr);
++
++    /*
++     * The pgd is never bad, and a pmd always exists(as it's folded into the pgd entry)
++     */
++    if (vaddr >= TASK_SIZE) /* use init_mm as mmu to look up in kernel mode */
++        pgdp = pgd_offset_k(vaddr);
++    else
++        pgdp = pgd_offset(current->mm, vaddr);
++
++    if (unlikely(pgd_none(*pgdp))) {
++        printk("fmem: 0x%x not mapped in pgd table! \n", vaddr);
++        goto err;
++    }
++
++    /* because we don't have 3-level MMU, so pud = pgd. Here we are in order to meet generic Linux
++     * version, pud is listed here.
++     */
++    pudp = pud_offset(pgdp, vaddr);
++    if (unlikely(pud_none(*pudp))) {
++        printk(KERN_INFO"fmem: 0x%x not mapped in pud table! \n", vaddr);
++        goto err;
++    }
++
++    pmdp = pmd_offset(pudp, vaddr);
++    if (unlikely(pmd_none(*pmdp))) {
++        printk(KERN_INFO"fmem: 0x%x not mapped in pmd 0x%x! \n", vaddr, (u32)pmdp);
++        goto err;
++    }
++
++    if (!pmd_bad(*pmdp)) {
++        u32 v_addr;
++
++        /* page mapping */
++        ptep = pte_offset_kernel(pmdp, vaddr);
++        if (pte_none(*ptep)) {
++            printk(KERN_ERR"fmem: 0x%x not mapped in pte! \n", vaddr);
++            goto err;
++        }
++
++        v_addr = (unsigned int)page_address(pte_page(*ptep)) + (vaddr & (PAGE_SIZE - 1));
++        paddr = __pa(v_addr);
++    } else {
++        /* section mapping. The cases are:
++         * 1. DDR direct mapping
++         * 2. ioremap's vaddr, size and paddr all are 2M alignment.
++         */
++        if (vaddr & SECTION_SIZE)
++            pmdp ++; /* move to pmd[1] */
++        paddr = (pmd_val(*pmdp) & SECTION_MASK) | (vaddr & ~SECTION_MASK);
++    }
++err:
++    return paddr;
++}
++EXPORT_SYMBOL(fmem_lookup_pa);
++
++/*
++ * @brief get the memory data information from frammap
++ *
++ * @function fmem_get_pageinfo(g_page_info_t **pg_info)
++ * @param pg_info is the pointer wants to be assigned the info
++ * @return none
++ */
++void fmem_get_pageinfo(g_page_info_t ** pg_info)
++{
++    *pg_info = &g_page_info;
++
++    return;
++}
++EXPORT_SYMBOL(fmem_get_pageinfo);
++
++/* __virt_to_phys macro porting arch/arm/include/mach/memory.h */
++unsigned long fmem_virt_to_phys(unsigned int vaddr)
++{
++    unsigned long phys;
++
++    if (phys_offset == FA726_START_ADDR) {
++        int cpu_id = __get_cpu_id();
++
++        if (cpu_id == 0x726)
++            phys_offset = FA726_PHYS_OFFSET;
++        else
++            phys_offset = FA626_PHYS_OFFSET;
++    }
++
++    if (mem_info.nr_banks == 0) {
++        phys = vaddr - PAGE_OFFSET + PHYS_OFFSET;
++
++        printk("%s, someone calls va2pa early............................. \n", __func__);
++
++        return phys;
++    }
++
++    if (mem_info.nr_banks == 1) {
++        phys = vaddr - PAGE_OFFSET + PHYS_OFFSET;
++    } else {
++        u32 end_vaddr;
++
++        end_vaddr = PAGE_OFFSET + bank_phys_size(&mem_info.bank[0]);
++        phys = vaddr >= end_vaddr ? (vaddr - end_vaddr) + bank_phys_start(&mem_info.bank[1]) :
++            (vaddr - PAGE_OFFSET) + bank_phys_start(&mem_info.bank[0]);
++    }
++
++    return phys;
++}
++
++/* __phys_to_virt macro porting in arch/arm/include/mach/memory.h */
++unsigned int fmem_phys_to_virt(unsigned long phys)
++{
++    u32 vaddr;
++
++    if (phys_offset == FA726_START_ADDR) {
++        int cpu_id = __get_cpu_id();
++
++        if (cpu_id == 0x726)
++            phys_offset = FA726_PHYS_OFFSET;
++        else
++            phys_offset = FA626_PHYS_OFFSET;
++    }
++
++    if (mem_info.nr_banks == 0) {
++         vaddr = phys - PHYS_OFFSET + PAGE_OFFSET;
++         printk("%s, someone calls pa2va early............................. \n", __func__);
++         return vaddr;
++    }
++
++    if (mem_info.nr_banks == 1) {
++        vaddr = phys - PHYS_OFFSET + PAGE_OFFSET;
++    } else {
++        vaddr = (phys >= bank_phys_start(&mem_info.bank[1])) ?
++            PAGE_OFFSET + bank_phys_size(&mem_info.bank[0]) + (phys - bank_phys_start(&mem_info.bank[1])) :
++            PAGE_OFFSET + (phys - PHYS_OFFSET);
++    }
++
++    return vaddr;
++}
++
++/*
++ * @This function is used to read CPU id and pci id
++ * @Return value: 0 for success, -1 for fail
++ */
++int fmem_get_identifier(fmem_pci_id_t *pci_id, fmem_cpu_id_t *cpu_id)
++{
++    int ret = 0;
++    u32 value;
++
++
++    /* Read CR0-0 Identification Code Register(ID)
++     * [31:24] IMP, [23:16]ARCH, [15:4] PART, [3:0] VER
++     */
++    __asm__ __volatile__ ("mrc p15, 0, %0, c0, c0, 0\t\n": "=r"(value));
++
++    switch ((value >> 0x4) & 0xFFF) {
++      case 0x626:
++        /* the code should be 0x66056261 */
++        *cpu_id = FMEM_CPU_FA626;
++        break;
++      case 0x726:
++        *cpu_id = FMEM_CPU_FA726;
++        break;
++      default:
++        *cpu_id = FMEM_CPU_UNKNOWN;
++        panic("Unknow cpu id: 0x%x \n", value);
++        break;
++    }
++
++    value = (ftpmu010_read_reg(0x04) >> 19) & 0x3;
++    /* 01: Endpoint, 10: RootPoint */
++    *pci_id = (value == 0x02) ? FMEM_PCI_HOST : FMEM_PCI_DEV0;
++
++    return ret;
++}
++EXPORT_SYMBOL(fmem_get_identifier);
++
++static void dev_release(struct device *dev) { return; }
++#define DRIVER_NAME "fmem_sync"
++static struct platform_device pseudo_dev = {
++	.name = DRIVER_NAME,
++	.id   = 0,
++	.num_resources = 0,
++	.dev  = {
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++		.release = dev_release,
++	}
++};
++
++/* process outer cache */
++static inline void __fmem_sync_outer_cache(void *vaddr, u32 len, enum dma_data_direction dir)
++{
++#ifdef CONFIG_OUTER_CACHE
++    phys_addr_t  paddr;
++
++    paddr = fmem_lookup_pa((unsigned int)vaddr);
++    if (paddr == 0xFFFFFFFF)
++        return;
++
++    switch (dir) {
++      case DMA_BIDIRECTIONAL:
++        outer_flush_range(paddr, paddr + len);
++        break;
++      case DMA_TO_DEVICE:
++        outer_clean_range(paddr, paddr + len);
++        break;
++      case DMA_FROM_DEVICE:
++        outer_inv_range(paddr, paddr + len);
++        break;
++      case DMA_NONE:
++        break;
++    }
++#endif
++}
++
++/* @this function is a data cache operation function,
++ * @parm: vaddr: any virtual address
++ * @parm: dir will be:
++ * DMA_BIDIRECTIONAL = 0, it means flush operation.
++ * DMA_TO_DEVICE = 1, it means clean operation.
++ * DMA_FROM_DEVICE = 2, it means invalidate operation.
++ * DMA_NONE = 3,
++ */
++void fmem_dcache_sync(void *vaddr, u32 len, enum dma_data_direction dir)
++{
++    struct device *dev = &pseudo_dev.dev;
++
++    if (!valid_dma_direction(dir))
++        panic("%s, invalid direction: %d \n", __func__, dir);
++
++    /* kernel buffer may not cache line alignment, it only can use both clean/inv
++     * for safe. Others we regard them as warning cases in coding.
++     */
++    if (dir != DMA_BIDIRECTIONAL) {
++        if ((u32)vaddr & CACHE_ALIGN_MASK) {
++            va_not_32align ++;
++            if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_VA)) {
++                printk("%s, warning, vaddr: 0x%x not cache alignment! \n", __func__, (u32)vaddr);
++                dump_stack();
++            }
++        }
++
++        if (len & CACHE_ALIGN_MASK) {
++            length_not_32align ++;
++            if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_LEN)) {
++                printk("%s, warning, len: %d not cache alignment! \n", __func__, len);
++                dump_stack();
++            }
++        }
++    }
++
++    if (virt_addr_valid(vaddr) && virt_addr_valid(vaddr + len - 1)) {
++        switch (dir) {
++          case DMA_BIDIRECTIONAL:
++            dma_map_single(dev, vaddr, len, DMA_BIDIRECTIONAL);
++            /* the purpose is for outer cache sync. dma_map_single() only did
++             * outer_clean_range() in arch/arm/mm/dma-mapping.c (#554), why?
++             */
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            //dma_unmap_single(dev, __pa(vaddr), len, DMA_FROM_DEVICE);
++            break;
++          case DMA_TO_DEVICE:
++            dma_map_single(dev, vaddr, len, DMA_TO_DEVICE);
++            /* outer cache will invoke clean function. */
++            break;
++          case DMA_FROM_DEVICE:
++            dma_map_single(dev, vaddr, len, DMA_FROM_DEVICE);
++            /* outer cache will invoke invalidate function. */
++            break;
++          case DMA_NONE:
++            break;
++        }
++        cpuaddr_flush ++;
++    } else {
++        switch (dir) {
++          case DMA_BIDIRECTIONAL:
++            dmac_flush_range(vaddr, vaddr + len);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_TO_DEVICE:
++            dmac_map_area(vaddr, len, DMA_TO_DEVICE);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_FROM_DEVICE:
++            dmac_map_area(vaddr, len, DMA_FROM_DEVICE);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_NONE:
++            break;
++        }
++        nonlinear_cpuaddr_flush ++;
++        if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_API)) {
++            printk("%s, warning, memory addr 0x%x not direct mapped! \n", __func__, (u32)vaddr);
++            dump_stack();
++        }
++    }
++}
++EXPORT_SYMBOL(fmem_dcache_sync);
++
++void CheckTxStatus(unsigned int port)
++{
++		// wait until Tx ready
++    while (!(*(volatile unsigned int *)(port + 0x14) & 0x20));
++      udelay(1);
++}
++
++static void _putchar(unsigned int base, char Ch)
++{
++    if(Ch != '\0'){
++        CheckTxStatus(base);
++        *(volatile unsigned int *)(base) = Ch;
++    }
++
++    if (Ch == '\n'){
++        CheckTxStatus(base);
++        *(volatile unsigned int *)(base) = '\r';
++    }
++}
++
++static int debug_init = 1;
++/* If we want to use this API, please enable arch/arm/kernel/head.S
++ * GM_CONSOLE_PRINT definition
++*/
++void debug_printk(const char *f, ...)
++{
++    volatile unsigned int i, uart_va_base, uart_pa_base;
++    va_list arg_ptr;
++    char buffer[256];
++
++    if (!debug_init) {
++        volatile unsigned int val, ttbr;
++        debug_init = 1;
++
++        __asm__ __volatile__ ("mrc p15, 0, %0, c2, c0, 0\t\n":"=r"(ttbr));
++
++        //ttbr = PAGE_OFFSET + (ttbr - PHYS_OFFSET);  //because the __va can't work at this moment (mem_info[] no data yet)
++        
++        if (__get_cpu_id() == 0x626) {
++            ttbr = PAGE_OFFSET + (ttbr - FA626_PHYS_OFFSET);
++            uart_va_base = UART_FTUART010_1_VA_BASE;
++            uart_pa_base = UART_FTUART010_1_PA_BASE;
++        } else {
++            ttbr = PAGE_OFFSET + (ttbr - FA726_PHYS_OFFSET);
++            uart_va_base = UART_FTUART010_0_VA_BASE;
++            uart_pa_base = UART_FTUART010_0_PA_BASE;
++        }
++   
++        val = *(u32 *)(ttbr + ((uart_va_base >> 20) << 2));
++        //uart temp mapping
++        if (!val) {
++            *(u32 *)(ttbr + ((uart_va_base >> 20) << 2)) = (uart_pa_base | 0xC12);
++
++            fmem_flush_kern_dcache_area((void *)(ttbr + ((uart_va_base >> 20) << 2)), PAGE_SIZE);
++            
++            //neet to flush dcache and tlb?
++            __asm__ __volatile__ ("mov r0, #0\n"
++                                  "mcr p15, 0, r0, c7, c10, 3\n"    /* Test and Clean DCache */
++                                  "mcr p15, 0, r0, c7, c10, 4\n"    /* drain WB */
++                                  "mcr p15, 0, r0, c8, c7, 0");	    /* invalidate TLB all */
++        }
++
++        va_start(arg_ptr, f);
++        vsprintf(&buffer[0], f, arg_ptr);
++        va_end(arg_ptr);
++    
++          //output the buffer
++        i = 0;
++        while (buffer[i]){
++              _putchar(uart_va_base, buffer[i]);
++              i++;
++        }
++    }
++}
++
++#define PCIE_WIN_SIZE   (128 << 20)
++#define PCIE_WIN_MASK   (~(PCIE_WIN_SIZE - 1))
++#define PCIE_WIN_BASE   0xE8000000
++static u32 ddr_win_base = 0, ddr_win_end = 0;
++
++/* @this function is used to set outbound window of EP
++ * @parm: phy_addr: start physical address
++ * @parm: size: window size
++ * return value: 0 for success, -1 for fail.
++ * Note: This function is only called in RC.
++ */
++int fmem_set_ep_outbound_win(u32 phy_addr, u32 size)
++{
++    static u32 remote_pcie_vbase = 0;
++    fmem_pci_id_t   pci_id;
++    fmem_cpu_id_t   cpu_id;
++
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (pci_id != FMEM_PCI_HOST)
++        return -1;  /* only RC can configure EP's BAR */
++
++    if (ftpmu010_get_attr(ATTR_TYPE_EPCNT) == 0)
++        return 0;
++
++    ddr_win_base = phy_addr & PCIE_WIN_MASK;
++    ddr_win_end = ddr_win_base + PCIE_WIN_SIZE;
++    if ((phy_addr + size) >= ddr_win_end) {
++        printk("%s, ddr_win_base: 0x%x, ddr_win_end: 0x%x  \n", __func__, ddr_win_base, ddr_win_end);
++        printk("input phy_addr: 0x%x, end: 0x%x is out of range! \n", phy_addr, phy_addr + size);
++        return -1;
++    }
++
++    if (!remote_pcie_vbase) {
++        u32 pcie_pbase = PCIE_PLDA_PA_BASE - 0x98000000 + 0xE0000000;
++
++        remote_pcie_vbase = (u32)ioremap_nocache(pcie_pbase, PAGE_SIZE);
++        if (!remote_pcie_vbase)
++            panic("%s fail! \n", __func__);
++    }
++
++    iowrite32(ddr_win_base, remote_pcie_vbase + 0xE8);
++
++    return 0;
++}
++EXPORT_SYMBOL(fmem_set_ep_outbound_win);
++
++/* @this function is used to translate local axi address to pcie address
++ * @parm: axi_phy_addr indicates local axi address
++ * return value: PCIe address. 0xFFFFFFFF if fail.
++ * Note: This function is only called in RC.
++ */
++u32 fmem_get_pcie_addr(u32 axi_phy_addr)
++{
++    fmem_pci_id_t   pci_id;
++    fmem_cpu_id_t   cpu_id;
++
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (pci_id != FMEM_PCI_HOST)
++        return 0xFFFFFFFF;
++
++    if ((axi_phy_addr < ddr_win_base) || (axi_phy_addr >= ddr_win_end))
++        return 0xFFFFFFFF;
++
++    return (axi_phy_addr - ddr_win_base) + PCIE_WIN_BASE;
++}
++EXPORT_SYMBOL(fmem_get_pcie_addr);
++
++/* @this function is used to translate pcie to local axi address
++ * @parm: pcie_phy_addr indicates pcie address
++ * return value: local axi address. 0xFFFFFFFF if fail.
++ * Note: This function is only called in RC.
++ */
++u32 fmem_get_axi_addr(u32 pcie_phy_addr)
++{
++    u32 axi_phy_addr;
++    fmem_pci_id_t   pci_id;
++    fmem_cpu_id_t   cpu_id;
++
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (pci_id != FMEM_PCI_HOST)
++        return 0xFFFFFFFF;
++
++    if (pcie_phy_addr < PCIE_WIN_BASE)
++        return 0xFFFFFFFF;
++
++    axi_phy_addr = (pcie_phy_addr - PCIE_WIN_BASE) + ddr_win_base;
++    if ((axi_phy_addr < ddr_win_base) || (axi_phy_addr >= ddr_win_end))
++        return 0xFFFFFFFF;
++
++    return axi_phy_addr;
++}
++EXPORT_SYMBOL(fmem_get_axi_addr);
++
++EXPORT_SYMBOL(debug_printk);
++EXPORT_SYMBOL(fmem_virt_to_phys);
++EXPORT_SYMBOL(fmem_phys_to_virt);
++
+diff --git a/arch/arm/mach-GM-Duo/ftapbb020.c b/arch/arm/mach-GM-Duo/ftapbb020.c
+new file mode 100644
+index 00000000..5f45716b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/ftapbb020.c
+@@ -0,0 +1,1473 @@
++/*
++ * Faraday FTAPBB020 DMA engine driver
++ *
++ * (C) Copyright 2010 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <asm/io.h>
++
++#include <mach/ftapbb020.h>
++
++#define CHANNEL_NR	4
++
++/*
++ * This value must be multiple of 32-bits to prevent from changing the
++ * alignment of child descriptors.
++ */
++#define MAX_CYCLE_PER_BLOCK		0x00800000
++#if (MAX_CYCLE_PER_BLOCK > FTAPBB020_CYC_MASK) || (MAX_CYCLE_PER_BLOCK & 0x3)
++#error invalid MAX_CYCLE_PER_BLOCK
++#endif
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 64;
++module_param(init_nr_desc_per_channel, uint, 0644);
++MODULE_PARM_DESC(init_nr_desc_per_channel,
++		 "initial descriptors per channel (default: 64)");
++
++/**
++ * struct ftapbb020_desc - async transaction descriptor.
++ * @txd: support for the async_tx api
++ * @node: node on the descriptors list
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @cmd: command register content
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @value: buf value for memset usage
++ * @len: length in bytes
++ */
++struct ftapbb020_desc {
++	struct dma_async_tx_descriptor txd;
++	struct list_head node;
++	struct list_head child_list;
++	struct ftapbb020_chan *ftchan;
++	unsigned int cmd;
++	dma_addr_t src;
++	dma_addr_t dst;
++	unsigned int cycle;
++	unsigned int value;
++	size_t len;
++};
++
++/**
++ * struct ftapbb020_chan - internal representation of an ftapbb020 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @pending_list: list of descriptors dmaengine which is wating to run
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftapbb020: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftapbb020_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head pending_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftapbb020 *ftapbb020;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++};
++
++/**
++ * struct ftapbb020 - internal representation of an ftapbb020 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @irq: irq number
++ * @channel: channel table
++ */
++struct ftapbb020 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	unsigned int irq;
++	struct ftapbb020_chan channel[CHANNEL_NR];
++};
++
++static const char *ftapbb020_name[] = {"ftapbb020_0", "ftapbb020_1", "ftapbb020_2"};
++static dma_cookie_t ftapbb020_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftapbb020_stop_channel(struct ftapbb020_chan *ftchan)
++{
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	iowrite32(0, base + FTAPBB020_OFFSET_CMD(chan_id));
++}
++
++static void ftapbb020_stop_all_channels(struct ftapbb020 *ftapbb020)
++{
++	void __iomem *base = ftapbb020->base;
++	int i;
++
++	for (i = 0; i < CHANNEL_NR; i++)
++		iowrite32(0, base + FTAPBB020_OFFSET_CMD(i));
++}
++
++static int ftapbb020_chan_is_enabled(struct ftapbb020_chan *ftchan)
++{
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++	unsigned int cmd;
++
++	cmd = ioread32(base + FTAPBB020_OFFSET_CMD(chan_id));
++	return cmd & FTAPBB020_CMD_ENABLE;
++}
++
++/**
++ * ftapbb020_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftapbb020_desc *ftapbb020_alloc_desc(struct ftapbb020_chan
++						   *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = kzalloc(sizeof(*desc), gfp_flags);
++	if (desc) {
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftapbb020_tx_submit;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftapbb020_free_desc(struct ftapbb020_desc *desc)
++{
++	struct dma_chan *chan = &desc->ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	kfree(desc);
++}
++
++/**
++ * ftapbb020_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftapbb020_desc *ftapbb020_desc_get(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc = NULL;
++
++	spin_lock_bh(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++					struct ftapbb020_desc, node);
++
++		list_del(&desc->node);
++	}
++	spin_unlock_bh(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftapbb020_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			spin_lock_bh(&ftchan->lock);
++			ftchan->descs_allocated++;
++			spin_unlock_bh(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftapbb020_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftapbb020_desc_put(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *child;
++
++	spin_lock_bh(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++static void ftapbb020_unmap_desc(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->dst, desc->len,
++					 DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->dst, desc->len,
++				       DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->src, desc->len,
++					 DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->src, desc->len,
++				       DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftapbb020_remove_chain(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *child;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->node, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftapbb020_unmap_desc(child);
++		ftapbb020_desc_put(child);
++	}
++
++	ftapbb020_unmap_desc(desc);
++	ftapbb020_desc_put(desc);
++}
++
++/**
++ * ftapbb020_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * @cmd: command register content
++ */
++static struct ftapbb020_desc *
++ftapbb020_create_chain(struct ftapbb020_chan *ftchan,
++			struct ftapbb020_desc *first,
++			dma_addr_t src,	dma_addr_t dest,
++			size_t len, unsigned int shift,
++			int fixed_src, int fixed_dest, unsigned int cmd)
++{
++	struct dma_chan *chan = &ftchan->common;
++	size_t offset;
++	unsigned int cycle;
++	bool is_memset = false;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, shift %d)\n",
++		__func__, src, dest, len, shift);
++
++	/* Check for memset */
++	if (cmd ==
++	    (FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB |
++	     FTAPBB020_CMD_SRC_MODE_FIXED | FTAPBB020_CMD_WIDTH_WORD |
++	     FTAPBB020_CMD_DST_MODE_WORD_INC)) {
++		is_memset = true;
++	}
++
++	if ((shift == 2 && ((src | dest | len) & 3)) ||
++	    (shift == 1 && ((src | dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	for (offset = 0; offset < len; offset += cycle << shift) {
++		struct ftapbb020_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> shift,
++			      MAX_CYCLE_PER_BLOCK);
++
++		cycle &= FTAPBB020_CYC_MASK;
++
++		desc = ftapbb020_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		if (is_memset) {
++			/* use fixed_dest as value */
++			desc->value = fixed_dest;
++			src = __pa(&(desc->value));
++		}
++
++		if (fixed_src)
++			desc->src = src;
++		else
++			desc->src = src + offset;
++
++		if (fixed_dest && !is_memset)
++			desc->dst = dest;
++		else
++			desc->dst = dest + offset;
++
++		desc->cmd = cmd;
++		desc->len = cycle << shift;
++		desc->cycle = cycle;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++	}
++
++	return first;
++err:
++	if (first)
++		ftapbb020_remove_chain(first);
++	return NULL;
++}
++
++static void ftapbb020_start_desc(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	unsigned int cmd = desc->cmd;
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	cmd |= FTAPBB020_CMD_ENABLE
++	    | FTAPBB020_CMD_FININT_E | FTAPBB020_CMD_ERRINT_E;
++
++	dev_dbg(chan2dev(chan), "\t[SAR %d] = %x\n", chan_id, desc->src);
++	iowrite32(desc->src, base + FTAPBB020_OFFSET_SAR(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DAR %d] = %x\n", chan_id, desc->dst);
++	iowrite32(desc->dst, base + FTAPBB020_OFFSET_DAR(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	iowrite32(desc->cycle, base + FTAPBB020_OFFSET_CYC(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CMD %d] = %x\n", chan_id, cmd);
++	iowrite32(cmd, base + FTAPBB020_OFFSET_CMD(chan_id));
++}
++
++static void ftapbb020_activate_chain(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	/* move new transfer chain to active list */
++	list_add_tail(&desc->node, &ftchan->active_list);
++	list_splice_tail_init(&desc->child_list, &ftchan->active_list);
++
++	/* start first descriptor */
++	ftapbb020_start_desc(desc);
++}
++
++static void ftapbb020_start_next_chain(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *new;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->pending_list))
++		return;
++
++	new = list_first_entry(&ftchan->pending_list, struct ftapbb020_desc,
++			       node);
++	list_del(&new->node);
++
++	ftapbb020_activate_chain(new);
++}
++
++static void ftapbb020_invoke_callback(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	ftchan->completed_cookie = desc->txd.cookie;
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback)
++		desc->txd.callback(desc->txd.callback_param);
++}
++
++static void ftapbb020_finish_all_pending_chains(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->pending_list, node) {
++		list_del(&desc->node);
++		ftapbb020_invoke_callback(desc);
++		ftapbb020_remove_chain(desc);
++	}
++}
++
++static void ftapbb020_finish_active_chain(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftapbb020_desc,
++				node);
++	/* first descriptor in the active list has callback fields */
++	ftapbb020_invoke_callback(desc);
++
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftapbb020_unmap_desc(desc);
++		ftapbb020_desc_put(desc);
++	}
++}
++
++static void ftapbb020_finish_all_chains(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftapbb020_finish_active_chain(ftchan);
++	ftapbb020_finish_all_pending_chains(ftchan);
++}
++
++static dma_cookie_t ftapbb020_new_cookie(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftapbb020_chan_filter(struct dma_chan * chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftapbb020_dma_slave *slave = data;
++	const char *ftapbb020_drv_name = *(ftapbb020_name + slave->id);
++
++	if (strncmp(ftapbb020_drv_name, drv_name, sizeof("ftapbb020_0"))) {
++		printk(KERN_DEBUG"driver name: %s wrong!\n", drv_name);
++		return false;
++	}
++
++	chan->private = slave;
++	return true;
++}
++
++EXPORT_SYMBOL_GPL(ftapbb020_chan_filter);
++
++/******************************************************************************
++ * tasklet - called after we finished one chunk
++ *****************************************************************************/
++static void ftapbb020_tasklet(unsigned long data)
++{
++	struct ftapbb020_chan *ftchan = (struct ftapbb020_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	BUG_ON(list_empty(&ftchan->active_list));
++
++	spin_lock_bh(&ftchan->lock);
++
++	/* remove already finished descriptor */
++	desc = list_first_entry(&ftchan->active_list, struct ftapbb020_desc,
++				node);
++	list_del(&desc->node);
++
++	if (list_empty(&ftchan->active_list)) {
++		ftapbb020_invoke_callback(desc);
++		ftapbb020_start_next_chain(ftchan);
++	} else {
++		struct ftapbb020_desc *next;
++
++		/* Do next descriptor in the trasnfer chain */
++		next = list_first_entry(&ftchan->active_list,
++					struct ftapbb020_desc, node);
++
++		/*
++		 * Always keep the txd fields in the first descriptor in the
++		 * active list.
++		 */
++		next->txd.cookie = desc->txd.cookie;
++		next->txd.flags = desc->txd.flags;
++		next->txd.callback = desc->txd.callback;
++		next->txd.callback_param = desc->txd.callback_param;
++
++		ftapbb020_start_desc(next);
++	}
++
++	ftapbb020_unmap_desc(desc);
++	spin_unlock_bh(&ftchan->lock);
++	ftapbb020_desc_put(desc);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftapbb020_interrupt(int irq, void *dev_id)
++{
++	struct ftapbb020 *ftapbb020 = dev_id;
++	struct device *dev = ftapbb020->dma.dev;
++	irqreturn_t ret = IRQ_NONE;
++	unsigned int sr;
++	int i;
++
++	sr = ioread32(ftapbb020->base + FTAPBB020_OFFSET_SR);
++	if (sr & FTAPBB020_SR_BWERRINT) {
++		dev_info(dev, "bufferable write error\n");
++		ret = IRQ_HANDLED;
++	}
++
++	/* clear SR */
++	iowrite32(sr, ftapbb020->base + FTAPBB020_OFFSET_SR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++		void __iomem *base = ftchan->ftapbb020->base;
++		int chan_id = ftchan->common.chan_id;
++		unsigned int cmd;
++
++		/*
++		 * status bits in command register?
++		 * what a brain-damaged design.
++		 */
++		cmd = ioread32(base + FTAPBB020_OFFSET_CMD(chan_id));
++
++		if (cmd & FTAPBB020_CMD_FININT_S) {
++			tasklet_schedule(&ftchan->tasklet);
++			ret = IRQ_HANDLED;
++		} else if (cmd & FTAPBB020_CMD_ERRINT_S) {
++			dev_err(chan2dev(chan), "error happened\n");
++			ret = IRQ_HANDLED;
++		}
++
++		if (cmd & (FTAPBB020_CMD_FININT_S | FTAPBB020_CMD_ERRINT_S)) {
++			/* clear interrupt status */
++			cmd &=
++			    ~(FTAPBB020_CMD_FININT_S | FTAPBB020_CMD_ERRINT_S);
++			iowrite32(cmd, base + FTAPBB020_OFFSET_CMD(chan_id));
++		}
++	}
++
++	return ret;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftapbb020_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftapbb020_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++
++	desc = container_of(txd, struct ftapbb020_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	spin_lock_bh(&ftchan->lock);
++
++	cookie = ftapbb020_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list)) {
++#if 0				/* Just add desc into active_list, not start doing tx */
++		ftapbb020_activate_chain(desc);
++#else
++		list_add_tail(&desc->node, &ftchan->active_list);
++		list_splice_tail_init(&desc->child_list, &ftchan->active_list);
++#endif
++	} else {
++		list_add_tail(&desc->node, &ftchan->pending_list);
++	}
++
++	spin_unlock_bh(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftapbb020_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftapbb020_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftapbb020_desc *desc;
++
++		desc = ftapbb020_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	spin_lock_bh(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list);
++	ftchan->completed_cookie = chan->cookie = 1;
++	spin_unlock_bh(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftapbb020_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftapbb020_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++	struct ftapbb020 *ftapbb020;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++	ftapbb020 = ftchan->ftapbb020;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(!list_empty(&ftchan->pending_list));
++	BUG_ON(ftapbb020_chan_is_enabled(ftchan));
++
++	spin_lock_bh(&ftchan->lock);
++	ftapbb020_stop_channel(ftchan);
++	ftapbb020_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftapbb020_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/**
++ * ftapbb020_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++			dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	unsigned int shift;
++	unsigned int cmd;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	/* Assume RAM is on AHB bus. */
++	cmd = FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB;
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++		cmd |= FTAPBB020_CMD_WIDTH_WORD
++		    | FTAPBB020_CMD_DST_MODE_WORD_INC
++		    | FTAPBB020_CMD_SRC_MODE_WORD_INC;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++		cmd |= FTAPBB020_CMD_WIDTH_HALF
++		    | FTAPBB020_CMD_DST_MODE_HALF_INC
++		    | FTAPBB020_CMD_SRC_MODE_HALF_INC;
++	} else {
++		shift = 0;
++		cmd |= FTAPBB020_CMD_WIDTH_BYTE
++		    | FTAPBB020_CMD_DST_MODE_BYTE_INC
++		    | FTAPBB020_CMD_SRC_MODE_BYTE_INC;
++	}
++
++	desc =
++	    ftapbb020_create_chain(ftchan, NULL, src, dest, len, shift, 0, 0,
++				   cmd);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	desc->cmd = cmd;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftapbb020_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @value: the given value for memset used
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest,
++			int value, size_t len, unsigned long flags)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	unsigned int shift;
++	unsigned int cmd;
++
++	dev_dbg(chan2dev(chan), "%s(dest %x, value %x, len %x)\n",
++		__func__, dest, value, len);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(len & 3)) {
++		dev_info(chan2dev(chan), "%s: length isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(dest & 3)) {
++		dev_info(chan2dev(chan), "%s: dest addr isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	/* Assume RAM is on AHB bus. */
++	cmd = FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB;
++
++	/* src address is from mem buf */
++	cmd |= FTAPBB020_CMD_SRC_MODE_FIXED;
++
++	/* dst address should be word align */
++	shift = 2;
++	cmd |= FTAPBB020_CMD_WIDTH_WORD | FTAPBB020_CMD_DST_MODE_WORD_INC;
++
++	desc =
++	    ftapbb020_create_chain(ftchan, NULL, 0, dest, len, shift, 1, value,
++				   cmd);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	desc->cmd = cmd;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftapbb020_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++			unsigned int sg_len,
++			enum dma_transfer_direction direction,
++			unsigned long flags)
++{
++	struct ftapbb020_dma_slave *slave = chan->private;
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int cmd;
++	unsigned int shift;
++	unsigned int i;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (direction) {
++	case DMA_MEM_TO_DEV:
++		cmd = FTAPBB020_CMD_DST_MODE_FIXED
++		    | FTAPBB020_CMD_DST_HANDSHAKE(slave->handshake);
++
++		/* Assume RAM is on AHB bus. */
++		cmd |= FTAPBB020_CMD_SRC_TYPE_AHB;
++
++		switch (slave->type) {
++		case FTAPBB020_BUS_TYPE_AHB:
++			cmd |= FTAPBB020_CMD_DST_TYPE_AHB;
++			break;
++		case FTAPBB020_BUS_TYPE_APB:
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect bus type\n",
++				__func__);
++			BUG();
++		}
++
++		switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			shift = 0;
++			cmd |= FTAPBB020_CMD_WIDTH_BYTE
++			    | FTAPBB020_CMD_SRC_MODE_BYTE_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			shift = 1;
++			cmd |= FTAPBB020_CMD_WIDTH_HALF
++			    | FTAPBB020_CMD_SRC_MODE_HALF_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			shift = 2;
++			cmd |= FTAPBB020_CMD_WIDTH_WORD
++			    | FTAPBB020_CMD_SRC_MODE_WORD_INC;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++				__func__);
++			BUG();
++		}
++
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftapbb020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftapbb020_create_chain(ftchan, desc,
++						     mem,
++						     slave->common.dst_addr,
++						     len, shift, 0, 1, cmd);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++		break;
++	case DMA_DEV_TO_MEM:
++		cmd = FTAPBB020_CMD_SRC_MODE_FIXED
++		    | FTAPBB020_CMD_SRC_HANDSHAKE(slave->handshake);
++
++		/* Assume RAM is on AHB bus. */
++		cmd |= FTAPBB020_CMD_DST_TYPE_AHB;
++
++		switch (slave->type) {
++		case FTAPBB020_BUS_TYPE_AHB:
++			cmd |= FTAPBB020_CMD_SRC_TYPE_AHB;
++			break;
++		case FTAPBB020_BUS_TYPE_APB:
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect bus type\n",
++				__func__);
++			BUG();
++		}
++
++		switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			shift = 0;
++			cmd |= FTAPBB020_CMD_WIDTH_BYTE
++			    | FTAPBB020_CMD_DST_MODE_BYTE_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			shift = 1;
++			cmd |= FTAPBB020_CMD_WIDTH_HALF
++			    | FTAPBB020_CMD_DST_MODE_HALF_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			shift = 2;
++			cmd |= FTAPBB020_CMD_WIDTH_WORD
++			    | FTAPBB020_CMD_DST_MODE_WORD_INC;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++				__func__);
++			BUG();
++		}
++
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftapbb020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftapbb020_create_chain(ftchan, desc,
++						     slave->common.src_addr,
++						     mem, len, shift, 1, 0,
++						     cmd);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n", __func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftapbb020_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++			     unsigned long arg)
++{
++	struct ftapbb020_chan *ftchan;
++	int ret = -ENXIO;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (cmd == DMA_SLAVE_CONFIG) {
++		struct dma_slave_config *slave_config = (struct dma_slave_config *)arg;
++		struct ftapbb020_dma_slave  *dma_slave;
++
++		dma_slave = container_of(slave_config, struct ftapbb020_dma_slave, common);
++		chan->private = dma_slave;
++		ret = 0;
++	} 
++
++	if (cmd == DMA_TERMINATE_ALL) {
++		/*
++		 * This is only called when something went wrong elsewhere, so
++		 * we don't really care about the data. Just disable the channel.
++		 */
++		spin_lock_bh(&ftchan->lock);
++		ftapbb020_stop_channel(ftchan);
++		ftapbb020_finish_all_chains(ftchan);
++		spin_unlock_bh(&ftchan->lock);
++	}
++
++	return ret;
++}
++
++/**
++ * ftapbb020_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftapbb020_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		    struct dma_tx_state *txstate)
++{
++	struct ftapbb020_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftapbb020_issue_pending - try to finish work
++ * @chan: target DMA channel
++ */
++static void ftapbb020_issue_pending(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (list_empty(&ftchan->active_list)) {
++		spin_lock_bh(&ftchan->lock);
++		ftapbb020_start_next_chain(ftchan);
++		spin_unlock_bh(&ftchan->lock);
++	} else {		/* Disable starting tx in tx_submit, start here */
++		desc =
++		    list_first_entry(&ftchan->active_list,
++				     struct ftapbb020_desc, node);
++		ftapbb020_start_desc(desc);
++	}
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftapbb020_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftapbb020 *ftapbb020;
++	struct dma_device *dma;
++	int irq;
++	int i;
++	int err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftapbb020 = kzalloc(sizeof(*ftapbb020), GFP_KERNEL);
++	if (!ftapbb020) {
++		return -ENOMEM;
++	}
++
++	dma = &ftapbb020->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftapbb020);
++
++	/* map io memory */
++
++	ftapbb020->res =
++	    request_mem_region(res->start, res->end - res->start + 1,
++			       dev_name(&pdev->dev));
++	if (ftapbb020->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftapbb020->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftapbb020->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* force dma off, just in case */
++	ftapbb020_stop_all_channels(ftapbb020);
++
++	/* initialize channels */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->pending_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device = dma;
++		ftchan->common.cookie = DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftapbb020 = ftapbb020;
++		ftchan->completed_cookie = DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftapbb020_tasklet,
++			     (unsigned long)ftchan);
++
++		list_add_tail(&ftchan->common.device_node, &dma->channels);
++	}
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftapbb020_alloc_chan_resources;
++	dma->device_free_chan_resources = ftapbb020_free_chan_resources;
++	dma->device_prep_dma_memcpy = ftapbb020_prep_dma_memcpy;
++	dma->device_prep_dma_memset = ftapbb020_prep_dma_memset;
++	dma->device_prep_slave_sg = ftapbb020_prep_slave_sg;
++	dma->device_control = ftapbb020_control;
++	dma->device_tx_status = ftapbb020_tx_status;
++	dma->device_issue_pending = ftapbb020_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
++	dma_cap_set(DMA_MEMSET, dma->cap_mask);
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);
++
++	err = request_irq(irq, ftapbb020_interrupt, IRQF_SHARED, pdev->name,
++			  ftapbb020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_irq;
++	}
++
++	ftapbb020->irq = irq;
++
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	dev_info(&pdev->dev, "DMA engine driver: irq %d, mapped at %p\n",
++		 irq, ftapbb020->base);
++
++	return 0;
++
++err_register:
++	free_irq(irq, ftapbb020);
++err_irq:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftapbb020->base);
++err_ioremap:
++	release_resource(ftapbb020->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftapbb020);
++	return err;
++}
++
++static int __exit ftapbb020_remove(struct platform_device *pdev)
++{
++	struct ftapbb020 *ftapbb020;
++	int i;
++
++	ftapbb020 = platform_get_drvdata(pdev);
++
++	dma_async_device_unregister(&ftapbb020->dma);
++
++	free_irq(ftapbb020->irq, ftapbb020);
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftapbb020->base);
++	release_resource(ftapbb020->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftapbb020);
++	return 0;
++}
++
++/*
++ * FTAPBB020
++ */
++static struct resource ftapbb020_0_resources[] = {
++	{
++		.start = APBB_FTAPBB020_0_PA_BASE,
++		.end = APBB_FTAPBB020_0_PA_LIMIT,
++		.flags = IORESOURCE_MEM,
++	}, 
++	{
++		.start = APBB_FTAPBB020_0_IRQ,
++		.end = APBB_FTAPBB020_0_IRQ,
++		.flags = IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftapbb020_0_device = {
++	.name = "ftapbb020_0",
++	.id = 0,
++	.dev = {
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.num_resources = ARRAY_SIZE(ftapbb020_0_resources),
++	.resource = ftapbb020_0_resources,
++};
++
++static struct platform_driver ftapbb020_0_driver = {
++	.probe = ftapbb020_probe,
++	.remove = __exit_p(ftapbb020_remove),
++	.driver = {
++		.name = "ftapbb020_0",
++		.owner = THIS_MODULE,
++	},
++};
++
++static struct resource ftapbb020_1_resources[] = {
++	{
++		.start = APBB_FTAPBB020_1_PA_BASE,
++		.end = APBB_FTAPBB020_1_PA_LIMIT,
++		.flags = IORESOURCE_MEM,
++	}, 
++	{
++		.start = APBB_FTAPBB020_1_IRQ,
++		.end = APBB_FTAPBB020_1_IRQ,
++		.flags = IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftapbb020_1_device = {
++	.name = "ftapbb020_1",
++	.id = 0,
++	.dev = {
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.num_resources = ARRAY_SIZE(ftapbb020_1_resources),
++	.resource = ftapbb020_1_resources,
++};
++
++static struct platform_driver ftapbb020_1_driver = {
++	.probe = ftapbb020_probe,
++	.remove = __exit_p(ftapbb020_remove),
++	.driver = {
++		.name = "ftapbb020_1",
++		.owner = THIS_MODULE,
++	},
++};
++
++static struct resource ftapbb020_2_resources[] = {
++	{
++		.start = APBB_FTAPBB020_2_PA_BASE,
++		.end = APBB_FTAPBB020_2_PA_LIMIT,
++		.flags = IORESOURCE_MEM,
++	}, 
++	{
++		.start = APBB_FTAPBB020_2_IRQ,
++		.end = APBB_FTAPBB020_2_IRQ,
++		.flags = IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftapbb020_2_device = {
++	.name = "ftapbb020_2",
++	.id = 0,
++	.dev = {
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++	},
++	.num_resources = ARRAY_SIZE(ftapbb020_2_resources),
++	.resource = ftapbb020_2_resources,
++};
++
++static struct platform_driver ftapbb020_2_driver = {
++	.probe = ftapbb020_probe,
++	.remove = __exit_p(ftapbb020_remove),
++	.driver = {
++		.name = "ftapbb020_2",
++		.owner = THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftapbb020_init(void)
++{
++	int ret = 0;
++
++	if ((ret = platform_device_register(&ftapbb020_0_device))) {
++		printk("failed to register FTAPBB020 device 0\n");
++		return ret;
++	}
++	if ((ret = platform_driver_register(&ftapbb020_0_driver))) {
++		printk("failed to register FTAPBB020 driver 0\n");
++		platform_device_unregister(&ftapbb020_0_device);
++		return ret;
++	}
++	if ((ret = platform_device_register(&ftapbb020_1_device))) {
++		printk("failed to register FTAPBB020 device 1\n");
++		platform_driver_unregister(&ftapbb020_0_driver);
++		platform_device_unregister(&ftapbb020_0_device);
++		return ret;
++	}
++	if ((ret = platform_driver_register(&ftapbb020_1_driver))) {
++		printk("failed to register FTAPBB020 driver 1\n");
++		platform_driver_unregister(&ftapbb020_0_driver);
++		platform_device_unregister(&ftapbb020_0_device);
++		platform_device_unregister(&ftapbb020_1_device);
++		return ret;
++	}
++	if ((ret = platform_device_register(&ftapbb020_2_device))) {
++		printk("failed to register FTAPBB020 device 2\n");
++		platform_driver_unregister(&ftapbb020_0_driver);
++		platform_device_unregister(&ftapbb020_0_device);
++		platform_driver_unregister(&ftapbb020_1_driver);
++		platform_device_unregister(&ftapbb020_1_device);
++		return ret;
++	}
++	if ((ret = platform_driver_register(&ftapbb020_2_driver))) {
++		printk("failed to register FTAPBB020 driver 2\n");
++		platform_driver_unregister(&ftapbb020_0_driver);
++		platform_device_unregister(&ftapbb020_0_device);
++		platform_driver_unregister(&ftapbb020_1_driver);
++		platform_device_unregister(&ftapbb020_1_device);
++		platform_device_unregister(&ftapbb020_2_device);
++		return ret;
++	}
++	return ret;
++}
++
++static void __exit ftapbb020_exit(void)
++{
++	platform_driver_unregister(&ftapbb020_0_driver);
++	platform_device_unregister(&ftapbb020_0_device);
++	platform_driver_unregister(&ftapbb020_1_driver);
++	platform_device_unregister(&ftapbb020_1_device);
++	platform_driver_unregister(&ftapbb020_2_driver);
++	platform_device_unregister(&ftapbb020_2_device);
++}
++
++module_init(ftapbb020_init);
++module_exit(ftapbb020_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTAPBB020 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-Duo/ftdmac020.c b/arch/arm/mach-GM-Duo/ftdmac020.c
+new file mode 100644
+index 00000000..3ce32aab
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/ftdmac020.c
+@@ -0,0 +1,1734 @@
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/dmapool.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++//#include <asm/io.h>
++#include <mach/ftdmac020.h>
++
++#define CHANNEL_NR	8
++#define MAX_CYCLE_PER_BLOCK	0x3FF000    //3.xM, TOT_SIZE[21:0]
++//#define DEBUG
++//#define REG_DUMP
++
++#define USE_IRQ_LOCK    /* SSP ALSA will call these functions while disabling irq */
++
++#ifdef USE_IRQ_LOCK
++#define DMAC020_LOCK(x)     spin_lock_irqsave(x, flags)
++#define DMAC020_UNLOCK(x)   spin_unlock_irqrestore(x, flags)
++#else
++#define DMAC020_LOCK(x)     spin_lock_bh(x)
++#define DMAC020_UNLOCK(x)   spin_unlock_bh(x)
++#endif
++
++/* platform dependent */
++static int (*platform_chan_filter)(int chan_id) = NULL;
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 24;
++
++/*
++ * driver/dma/at_hdmac.c can be the template
++ */
++/**
++ * struct ftdmac020_desc - async transaction descriptor.
++ * @lld: hardware descriptor, MUST be the first member
++ * @value: value for MEMSET (Must be fixed here)
++ * @ccr: value for channel control register
++ * @cfg: value for channel configuration register
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the first link list descriptor (2nd block)
++ * @cycle: transfer size
++ * @txd: support for the async_tx api
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @node: node on the descriptors list
++ * @len: length in bytes
++ *
++ * For a chained transfer, software has to set channel-specific hardware
++ * registers to describe the first block and link list descriptors to describe
++ * other blocks. Because of this unbelievable brain-damaged design, the
++ * software descriptor and driver became unnecessarily complex.
++ *
++ * Sure, we can reuse src, dst, next and cycle in lld to save some space.
++ * The reason I do not do that is not to make you confused.
++ */
++struct ftdmac020_desc {
++	/* not used by the first block */
++	struct ftdmac020_lld lld;
++
++	/* used only by the first block. This is per channel configuration */
++	unsigned int value; /* for MEMSET */
++	unsigned int ccr;   /* Cn_CSR */
++	unsigned int cfg;   /* Cn_CFG */
++	dma_addr_t src;     /* Cn_SrcAddr */
++	dma_addr_t dst;     /* Cn_DstAddr */
++	dma_addr_t next;    /* Cn_LLP */
++	unsigned int cycle; /* Cn_SIZE */
++
++	struct dma_async_tx_descriptor txd;
++	struct list_head child_list;
++
++	/* used by all blocks */
++	struct ftdmac020_chan *ftchan;
++	struct list_head node;
++	size_t len;
++};
++
++/**
++ * struct ftdmac020_chan - internal representation of an ftdmac020 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftdmac020: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftdmac020_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftdmac020 *ftdmac020;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++	enum dma_transaction_type transaction_type;
++};
++
++/**
++ * struct ftdmac020 - internal representation of an ftdmac020 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @id: id for each device
++ * @tc_irq: terminal count irq number
++ * @ea_irq: error and abort irq number
++ * @channel: channel table
++ */
++struct ftdmac020 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	int id;
++	unsigned int irq;
++	struct dma_pool *dma_desc_pool;
++	struct ftdmac020_chan channel[CHANNEL_NR];
++};
++
++static const char *ftdmac020_name[] = {"ftdmac020", "ftdmac020"};
++static dma_cookie_t ftdmac020_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftdmac020_stop_channel(struct ftdmac020_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++    u32 value;
++
++    /* abort first */
++    value = ioread32(base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++    value |= (0x1 << 15);   /* ABT */
++    iowrite32(value, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++    udelay(100);
++#if 0
++    // clear ABT interrupt will do at ISR
++    /* clear ABT interrupt, then this channel can be enabled again */
++    value = (0x1 << chan_id) | (0x1 << (16 + chan_id));
++    iowrite32(value, base + FTDMAC020_OFFSET_EAICR);
++    // we don't need to disable dmach, because when ERR/ABT status register(0x18) was assert to 1,
++    // dma020 controller will set dmach CH_EN & ABT(Cn_CSR)to 0
++    /* disable dmach */
++	iowrite32(0, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++#endif
++}
++
++static void ftdmac020_enable(struct ftdmac020 *ftdmac020)
++{
++	void __iomem *base = ftdmac020->base;
++
++	iowrite32(FTDMAC020_CR_ENABLE, base + FTDMAC020_OFFSET_CR);
++}
++
++static void ftdmac020_disable(struct ftdmac020 *ftdmac020)
++{
++	void __iomem *base = ftdmac020->base;
++
++	iowrite32(0, base + FTDMAC020_OFFSET_CR);
++}
++
++
++static int ftdmac020_chan_is_enabled(struct ftdmac020_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++	unsigned int enabled;
++
++	enabled = ioread32(base + FTDMAC020_OFFSET_CH_ENABLED);
++	return enabled & (1 << chan_id);
++}
++
++/**
++ * ftdmac020_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftdmac020_desc *ftdmac020_alloc_desc(
++		struct ftdmac020_chan *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020 *ftdmac020 = ftchan->ftdmac020;
++	struct ftdmac020_desc *desc;
++	dma_addr_t phys;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = dma_pool_alloc(ftdmac020->dma_desc_pool, gfp_flags, &phys);
++	if (desc) {
++		memset(desc, 0, sizeof(*desc));
++
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftdmac020_tx_submit;
++		desc->txd.phys = phys;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftdmac020_free_desc(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &desc->ftchan->common;
++	struct ftdmac020 *ftdmac020 = ftchan->ftdmac020;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	dma_pool_free(ftdmac020->dma_desc_pool, desc, desc->txd.phys);
++}
++
++/**
++ * ftdmac020_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftdmac020_desc *ftdmac020_desc_get(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc = NULL;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	DMAC020_LOCK(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++			struct ftdmac020_desc, node);
++
++		list_del(&desc->node);
++	}
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftdmac020_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			DMAC020_LOCK(&ftchan->lock);
++			ftchan->descs_allocated++;
++			DMAC020_UNLOCK(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftdmac020_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftdmac020_desc_put(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *child;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	DMAC020_LOCK(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++static void ftdmac020_unmap_desc(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftdmac020_remove_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *child;
++	struct ftdmac020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->child_list, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftdmac020_unmap_desc(child);
++		ftdmac020_desc_put(child);
++	}
++
++	ftdmac020_unmap_desc(desc);
++	ftdmac020_desc_put(desc);
++}
++
++/**
++ * ftdmac020_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @src_shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @dst_shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * 		when MEMSET, it's the set value
++ */
++static struct ftdmac020_desc *ftdmac020_create_chain(
++		struct ftdmac020_chan *ftchan,
++		struct ftdmac020_desc *first,
++		dma_addr_t src, dma_addr_t dest, size_t len,
++		unsigned int src_shift, unsigned int dst_shift, int fixed_src, int fixed_dest)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_dma_slave *slave = chan->private;
++	struct ftdmac020_desc *prev = NULL;
++	unsigned int ccr;
++	unsigned int lld_ctrl;
++	size_t offset;
++	unsigned int cycle;
++	bool is_memset = false;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, src_shift %d, dst_shift %d)\n",
++		__func__, src, dest, len, src_shift, dst_shift);
++	if ((src_shift == 2 && ((src | len) & 3)) ||
++	    (src_shift == 1 && ((src | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or src data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++    if ((dst_shift == 2 && ((dest | len) & 3)) ||
++	    (dst_shift == 1 && ((dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or dst data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	/* When using memset, src is set to zero */
++	if (src == 0 && fixed_src)
++		is_memset = true;
++
++	if (first) {
++		if (list_empty(&first->child_list))
++			prev = first;
++		else
++			prev = list_entry(first->child_list.prev,
++				struct ftdmac020_desc, node);
++	}
++
++	ccr = FTDMAC020_CCR_ENABLE
++	    | ((slave->src_size & 0x7) << 16)
++	    | FTDMAC020_CCR_PRIO_0
++	    | FTDMAC020_CCR_FIFOTH_1;
++
++	lld_ctrl = FTDMAC020_LLD_CTRL_FIFOTH_1;
++
++    switch (src_shift) {
++	case 2:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_32;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_32;
++		break;
++	case 1:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_16;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_16;
++		break;
++	case 0:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_8;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	switch (dst_shift) {
++	case 2:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_32;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_32;
++		break;
++	case 1:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_16;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_16;
++		break;
++	case 0:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_8;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	if (slave && slave->handshake >= 0)
++		ccr |= FTDMAC020_CCR_HANDSHAKE;
++
++	if (fixed_src) {
++		ccr |= FTDMAC020_CCR_SRC_FIXED;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_FIXED;
++	} else {
++		ccr |= FTDMAC020_CCR_SRC_INC;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_INC;
++	}
++
++	if (fixed_dest && !is_memset) {
++		ccr |= FTDMAC020_CCR_DST_FIXED;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_FIXED;
++	} else {
++		ccr |= FTDMAC020_CCR_DST_INC;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_INC;
++	}
++
++	ccr |= ((slave->src_sel & 0x1) << 2);  /* SRC_SEL */
++	ccr |= ((slave->dst_sel & 0x1) << 1);  /* DST_SEL */
++	lld_ctrl |= ((slave->src_sel & 0x1) << 17);  /* SRC_SEL */
++	lld_ctrl |= ((slave->dst_sel & 0x1) << 16);  /* DST_SEL */
++
++	/* we must seperate the len into multiple descriptors. Because len may be a bigger one */
++	for (offset = 0; offset < len; offset += cycle << src_shift) {
++		struct ftdmac020_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> src_shift,
++				MAX_CYCLE_PER_BLOCK);
++
++		desc = ftdmac020_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		/*
++		 * Importatnt: 1. fixed_dest is viewed as memset value
++		 *             2. src is defined as the place of "int value" in ftdmac020_desc
++		 */
++		if (is_memset) {
++			desc->value = fixed_dest;
++			src = desc->txd.phys + sizeof(struct ftdmac020_lld);
++		}
++
++		if (fixed_src) {
++			desc->src = desc->lld.src = src;
++		} else {
++			desc->src = desc->lld.src = src + offset;
++		}
++
++		if (fixed_dest && !is_memset) {
++			desc->dst = desc->lld.dst = dest;
++		} else {
++			desc->dst = desc->lld.dst = dest + offset;
++		}
++
++		desc->next	= 0;
++		desc->cycle	= cycle & FTDMAC020_CYC_MASK;
++		desc->ccr	= ccr;
++		desc->cfg	= 0;
++		desc->len	= cycle << src_shift;
++
++		desc->lld.next	= 0;
++		desc->lld.cycle	= cycle & FTDMAC020_LLD_CYCLE_MASK;
++		desc->lld.ctrl	= lld_ctrl;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/*
++			 * Mask terminal count interrupt for this descriptor.
++			 * What an inconvenient stupid design.
++			 */
++			prev->ccr	|= FTDMAC020_CCR_MASK_TC;
++			prev->lld.ctrl	|= FTDMAC020_LLD_CTRL_MASK_TC;
++
++			/* hardware link list pointer */
++			prev->next	= FTDMAC020_LLP_ADDR(desc->txd.phys);
++			prev->lld.next	= desc->txd.phys;
++
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++		prev = desc;
++	}
++
++	/*
++	 * Here just create the chain only. When submit function is called, this desc will be added to
++	 * ftchan->active_list.
++	 */
++	return first;
++err:
++	if (first)
++		ftdmac020_remove_chain(first);
++	return NULL;
++}
++
++static void ftdmac020_start_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	void __iomem *base = ftchan->ftdmac020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++
++	/*
++	 * The first transfer block is not described by hardware lld.
++	 * Instead, we should fill some hardware registers.
++	 * What a stupid weird design.
++	 */
++	dev_dbg(chan2dev(chan), "\t[SRC %d] = %x\n", chan_id, desc->src);
++	iowrite32(desc->src, base + FTDMAC020_OFFSET_SRC_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DST %d] = %x\n", chan_id, desc->dst);
++	iowrite32(desc->dst, base + FTDMAC020_OFFSET_DST_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[LLP %d] = %x\n", chan_id, desc->next);
++	iowrite32(desc->next, base + FTDMAC020_OFFSET_LLP_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	iowrite32(desc->cycle, base + FTDMAC020_OFFSET_CYC_CH(chan_id));
++
++	/* go */
++	dev_dbg(chan2dev(chan), "\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	iowrite32(desc->cfg, base + FTDMAC020_OFFSET_CFG_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CCR %d] = %x\n", chan_id, desc->ccr);
++	iowrite32(desc->ccr, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++
++#ifdef REG_DUMP
++	printk("\t[SRC %d] = %x\n", chan_id, desc->src);
++	printk("\t[DST %d] = %x\n", chan_id, desc->dst);
++	printk("\t[LLP %d] = %x\n", chan_id, desc->next);
++	printk("\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	printk("\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	printk("\t[CCR %d] = %x\n", chan_id, desc->ccr);
++#endif
++}
++
++static void ftdmac020_start_new_chain(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++	ftdmac020_start_chain(desc);
++}
++
++static void ftdmac020_finish_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	DMAC020_LOCK(&ftchan->lock);
++	ftchan->completed_cookie = desc->txd.cookie;
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback) {
++	    /* If this channel is terminated by manual, we dont need to callback */
++	    if (ftchan->transaction_type != DMA_TX_TYPE_END)
++		    desc->txd.callback(desc->txd.callback_param);
++    }
++
++	ftdmac020_remove_chain(desc);
++}
++
++static void ftdmac020_finish_all_chains(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftdmac020_finish_chain(desc);
++	}
++}
++
++static dma_cookie_t ftdmac020_new_cookie(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftdmac020_chan_filter(struct dma_chan *chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftdmac020_dma_slave *slave = data;
++	const char *ftdmac020_drv_name = *(ftdmac020_name + slave->id);
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020 *ftdmac020;
++
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++	ftdmac020 = ftchan->ftdmac020;
++
++	if (strncmp(ftdmac020_drv_name, drv_name, sizeof("ftdmac020")))
++		return false;
++
++	/* When you have more than 2 dma controller's, it checks id */
++	if (slave->id >= 0 && slave->id != ftdmac020->id)
++		return false;
++
++    /* this is platform dependent. Some platform only can use some channels instead of all. */
++    if (platform_chan_filter && platform_chan_filter((int)chan->chan_id))
++        return false;
++
++	chan->private = slave;
++	return true;
++}
++EXPORT_SYMBOL_GPL(ftdmac020_chan_filter);
++
++/**
++ * atc_handle_cyclic - at the end of a period, run callback function
++ * @atchan: channel used for cyclic operations
++ *
++ * Called with atchan->lock held and bh disabled
++ */
++static void ftdmac020_handle_cyclic(struct ftdmac020_chan *ftchan)
++{
++    struct ftdmac020_desc	*first = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++	struct dma_async_tx_descriptor	*txd = &first->txd;
++	dma_async_tx_callback   callback = txd->callback;
++	void			*param = txd->callback_param;
++    struct dma_chan *chan = &ftchan->common;
++
++    dev_dbg(chan2dev(chan), "%s\n", __func__);
++
++	if (callback)
++		callback(param);
++}
++
++/******************************************************************************
++ * tasklet - called after we finished one chain
++ *****************************************************************************/
++static void ftdmac020_tasklet(unsigned long data)
++{
++	struct ftdmac020_chan *ftchan = (struct ftdmac020_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++    if (ftchan->transaction_type == DMA_TX_TYPE_END) {
++        if (!list_empty(&ftchan->active_list))
++            panic("%s, active_list should be empty due to terminate_all! \n", __func__);
++
++        return;
++    }
++
++    if (ftchan->transaction_type == DMA_CYCLIC) {
++        dev_dbg(chan2dev(chan), "%s, DMA_CYCLIC \n", __func__);
++	    BUG_ON(list_empty(&ftchan->active_list));
++
++        DMAC020_LOCK(&ftchan->lock);
++        ftdmac020_handle_cyclic(ftchan);
++        DMAC020_UNLOCK(&ftchan->lock);
++    } else {
++        /*
++         * DMA_SLAVE, DMA_MEMCPY
++         */
++        dev_dbg(chan2dev(chan), "%s, DMA_SLAVE / MEMCPY\n", __func__);
++	    BUG_ON(list_empty(&ftchan->active_list));
++
++        DMAC020_LOCK(&ftchan->lock);
++
++    	/* remove already finished descriptor */
++    	desc = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++    	list_del(&desc->node);
++
++    	/* check if there were another transfer to do */
++    	ftdmac020_start_new_chain(ftchan);
++
++    	DMAC020_UNLOCK(&ftchan->lock);
++    	ftdmac020_finish_chain(desc);
++    }
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftdmac020_interrupt(int irq, void *dev_id)
++{
++	struct ftdmac020 *ftdmac020 = dev_id;
++	unsigned int status;
++	int i, count = 0;
++
++	status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_TCISR);
++	if (!status) {
++	    /* read error status */
++	    status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_EAISR);
++    	if (!status)
++    		return IRQ_NONE;
++
++        /* check channel abort */
++        if (status & 0x00ff0000) {  // if channel abort
++            while(1) {
++                unsigned int abort_status;
++                count++;
++                // read ABT status register to make sure channel has abort status
++                abort_status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_EARAW);
++                // wait channel abort status is 1, exit
++                if (status & abort_status)
++                    break;
++
++                if (count > 1000) {
++                    printk("Error!! FTDMAC020 abort but abort sts bit not assert to 1\n");
++                    break;
++                }
++            }
++        }
++
++        /* clear status */
++	    iowrite32(status, ftdmac020->base + FTDMAC020_OFFSET_EAICR);
++
++	    for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (status & FTDMAC020_EA_ERR_CH(i))
++			dev_info(chan2dev(chan), "error happened\n");
++
++#if 0	/* treat this case as normal due to ABT action for stop */
++		if (status & FTDMAC020_EA_ABT_CH(i))
++			dev_dbg(chan2dev(chan), "transfer aborted\n");
++#endif
++	    }
++
++	    return IRQ_HANDLED;
++	}
++
++	/* clear status */
++	iowrite32(status, ftdmac020->base + FTDMAC020_OFFSET_TCICR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (status & (1 << i)) {
++			dev_dbg(chan2dev(chan), "terminal count\n");
++			tasklet_schedule(&ftchan->tasklet);
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftdmac020_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftdmac020_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++	bool busy;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	desc = container_of(txd, struct ftdmac020_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	DMAC020_LOCK(&ftchan->lock);
++
++	cookie = ftdmac020_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list))
++		busy = false;
++	else
++		busy = true;
++
++	list_add_tail(&desc->node, &ftchan->active_list);
++
++#if 0   /* Harry, move to issue pending. If we start the transaction here, it will have potential
++         * chance to lose the LLP due to race condition between CPU and hardware.
++         */
++	/* start ASAP */
++	if (!busy)
++		ftdmac020_start_chain(desc);
++#endif
++
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftdmac020_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftdmac020_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++	unsigned long       flags;
++
++    if (flags)  {}
++
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftdmac020_desc *desc;
++
++		desc = ftdmac020_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	DMAC020_LOCK(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list); /* add tmp_list to free_list */
++	ftchan->completed_cookie = chan->cookie = 1;
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftdmac020_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftdmac020_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_desc *tmp;
++	struct ftdmac020 *ftdmac020;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++	ftdmac020 = ftchan->ftdmac020;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(ftdmac020_chan_is_enabled(ftchan));
++
++	DMAC020_LOCK(&ftchan->lock);
++	ftdmac020_stop_channel(ftchan);
++	ftdmac020_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftdmac020_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++/**
++ * ftdmac020_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++		dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((src >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect src physical address 0x%x \n", __func__, src);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++	} else {
++		shift = 0;
++	}
++
++	desc = ftdmac020_create_chain(ftchan, NULL, src, dest, len,
++		shift, shift, 0, 0);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMCPY;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac020_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @value: the given value for memset used
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest,
++		int value, size_t len, unsigned long flags)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(dest %x, value %x, len %x)\n",
++		__func__, dest, value, len);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(len & 3)) {
++		dev_info(chan2dev(chan), "%s: length isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(dest & 3)) {
++		dev_info(chan2dev(chan), "%s: dest addr isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	shift = 2;
++
++	desc = ftdmac020_create_chain(ftchan, NULL, 0, dest, len,
++		shift, shift, 1, value);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMSET;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * atc_prep_dma_cyclic - prepare the cyclic DMA transfer
++ * @chan: the DMA channel to prepare
++ * @buf_addr: physical DMA address where the buffer starts
++ * @buf_len: total number of bytes for the entire buffer
++ * @period_len: number of bytes for each period
++ * @direction: transfer direction, to or from device
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
++		size_t period_len, enum dma_transfer_direction direction)
++{
++	struct ftdmac020_dma_slave  *slave = chan->private;
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc = NULL, *child, *last;
++	dma_addr_t  src_addr, dst_addr;
++	int i, src_shift, dst_shift, periods = buf_len / period_len;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s, please call dmaengine_slave_config() first! \n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!list_empty(&ftchan->active_list))) {
++		dev_err(chan2dev(chan), "%s, active list is not empty! \n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!buf_len || !period_len)) {
++		dev_dbg(chan2dev(chan), "prep_dma_cyclic: length is zero!\n");
++		return NULL;
++	}
++
++	if ((direction != DMA_MEM_TO_DEV) && (direction != DMA_DEV_TO_MEM)) {
++		dev_err(chan2dev(chan), "%s: incorrect direction %d \n", __func__, direction);
++		return NULL;
++	}
++
++	if (buf_len % period_len) {
++		dev_err(chan2dev(chan), "%s: incorrect length %d \n", __func__, buf_len);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			src_shift = 0;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			src_shift = 1;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			src_shift = 2;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++					__func__);
++			return NULL;
++	}
++
++    switch (slave->common.dst_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			dst_shift = 0;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			dst_shift = 1;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			dst_shift = 2;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++					__func__);
++			return NULL;
++	}
++
++#ifdef REG_DUMP
++    printk("%s, src_shift: %d, dst_shift: %d, slave->src_size: %d\n", __func__,
++                    src_shift, dst_shift, slave->src_size);
++#endif
++
++	if (slave->src_size > FTDMAC020_BURST_SZ_256 || slave->src_size < FTDMAC020_BURST_SZ_1) {
++		dev_err(chan2dev(chan), "%s: incorrect src_size %d\n", __func__, slave->src_size);
++		return NULL;
++	}
++
++    if (direction == DMA_MEM_TO_DEV) {
++        if (buf_addr != slave->common.src_addr) {
++            dev_err(chan2dev(chan), "%s: inconsistent src address %x \n", __func__, buf_addr);
++                      return NULL;
++        }
++    } else {
++        if (buf_addr != slave->common.dst_addr) {
++            dev_err(chan2dev(chan), "%s: inconsistent dst address %x \n", __func__, buf_addr);
++                      return NULL;
++        }
++    }
++
++	if (unlikely(!pfn_valid((buf_addr >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, buf_addr);
++		return NULL;
++	}
++
++	if (direction != slave->common.direction) {
++		dev_err(chan2dev(chan), "%s: inconsistent direction %d\n", __func__, direction);
++		return NULL;
++	}
++
++	src_addr = slave->common.src_addr;
++	dst_addr = slave->common.dst_addr;
++
++	/* create chain */
++	for (i = 0; i < periods; i ++) {
++		struct ftdmac020_desc *tmp;
++		int fixed_src, fixed_dst;
++
++		if (direction == DMA_MEM_TO_DEV) {
++			fixed_src = 0;  /* INC */
++			fixed_dst = 1;
++		} else {
++			fixed_src = 1;
++			fixed_dst = 0;
++		}
++
++		tmp = ftdmac020_create_chain(ftchan, desc,
++				src_addr, dst_addr, period_len,
++				src_shift, dst_shift, fixed_src, fixed_dst);
++
++		/* increase the address */
++		if (fixed_src == 0)
++			src_addr += period_len;
++		if (fixed_dst == 0)
++			dst_addr += period_len;
++
++		if (!tmp)
++			return NULL;
++		if (!desc)  /* all childs are chained to the first active node */
++			desc = tmp;
++
++		if (direction == DMA_MEM_TO_DEV) {
++			if (slave->handshake >= 0)
++				tmp->cfg = FTDMAC020_CFG_DST_HANDSHAKE_EN
++					| FTDMAC020_CFG_DST_HANDSHAKE(slave->handshake);
++		} else {
++			if (slave->handshake >= 0)
++				tmp->cfg = FTDMAC020_CFG_SRC_HANDSHAKE_EN
++					| FTDMAC020_CFG_SRC_HANDSHAKE(slave->handshake);
++		}
++	}
++
++	/* walk through the whole list and update TC_MASK to issue interrupt
++	*/
++	list_for_each_entry(child, &desc->child_list, node) {
++		child->ccr &= ~FTDMAC020_CCR_MASK_TC;
++		child->ccr |= FTDMAC020_CCR_PRIO_3; /* audio needs high priority */
++		child->lld.ctrl &= ~FTDMAC020_LLD_CTRL_MASK_TC;
++	}
++
++	/* form hardware link list pointer ring */
++	last = list_entry(desc->child_list.prev, struct ftdmac020_desc, node);
++	last->next	= FTDMAC020_LLP_ADDR(desc->txd.phys);
++	last->lld.next	= desc->txd.phys;
++
++#ifdef REG_DUMP   //dump register
++	child = desc;
++	printk("(0x%x)child->ccr: 0x%x, cfg: 0x%x, src:0x%x, lld.src:0x%x, dst:0x%x, lld.dst:0x%x, lld.next:0x%x, lld.cycle:0x%x, lld.ctrl:0x%x \n",
++			child->txd.phys, child->ccr, child->cfg, child->src, child->dst,
++			child->lld.src, child->lld.dst, child->lld.next, child->lld.cycle, child->lld.ctrl);
++
++	list_for_each_entry(child, &desc->child_list, node) {
++		printk("(0x%x)child->ccr:0x%x, cfg:0x%x, src:0x%x, dst:0x%x, lld.src:0x%x, lld.dst:0x%x, lld.next:0x%x, lld.cycle:0x%x, lld.ctrl:0x%x \n",
++				child->txd.phys, child->ccr, child->cfg, child->src, child->dst,
++				child->lld.src, child->lld.dst, child->lld.next, child->lld.cycle, child->lld.ctrl);
++	}
++#endif
++
++	/* Update the tc_mask to issue interrupt per element in the chain */
++	desc->txd.cookie = -EBUSY;
++	desc->txd.flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	ftchan->transaction_type = DMA_CYCLIC;
++	chan->private = NULL;   /* got the parameter already, so free it */
++
++	return &desc->txd;
++}
++
++
++/**
++ * ftdmac020_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++		unsigned int sg_len, enum dma_transfer_direction direction,
++		unsigned long flags)
++{
++	struct ftdmac020_dma_slave *slave = chan->private;
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int src_shift, dst_shift;
++	unsigned int i;
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s, please call dmaengine_slave_config() first! \n", __func__);
++		return NULL;
++	}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		src_shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		src_shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		src_shift = 2;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++    switch (slave->common.dst_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		dst_shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		dst_shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		dst_shift = 2;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++	if (slave->src_size > FTDMAC020_BURST_SZ_256 || slave->src_size < FTDMAC020_BURST_SZ_1) {
++		dev_err(chan2dev(chan), "%s: incorrect src_size %d\n", __func__, slave->src_size);
++		BUG();
++	}
++
++	switch (direction) {
++	case DMA_MEM_TO_DEV:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++            if (unlikely(!pfn_valid((mem >> PAGE_SHIFT)))) {
++                dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, mem);
++                goto err;
++            }
++			tmp = ftdmac020_create_chain(ftchan, desc,
++				mem, slave->common.dst_addr, len,
++				src_shift, dst_shift, 0, 1);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC020_CFG_DST_HANDSHAKE_EN
++				| FTDMAC020_CFG_DST_HANDSHAKE(slave->handshake);
++		break;
++	case DMA_DEV_TO_MEM:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++            if (unlikely(!pfn_valid((mem >> PAGE_SHIFT)))) {
++                dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, mem);
++                goto err;
++            }
++
++			tmp = ftdmac020_create_chain(ftchan, desc,
++				slave->common.src_addr, mem, len,
++				src_shift, dst_shift, 1, 0);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC020_CFG_SRC_HANDSHAKE_EN
++				| FTDMAC020_CFG_SRC_HANDSHAKE(slave->handshake);
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n",
++			__func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++	chan->private = NULL;   /* got the parameter already, so free it */
++	ftchan->transaction_type = DMA_SLAVE;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftdmac020_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++		unsigned long arg)
++{
++	struct ftdmac020_chan *ftchan;
++	unsigned long       flags;
++	int ret = -ENXIO;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (cmd == DMA_SLAVE_CONFIG) {
++		struct dma_slave_config *slave_config = (struct dma_slave_config *)arg;
++		struct ftdmac020_dma_slave  *dma_slave;
++
++		dma_slave = container_of(slave_config, struct ftdmac020_dma_slave, common);
++		chan->private = dma_slave;
++		ret = 0;
++	}
++
++	if (cmd == DMA_TERMINATE_ALL) {
++		/*
++		 * This is only called when something went wrong elsewhere, so
++		 * we don't really care about the data. Just disable the channel.
++		 */
++		DMAC020_LOCK(&ftchan->lock);
++		ftdmac020_stop_channel(ftchan);
++		ftchan->transaction_type = DMA_TX_TYPE_END;
++		ftdmac020_finish_all_chains(ftchan);
++		DMAC020_UNLOCK(&ftchan->lock);
++	}
++
++	return ret;
++}
++
++/**
++ * ftdmac020_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftdmac020_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		struct dma_tx_state *txstate)
++{
++	struct ftdmac020_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftdmac020_issue_pending - try to active work
++ * @chan: target DMA channel
++ */
++static void ftdmac020_issue_pending(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	DMAC020_LOCK(&ftchan->lock);
++	BUG_ON(list_empty(&ftchan->active_list));
++	/* get first descriptor and go */
++	ftdmac020_start_new_chain(ftchan);
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftdmac020_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftdmac020 *ftdmac020;
++	struct dma_device *dma;
++	int irq, i , err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftdmac020 = kzalloc(sizeof(*ftdmac020), GFP_KERNEL);
++	if (!ftdmac020) {
++		return -ENOMEM;
++	}
++
++	dma = &ftdmac020->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftdmac020);
++	ftdmac020->id = pdev->id;
++
++	/* map io memory */
++	ftdmac020->res = request_mem_region(res->start, res->end - res->start + 1,
++			dev_name(&pdev->dev));
++	if (ftdmac020->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftdmac020->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftdmac020->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* create a pool of consistent memory blocks for hardware descriptors */
++	ftdmac020->dma_desc_pool = dma_pool_create("ftdmac020_desc_pool",
++			&pdev->dev, sizeof(struct ftdmac020_desc),
++			4 /* word alignment */, 0);
++	if (!ftdmac020->dma_desc_pool) {
++		dev_err(&pdev->dev, "No memory for descriptor pool\n");
++		err = -ENOMEM;
++		goto err_pool_create;
++	}
++
++	/* force dma off, just in case */
++	ftdmac020_disable(ftdmac020);
++
++	/* initialize channels and create tasklet per channel */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device	= dma;
++		ftchan->common.cookie	= DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftdmac020		= ftdmac020;
++		ftchan->completed_cookie	= DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftdmac020_tasklet, (unsigned long)ftchan);
++		list_add_tail(&ftchan->common.device_node /*new*/, &dma->channels /*head*/);
++	}
++
++	/* clear all pending interrupts */
++	iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_TCICR);
++	iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_EAICR);
++
++    /* sync dma_req */
++    iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_SYNC);	
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftdmac020_alloc_chan_resources;
++	dma->device_free_chan_resources	= ftdmac020_free_chan_resources;
++	dma->device_prep_dma_memcpy	= ftdmac020_prep_dma_memcpy;
++	dma->device_prep_dma_memset 	= ftdmac020_prep_dma_memset;
++	dma->device_prep_slave_sg	= ftdmac020_prep_slave_sg;
++	dma->device_prep_dma_cyclic = ftdmac020_prep_dma_cyclic;
++	dma->device_control		    = ftdmac020_control;
++	dma->device_tx_status		= ftdmac020_tx_status;
++	dma->device_issue_pending	= ftdmac020_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask); //for replacing memcpy by DMA
++	dma_cap_set(DMA_MEMSET, dma->cap_mask); //for replacing memset by DMA
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);  //for normal DMA IO
++	dma_cap_set(DMA_CYCLIC, dma->cap_mask); //for audio
++
++	err = request_irq(irq, ftdmac020_interrupt, 0, pdev->name, ftdmac020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_irq;
++	}
++
++	ftdmac020->irq = irq;
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	ftdmac020_enable(ftdmac020);
++	dev_info(&pdev->dev,
++		"DMA engine driver: irq %d, mapped at 0x%p\n",
++		irq, ftdmac020->base);
++
++	return 0;
++
++err_register:
++	free_irq(irq, ftdmac020);
++err_irq:
++	dma_pool_destroy(ftdmac020->dma_desc_pool);
++err_pool_create:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftdmac020->base);
++err_ioremap:
++	release_resource(ftdmac020->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac020);
++	return err;
++}
++
++static int __exit ftdmac020_remove(struct platform_device *pdev)
++{
++	struct ftdmac020 *ftdmac020;
++	int i;
++
++	ftdmac020 = platform_get_drvdata(pdev);
++
++	ftdmac020_disable(ftdmac020);
++	dma_async_device_unregister(&ftdmac020->dma);
++
++	free_irq(ftdmac020->irq, ftdmac020);
++	dma_pool_destroy(ftdmac020->dma_desc_pool);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftdmac020->base);
++	release_resource(ftdmac020->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac020);
++
++	return 0;
++}
++
++/**
++ * ftdmac020_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac020_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac020_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id))
++{
++    if (platform_chan_filter != NULL) {
++        printk("%s, platform_chan_filter was registered already! \n", __func__);
++        return -1;
++    }
++
++    platform_chan_filter = chan_filter_fn;
++
++    return 0;
++}
++
++static struct platform_driver ftdmac020_driver = {
++	.probe		= ftdmac020_probe,
++	.remove		= __exit_p(ftdmac020_remove),
++	.driver		= {
++		.name	= "ftdmac020",
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftdmac020_init(void)
++{
++	int ret = 0;
++	if (MAX_CYCLE_PER_BLOCK & ~FTDMAC020_CYC_MASK)
++		panic("%s, invalid MAX_CYCLE_PER_BLOCK: 0x%x \n", __func__, MAX_CYCLE_PER_BLOCK);
++
++	if ((ret = platform_driver_register(&ftdmac020_driver))) {
++		printk("failed to register DMAC020 driver\n");
++		return ret;
++	}
++	return ret;
++}
++
++static void __exit ftdmac020_exit(void)
++{
++	platform_driver_unregister(&ftdmac020_driver);
++}
++
++module_init(ftdmac020_init);
++module_exit(ftdmac020_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTDMAC020 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-Duo/ftdmac030.c b/arch/arm/mach-GM-Duo/ftdmac030.c
+new file mode 100644
+index 00000000..fa324005
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/ftdmac030.c
+@@ -0,0 +1,1484 @@
++/*
++ * Faraday FTDMAC030 DMA engine driver
++ *
++ * (C) Copyright 2011 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/dmapool.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <asm/io.h>
++#include <asm/cputype.h>
++#include <mach/ftdmac030.h>
++#ifdef CONFIG_PLATFORM_GM8210
++#include <mach/ftpmu010.h>
++#include <mach/fmem.h>
++#endif
++
++#define DRV_NAME	"ftdmac030"
++#define CHANNEL_NR	8
++unsigned int dmac030_sw_intr[5] = {0, 0, 0, 0, 0};
++EXPORT_SYMBOL(dmac030_sw_intr);
++
++/*
++ * This value must be multiple of 32-bits to prevent from changing the
++ * alignment of child descriptors.
++ */
++#define MAX_CYCLE_PER_BLOCK	0x200000
++#if (MAX_CYCLE_PER_BLOCK > FTDMAC030_CYC_MASK) || \
++	(MAX_CYCLE_PER_BLOCK & 0x3)
++#error invalid MAX_CYCLE_PER_BLOCK
++#endif
++
++#define GRANT_WINDOW	64
++
++/* platform dependent */
++static int (*platform_chan_filter)(int chan_id) = NULL;
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 64;
++module_param(init_nr_desc_per_channel, uint, 0644);
++MODULE_PARM_DESC(init_nr_desc_per_channel,
++		 "initial descriptors per channel (default: 64)");
++
++/**
++ * struct ftdmac030_desc - async transaction descriptor.
++ * @lld: hardware descriptor, MUST be the first member
++ * @ctrl: value for channel control register
++ * @cfg: value for channel configuration register
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the first link list descriptor (2nd block)
++ * @cycle: transfer size
++ * @txd: support for the async_tx api
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @node: node on the descriptors list
++ * @len: length in bytes
++ */
++struct ftdmac030_desc {
++	struct ftdmac030_lld lld;
++
++	/* used only by the first block */
++	unsigned int value; /* for MEMSET */
++	unsigned int cfg;
++
++	struct dma_async_tx_descriptor txd;
++	struct list_head child_list;
++
++	/* used by all blocks */
++	struct ftdmac030_chan *ftchan;
++	struct list_head node;
++	size_t len;
++};
++
++/**
++ * struct ftdmac030_chan - internal representation of an ftdmac030 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftdmac030: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftdmac030_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftdmac030 *ftdmac030;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++	enum dma_transaction_type transaction_type;
++};
++
++/**
++ * struct ftdmac030 - internal representation of an ftdmac030 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @id: id for each device
++ * @irq: irq number
++ * @channel: channel table
++ */
++struct ftdmac030 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	int id;
++	unsigned int irq;
++	struct dma_pool *dma_desc_pool;
++	struct ftdmac030_chan channel[CHANNEL_NR];
++};
++
++static dma_cookie_t ftdmac030_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftdmac030_stop_channel(struct ftdmac030_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac030->base;
++
++	iowrite32(0, base + FTDMAC030_OFFSET_CTRL_CH(chan_id));
++}
++
++static int ftdmac030_chan_is_enabled(struct ftdmac030_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac030->base;
++	unsigned int enabled;
++
++	enabled = ioread32(base + FTDMAC030_OFFSET_CH_ENABLED);
++	return enabled & (1 << chan_id);
++}
++
++/**
++ * ftdmac030_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftdmac030_desc *ftdmac030_alloc_desc(
++		struct ftdmac030_chan *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030 *ftdmac030 = ftchan->ftdmac030;
++	struct ftdmac030_desc *desc;
++	dma_addr_t phys;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = dma_pool_alloc(ftdmac030->dma_desc_pool, gfp_flags, &phys);
++	if (desc) {
++		memset(desc, 0, sizeof(*desc));
++
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftdmac030_tx_submit;
++		desc->txd.phys = phys;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftdmac030_free_desc(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &desc->ftchan->common;
++	struct ftdmac030 *ftdmac030 = ftchan->ftdmac030;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	dma_pool_free(ftdmac030->dma_desc_pool, desc, desc->txd.phys);
++}
++
++/**
++ * ftdmac030_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftdmac030_desc *ftdmac030_desc_get(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc = NULL;
++
++	spin_lock_bh(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++			struct ftdmac030_desc, node);
++
++		list_del(&desc->node);
++	}
++	spin_unlock_bh(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftdmac030_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			spin_lock_bh(&ftchan->lock);
++			ftchan->descs_allocated++;
++			spin_unlock_bh(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftdmac030_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftdmac030_desc_put(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *child;
++
++	spin_lock_bh(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++static void ftdmac030_unmap_desc(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftdmac030_remove_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *child;
++	struct ftdmac030_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->child_list, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftdmac030_unmap_desc(child);
++		ftdmac030_desc_put(child);
++	}
++
++	ftdmac030_unmap_desc(desc);
++	ftdmac030_desc_put(desc);
++}
++
++/**
++ * ftdmac030_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * 		when MEMSET, it's the set value
++ */
++static struct ftdmac030_desc *ftdmac030_create_chain(
++		struct ftdmac030_chan *ftchan,
++		struct ftdmac030_desc *first,
++		dma_addr_t src, dma_addr_t dest, size_t len,
++		unsigned int shift, int fixed_src, int fixed_dest)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *prev = NULL;
++	struct ftdmac030_dma_slave *slave = chan->private;
++	unsigned int ctrl;
++	size_t offset;
++	unsigned int cycle, SrcTcnt;
++	bool is_memset = false;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, shift %d)\n",
++		__func__, src, dest, len, shift);
++	if ((shift == 3 && ((src | dest | len) & 7)) ||
++	    (shift == 2 && ((src | dest | len) & 3)) ||
++	    (shift == 1 && ((src | dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	/* When using memset, src is set to zero */
++	if (src == 0 && fixed_src)
++		is_memset = true;
++
++	if (first) {
++		if (list_empty(&first->child_list))
++			prev = first;
++		else
++			prev = list_entry(first->child_list.prev,
++				struct ftdmac030_desc, node);
++	}
++
++	switch (slave->common.src_maxburst) {
++	case 128:
++		SrcTcnt = FTDMAC030_CTRL_128BEATS;
++		break;
++	case 64:
++		SrcTcnt = FTDMAC030_CTRL_64BEATS;
++		break;
++	case 32:
++		SrcTcnt = FTDMAC030_CTRL_32BEATS;
++		break;
++	case 16:
++		SrcTcnt = FTDMAC030_CTRL_16BEATS;
++		break;
++	case 8:
++		SrcTcnt = FTDMAC030_CTRL_8BEATS;
++		break;
++	case 4:
++		SrcTcnt = FTDMAC030_CTRL_4BEATS;
++		break;
++	case 2:
++		SrcTcnt = FTDMAC030_CTRL_2BEATS;
++		break;
++	default:
++		SrcTcnt = FTDMAC030_CTRL_1BEAT;
++		break;
++	}
++
++    /* According to CTD/Jerry,
++     * If WSync is disable, tc is asserted when last write command push into command queue.
++     * If WSync is enable, tc is asserted after completing transfer on AXI.
++     * In order to prevent commands not issue to AXI bus, turn on WSync on ctrl register.
++     */
++	ctrl = FTDMAC030_CTRL_ENABLE | SrcTcnt | FTDMAC030_CTRL_WSYNC | FTDMAC030_CTRL_EXP;
++
++	switch (shift) {
++	case 3:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_64
++		     |  FTDMAC030_CTRL_SRC_WIDTH_64;
++		break;
++	case 2:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_32
++		     |  FTDMAC030_CTRL_SRC_WIDTH_32;
++		break;
++	case 1:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_16
++		     |  FTDMAC030_CTRL_SRC_WIDTH_16;
++		break;
++	case 0:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_8
++		     |  FTDMAC030_CTRL_SRC_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	if (fixed_src)
++		ctrl |= FTDMAC030_CTRL_SRC_FIXED;
++	else
++		ctrl |= FTDMAC030_CTRL_SRC_INC;
++
++	if (fixed_dest && !is_memset)
++		ctrl |= FTDMAC030_CTRL_DST_FIXED;
++	else
++		ctrl |= FTDMAC030_CTRL_DST_INC;
++
++	for (offset = 0; offset < len; offset += cycle << shift) {
++		struct ftdmac030_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> shift,
++				MAX_CYCLE_PER_BLOCK);
++
++		desc = ftdmac030_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		/*
++		 * Importatnt: 1. fixed_dest is viewed as memset value
++		 *             2. src is defined as the place of "int value" in ftdmac020_desc
++		 */
++		if (is_memset) {
++			desc->value = fixed_dest;
++			src = desc->txd.phys + sizeof(struct ftdmac030_lld);
++		}
++
++		if (fixed_src)
++			desc->lld.src = src;
++		else
++			desc->lld.src = src + offset;
++
++		if (fixed_dest && !is_memset)
++			desc->lld.dst = dest;
++		else
++			desc->lld.dst = dest + offset;
++
++		desc->cfg = FTDMAC030_CFG_GW(GRANT_WINDOW)
++			  | FTDMAC030_CFG_HIGH_PRIO;
++		desc->len = cycle << shift;
++
++		desc->lld.next	= 0;
++		desc->lld.cycle	= FTDMAC030_CYC_TOTAL(cycle);
++		desc->lld.ctrl	= ctrl;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/*
++			 * Mask terminal count interrupt for this descriptor.
++			 * What an inconvenient stupid design.
++			 */
++			prev->lld.ctrl |= FTDMAC030_CTRL_MASK_TC;
++
++			/* hardware link list pointer */
++			prev->lld.next = desc->txd.phys;
++
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++
++		prev = desc;
++	}
++
++	return first;
++err:
++	if (first)
++		ftdmac030_remove_chain(first);
++	return NULL;
++}
++
++static void ftdmac030_start_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	void __iomem *base = ftchan->ftdmac030->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++
++	/*
++	 * The first transfer block is not described by hardware lld.
++	 * Instead, we should fill some hardware registers.
++	 * What a stupid weird design.
++	 */
++	dev_dbg(chan2dev(chan), "\t[SRC %d] = %x\n", chan_id, desc->lld.src);
++	iowrite32(desc->lld.src, base + FTDMAC030_OFFSET_SRC_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DST %d] = %x\n", chan_id, desc->lld.dst);
++	iowrite32(desc->lld.dst, base + FTDMAC030_OFFSET_DST_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[LLP %d] = %x\n", chan_id, desc->lld.next);
++	iowrite32(desc->lld.next, base + FTDMAC030_OFFSET_LLP_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->lld.cycle);
++	iowrite32(desc->lld.cycle, base + FTDMAC030_OFFSET_CYC_CH(chan_id));
++
++	/* go */
++	dev_dbg(chan2dev(chan), "\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	iowrite32(desc->cfg, base + FTDMAC030_OFFSET_CFG_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CTRL %d] = %x\n", chan_id, desc->lld.ctrl);
++	iowrite32(desc->lld.ctrl, base + FTDMAC030_OFFSET_CTRL_CH(chan_id));
++}
++
++static void ftdmac030_start_new_chain(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac030_desc, node);
++	ftdmac030_start_chain(desc);
++}
++
++static void ftdmac030_finish_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	spin_lock_bh(&ftchan->lock);
++	ftchan->completed_cookie = desc->txd.cookie;
++	spin_unlock_bh(&ftchan->lock);
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback) {
++		/* If this channel is terminated by manual, we dont need to callback */
++		if (ftchan->transaction_type != DMA_TX_TYPE_END)
++			desc->txd.callback(desc->txd.callback_param);
++	}
++
++	ftdmac030_remove_chain(desc);
++}
++
++static void ftdmac030_finish_all_chains(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftdmac030_finish_chain(desc);
++	}
++}
++
++static dma_cookie_t ftdmac030_new_cookie(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftdmac030_chan_filter(struct dma_chan *chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftdmac030_dma_slave *slave = data;
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030 *ftdmac030;
++
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++	ftdmac030 = ftchan->ftdmac030;
++
++	if (strncmp(DRV_NAME, drv_name, sizeof(DRV_NAME)))
++		return false;
++
++	if (slave->id >= 0 && slave->id != ftdmac030->id)
++		return false;
++
++    /* this is platform dependent. Some platform only can use some channels instead of all. */
++    if (platform_chan_filter && platform_chan_filter((int)chan->chan_id))
++        return false;
++
++#if 0 // Let kernel to choose channel
++	if ((slave->channels & (1 << chan->chan_id)) == 0)
++		return false;
++#endif
++
++	chan->private = slave;
++	return true;
++}
++EXPORT_SYMBOL_GPL(ftdmac030_chan_filter);
++
++/******************************************************************************
++ * tasklet - called after we finished one chain
++ *****************************************************************************/
++static void ftdmac030_tasklet(unsigned long data)
++{
++	struct ftdmac030_chan *ftchan = (struct ftdmac030_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++
++	if (ftchan->transaction_type == DMA_TX_TYPE_END) {
++		if (!list_empty(&ftchan->active_list))
++			panic("%s, active_list should be empty due to terminate_all! \n", __func__);
++
++		return;
++	}
++
++	BUG_ON(list_empty(&ftchan->active_list));
++
++	spin_lock_bh(&ftchan->lock);
++
++	/* remove already finished descriptor */
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac030_desc,
++		node);
++	list_del(&desc->node);
++
++	/* check if there were another transfer to do */
++	ftdmac030_start_new_chain(ftchan);
++
++	spin_unlock_bh(&ftchan->lock);
++	ftdmac030_finish_chain(desc);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftdmac030_interrupt(int irq, void *dev_id)
++{
++	struct ftdmac030 *ftdmac030 = dev_id;
++	unsigned int tcs;
++	unsigned int eas;
++	int i;
++
++	tcs = ioread32(ftdmac030->base + FTDMAC030_OFFSET_TCISR);
++	eas = ioread32(ftdmac030->base + FTDMAC030_OFFSET_EAISR);
++	if (!tcs && !eas)
++		return IRQ_NONE;
++
++	/* clear status */
++	if (tcs)
++		iowrite32(tcs, ftdmac030->base + FTDMAC030_OFFSET_TCICR);
++	if (eas)
++		iowrite32(eas, ftdmac030->base + FTDMAC030_OFFSET_EAICR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (eas & FTDMAC030_EA_ERR_CH(i)) {
++			dev_info(chan2dev(chan), "error happened\n");
++			/* dump register to know the direction */
++			printk("ftdmac030_interrupt: srcAddr:0x%x, dstAddr:0x%x, LLP:0x%x \n",
++			    ioread32(ftdmac030->base + 0x108 + 0x20*i), ioread32(ftdmac030->base + 0x10C + 0x20*i),
++			    ioread32(ftdmac030->base + 0x110 + 0x20*i));
++		}
++
++		if (eas & FTDMAC030_EA_ABT_CH(i))
++			dev_info(chan2dev(chan), "transfer aborted\n");
++
++		if (tcs & (1 << i)) {
++			dev_dbg(chan2dev(chan), "terminal count\n");
++
++#ifdef CONFIG_PLATFORM_GM8210
++            /* Temp soluation:
++             * Work around: DMAC030 is shared between FA726 and FA626. The Master CPU uses channel
++             * 0-3 for general use. For the cpucomm module, Slave CPU uses 6, 7 and Master cpu use
++             * channel 4,5. When DMAC interrupt comes, we forward interupt to other cpu.
++             * So we add code here.
++             */
++            if (get_cpu_id() == 0x726) {
++                if (i >= 4) {
++                    switch (i) {
++                      case 4:
++                        ftpmu010_trigger_intr(CPU_INT_6);
++                        dmac030_sw_intr[0] ++;
++                        break;
++                      case 5:
++                        ftpmu010_trigger_intr(CPU_INT_4);
++                        dmac030_sw_intr[1] ++;
++                        break;
++                      case 6:
++                        ftpmu010_trigger_intr(CPU_INT_2);
++                        dmac030_sw_intr[2] ++;
++                        break;
++                      case 7:
++                        ftpmu010_trigger_intr(CPU_INT_3);
++                        dmac030_sw_intr[3] ++;
++                        break;
++                    }
++                } else {
++                    static fmem_pci_id_t  pci_id = -1;
++                    static fmem_cpu_id_t  cpu_id = -1;
++
++                    if (pci_id == -1)
++                        fmem_get_identifier(&pci_id, &cpu_id);
++
++                    /* Only EP needs this feature for 2ddma. cpucomm uses ZEBRA_EP_FA626_IRQ0: CPU_INT_9
++                     */
++                    if ((pci_id != FMEM_PCI_HOST) && (i == 3)) {
++                        ftpmu010_trigger_intr(CPU_INT_9);
++                        dmac030_sw_intr[4] ++;
++                    } else {
++                        /* channel 0-3 */
++                        tasklet_schedule(&ftchan->tasklet);
++                    }
++                }
++            } else {
++                panic("i = %d \n", i);
++            }
++#else
++			tasklet_schedule(&ftchan->tasklet);
++#endif /* CONFIG_PLATFORM_GM8210 */
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftdmac030_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftdmac030_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++	bool busy;
++
++	desc = container_of(txd, struct ftdmac030_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	spin_lock_bh(&ftchan->lock);
++
++	cookie = ftdmac030_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list))
++		busy = false;
++	else
++		busy = true;
++
++	list_add_tail(&desc->node, &ftchan->active_list);
++
++#if 0   /* Harry, move to issue pending. If we start the transaction here, it will have potential
++         * chance to lose the LLP due to race condition between CPU and hardware.
++         */
++	/* start ASAP */
++	if (!busy)
++		ftdmac030_start_chain(desc);
++#endif
++
++	spin_unlock_bh(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftdmac030_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftdmac030_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac030_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftdmac030_desc *desc;
++
++		desc = ftdmac030_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	spin_lock_bh(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list);
++	ftchan->completed_cookie = chan->cookie = 1;
++	spin_unlock_bh(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftdmac030_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftdmac030_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_desc *tmp;
++	struct ftdmac030 *ftdmac030;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++	ftdmac030 = ftchan->ftdmac030;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(ftdmac030_chan_is_enabled(ftchan));
++
++	spin_lock_bh(&ftchan->lock);
++	ftdmac030_stop_channel(ftchan);
++	ftdmac030_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftdmac030_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/**
++ * ftdmac030_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac030_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++		dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((src >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect src physical address 0x%x \n", __func__, src);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 7)) {
++		shift = 3;
++	} else if (!((src | dest | len) & 3)) {
++		shift = 2;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++	} else {
++		shift = 0;
++	}
++
++	desc = ftdmac030_create_chain(ftchan, NULL, src, dest, len,
++		shift, 0, 0);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMCPY;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac030_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @value: the given value for memset used
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac030_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest,
++		int value, size_t len, unsigned long flags)
++{
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s(dest %x, value %x, len %x)\n",
++		__func__, dest, value, len);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(len & 3)) {
++		dev_info(chan2dev(chan), "%s: length isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(dest & 3)) {
++		dev_info(chan2dev(chan), "%s: dest addr isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	desc = ftdmac030_create_chain(ftchan, NULL, 0, dest, len,
++		2, 1, value);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMSET;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac030_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac030_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++		unsigned int sg_len, enum dma_transfer_direction direction,
++		unsigned long flags)
++{
++	struct ftdmac030_dma_slave *slave = chan->private;
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int shift;
++	unsigned int i;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		shift = 2;
++		break;
++	case DMA_SLAVE_BUSWIDTH_8_BYTES:
++		shift = 3;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++	switch (direction) {
++	case DMA_TO_DEVICE:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac030_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftdmac030_create_chain(ftchan, desc,
++				mem, slave->common.dst_addr, len,
++				shift, 0, 1);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC030_CFG_DST_HANDSHAKE_EN
++				| FTDMAC030_CFG_DST_HANDSHAKE(slave->handshake);
++		break;
++	case DMA_FROM_DEVICE:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac030_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftdmac030_create_chain(ftchan, desc,
++				slave->common.src_addr, mem, len,
++				shift, 1, 0);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC030_CFG_SRC_HANDSHAKE_EN
++				| FTDMAC030_CFG_SRC_HANDSHAKE(slave->handshake);
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n",
++			__func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_SLAVE;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftdmac030_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++		unsigned long arg)
++{
++	int ret = -ENXIO;
++	struct ftdmac030_chan *ftchan;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++#if 0
++	/* Only supports DMA_TERMINATE_ALL */
++	if (cmd != DMA_TERMINATE_ALL)
++		return -ENXIO;
++#endif
++
++	if (cmd == DMA_SLAVE_CONFIG) {
++		struct dma_slave_config *slave_config = (struct dma_slave_config *)arg;
++		struct ftdmac030_dma_slave  *dma_slave;
++
++		dma_slave = container_of(slave_config, struct ftdmac030_dma_slave, common);
++		chan->private = dma_slave;
++		ret = 0;
++	}
++
++	if (cmd == DMA_TERMINATE_ALL) {
++		/*
++		 * This is only called when something went wrong elsewhere, so
++		 * we don't really care about the data. Just disable the channel.
++		 */
++		spin_lock_bh(&ftchan->lock);
++		ftdmac030_stop_channel(ftchan);
++		ftdmac030_finish_all_chains(ftchan);
++		ftchan->transaction_type = DMA_TX_TYPE_END;
++		spin_unlock_bh(&ftchan->lock);
++	}
++	return ret;
++}
++
++/**
++ * ftdmac030_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftdmac030_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		struct dma_tx_state *txstate)
++{
++	struct ftdmac030_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftdmac030_issue_pending - try to finish work
++ * @chan: target DMA channel
++ */
++static void ftdmac030_issue_pending(struct dma_chan *chan)
++{
++	struct ftdmac030_chan *ftchan;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	spin_lock_bh(&ftchan->lock);
++	BUG_ON(list_empty(&ftchan->active_list));
++	/* get first descriptor and go */
++	ftdmac030_start_new_chain(ftchan);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftdmac030_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftdmac030 *ftdmac030;
++	struct dma_device *dma;
++	int irq;
++	int i;
++	int err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftdmac030 = kzalloc(sizeof(*ftdmac030), GFP_KERNEL);
++	if (!ftdmac030) {
++		return -ENOMEM;
++	}
++
++	dma = &ftdmac030->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftdmac030);
++	ftdmac030->id = pdev->id;
++
++	/* map io memory */
++
++	ftdmac030->res = request_mem_region(res->start, res->end - res->start + 1,
++			dev_name(&pdev->dev));
++	if (ftdmac030->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftdmac030->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftdmac030->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* create a pool of consistent memory blocks for hardware descriptors */
++	ftdmac030->dma_desc_pool = dma_pool_create("ftdmac030_desc_pool",
++			&pdev->dev, sizeof(struct ftdmac030_desc),
++			8 /* double word alignment */, 0);
++	if (!ftdmac030->dma_desc_pool) {
++		dev_err(&pdev->dev, "No memory for descriptor pool\n");
++		err = -ENOMEM;
++		goto err_pool_create;
++	}
++
++	/* initialize channels */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device	= dma;
++		ftchan->common.cookie	= DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftdmac030		= ftdmac030;
++		ftchan->completed_cookie	= DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftdmac030_tasklet,
++				(unsigned long)ftchan);
++		list_add_tail(&ftchan->common.device_node, &dma->channels);
++	}
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftdmac030_alloc_chan_resources;
++	dma->device_free_chan_resources	= ftdmac030_free_chan_resources;
++	dma->device_prep_dma_memcpy	= ftdmac030_prep_dma_memcpy;
++	dma->device_prep_dma_memset	= ftdmac030_prep_dma_memset;
++	dma->device_prep_slave_sg	= ftdmac030_prep_slave_sg;
++	dma->device_control		= ftdmac030_control;
++	dma->device_tx_status		= ftdmac030_tx_status;
++	dma->device_issue_pending	= ftdmac030_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
++	dma_cap_set(DMA_MEMSET, dma->cap_mask);
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);
++
++	err = request_irq(irq, ftdmac030_interrupt, IRQF_SHARED, pdev->name, ftdmac030);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_req_irq;
++	}
++	ftdmac030->irq = irq;
++
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	dev_info(&pdev->dev,
++		"DMA engine driver: irq %d, mapped at %p\n",
++		irq, ftdmac030->base);
++	
++    /* sync dma_req */
++    iowrite32(0xFF, ftdmac030->base + FTDMAC030_OFFSET_SYNC);
++    
++	return 0;
++
++err_register:
++	free_irq(irq, ftdmac030);
++err_req_irq:
++	dma_pool_destroy(ftdmac030->dma_desc_pool);
++err_pool_create:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftdmac030->base);
++err_ioremap:
++	release_resource(ftdmac030->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac030);
++	return err;
++}
++
++static int __exit ftdmac030_remove(struct platform_device *pdev)
++{
++	struct ftdmac030 *ftdmac030;
++	int i;
++
++	ftdmac030 = platform_get_drvdata(pdev);
++
++	dma_async_device_unregister(&ftdmac030->dma);
++
++	free_irq(ftdmac030->irq, ftdmac030);
++	dma_pool_destroy(ftdmac030->dma_desc_pool);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftdmac030->base);
++	release_resource(ftdmac030->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac030);
++	return 0;
++}
++
++/**
++ * ftdmac030_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac030_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac030_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id))
++{
++    if (platform_chan_filter != NULL) {
++        printk("%s, platform_chan_filter was registered already! \n", __func__);
++        return -1;
++    }
++
++    platform_chan_filter = chan_filter_fn;
++
++    return 0;
++}
++
++/* proc function
++ */
++static struct proc_dir_entry *sw_int_proc = NULL;
++
++ /* sw interrupt info
++  */
++static int proc_read_swint_stats(char *page, char **start, off_t off, int count, int *eof,
++                                    void *data)
++{
++    int i, len = 0;
++
++    for (i = 0; i < ARRAY_SIZE(dmac030_sw_intr); i ++)
++        len += sprintf(page + len, "sw_int[%d] = %d \n", i, dmac030_sw_intr[i]);
++
++    return len;
++}
++
++static void ftdmac030_proc_init(void)
++{
++    struct proc_dir_entry *p;
++
++    p = create_proc_entry("dmac030", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (p == NULL) {
++        panic("error in %s \n", __func__);
++    }
++
++    /*
++     * sw interruupt counter
++     */
++    sw_int_proc = create_proc_entry("sw_int", S_IRUGO, p);
++    if (sw_int_proc == NULL)
++        panic("DMAC030: Fail to create proc sw_int!\n");
++
++    sw_int_proc->read_proc = (read_proc_t *) proc_read_swint_stats;
++}
++
++/* driver
++ */
++static struct platform_driver ftdmac030_driver = {
++	.probe		= ftdmac030_probe,
++	.remove		= __exit_p(ftdmac030_remove),
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftdmac030_init(void)
++{
++#ifdef CONFIG_PLATFORM_GM8210
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id != FMEM_CPU_FA726)
++        return 0;
++#endif
++
++    ftdmac030_proc_init();
++
++	return platform_driver_register(&ftdmac030_driver);
++}
++
++static void __exit ftdmac030_exit(void)
++{
++	platform_driver_unregister(&ftdmac030_driver);
++}
++
++module_init(ftdmac030_init);
++module_exit(ftdmac030_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTDMAC030 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-Duo/ftintc010.c b/arch/arm/mach-GM-Duo/ftintc010.c
+new file mode 100644
+index 00000000..baee7dcb
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/ftintc010.c
+@@ -0,0 +1,435 @@
++/*
++ *  linux/arch/arm/mach-GM-Duo/ftintc010.c
++ *
++ *  Faraday FTINTC010 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++
++#include <asm/mach/irq.h>
++#include <mach/ftintc010.h>
++#include <mach/ftintc030.h>
++
++#ifndef MAX_FTINTC010_NR
++#define MAX_FTINTC010_NR	1
++#endif
++
++static struct ftintc010_chip_data ftintc010_data[MAX_FTINTC010_NR];
++static DEFINE_SPINLOCK(ftintc010_lock);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline void __iomem *ftintc010_base(unsigned int irq)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_chip_data(irq);
++
++	return chip_data->base;
++}
++
++/*
++ * return hardware irq number
++ */
++static inline unsigned int ftintc010_irq(unsigned int irq)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_chip_data(irq);
++
++	return irq - chip_data->irq_offset;
++}
++
++static inline void ftintc010_clear_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	if (hw_irq < 32) {
++		mask = 1 << hw_irq;
++
++		writel(mask, base + FTINTC010_OFFSET_IRQCLEAR);
++	} else {
++		mask = 1 << (hw_irq - 32);
++		writel(mask, base + FTINTC010_OFFSET_IRQCLEAREX);
++	}
++}
++
++static inline void ftintc010_mask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	if (hw_irq < 32) {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASK);
++		mask &= ~(1 << hw_irq);
++		writel(mask, base + FTINTC010_OFFSET_IRQMASK);
++	} else {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASKEX);
++		mask &= ~(1 << (hw_irq - 32));
++		writel(mask, base + FTINTC010_OFFSET_IRQMASKEX);
++	}
++}
++
++static inline void ftintc010_unmask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	if (hw_irq < 32) {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASK);
++		mask |= 1 << hw_irq;
++		writel(mask, base + FTINTC010_OFFSET_IRQMASK);
++	} else {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASKEX);
++		mask |= 1 << (hw_irq - 32);
++		writel(mask, base + FTINTC010_OFFSET_IRQMASKEX);
++	}
++}
++
++/******************************************************************************
++ * struct irq_chip functions
++ *****************************************************************************/
++static inline void ftintc010_set_trig_mode(void __iomem *base, unsigned int hw_irq, int mode)
++{
++	unsigned int irqmode, fiqmode;
++
++	/*
++	 * 0: level trigger
++	 * 1: edge trigger
++	 */
++	if (hw_irq < 32) {
++		irqmode = readl(base + FTINTC010_OFFSET_IRQMODE);
++		if (mode)
++			irqmode |= 1 << hw_irq;
++		else
++			irqmode &= ~(1 << hw_irq);
++		writel(irqmode, base + FTINTC010_OFFSET_IRQMODE);
++	} else {
++		irqmode = readl(base + FTINTC010_OFFSET_IRQMODEEX);
++		if (mode)
++			irqmode |= 1 << (hw_irq - 32);
++		else
++			irqmode &= ~(1 << (hw_irq - 32));
++		writel(irqmode, base + FTINTC010_OFFSET_IRQMODEEX);
++	}
++
++	/* fiq */
++	if (hw_irq < 32) {
++	    fiqmode = readl(base + FTINTC010_OFFSET_FIQMODE);
++		if (mode)
++			fiqmode |= 1 << hw_irq;
++		else
++			fiqmode &= ~(1 << hw_irq);
++		writel(fiqmode, base + FTINTC010_OFFSET_FIQMODE);
++	} else {
++	    fiqmode = readl(base + FTINTC010_OFFSET_FIQMODEEX);
++		if (mode)
++			fiqmode |= 1 << (hw_irq - 32);
++		else
++			fiqmode &= ~(1 << (hw_irq - 32));
++		writel(fiqmode, base + FTINTC010_OFFSET_FIQMODEEX);
++	}
++}
++
++static inline void ftintc010_set_trig_level(void __iomem *base, unsigned int hw_irq, int level)
++{
++	unsigned int irqlevel, fiqlevel;
++
++	/*
++	 * 0: active-high level trigger / rising edge trigger
++	 * 1: active-low level trigger / falling edge trigger
++	 */
++	if (hw_irq < 32) {
++		irqlevel = readl(base + FTINTC010_OFFSET_IRQLEVEL);
++		if (level)
++			irqlevel |= 1 << hw_irq;
++		else
++			irqlevel &= ~(1 << hw_irq);
++		writel(irqlevel, base + FTINTC010_OFFSET_IRQLEVEL);
++	} else {
++		irqlevel = readl(base + FTINTC010_OFFSET_IRQLEVELEX);
++		if (level)
++			irqlevel |= 1 << (hw_irq - 32);
++		else
++			irqlevel &= ~(1 << (hw_irq - 32));
++		writel(irqlevel, base + FTINTC010_OFFSET_IRQLEVELEX);
++	}
++
++	/* fiq */
++	if (hw_irq < 32) {
++		fiqlevel = readl(base + FTINTC010_OFFSET_FIQLEVEL);
++		if (level)
++			fiqlevel |= 1 << hw_irq;
++		else
++			fiqlevel &= ~(1 << hw_irq);
++		writel(irqlevel, base + FTINTC010_OFFSET_FIQLEVEL);
++	} else {
++		fiqlevel = readl(base + FTINTC010_OFFSET_FIQLEVELEX);
++		if (level)
++			fiqlevel |= 1 << (hw_irq - 32);
++		else
++			irqlevel &= ~(1 << (hw_irq - 32));
++		writel(fiqlevel, base + FTINTC010_OFFSET_FIQLEVELEX);
++	}
++}
++
++static int ftintc010_set_type(struct irq_data *data, unsigned int type)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++	int mode = 0;
++	int level = 0;
++
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_LEVEL_HIGH:
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_EDGE_RISING:
++		mode = 1;
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_set_trig_mode(base, hw_irq, mode);
++	ftintc010_set_trig_level(base, hw_irq, level);
++	spin_unlock(&ftintc010_lock);
++	return 0;
++}
++/*
++ * Edge trigger IRQ chip methods
++ */
++static void ftintc010_edge_ack(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_clear_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static void ftintc010_mask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_mask_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static void ftintc010_unmask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_unmask_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static struct irq_chip ftintc010_edge_chip = {
++	.irq_ack	= ftintc010_edge_ack,
++	.irq_mask	= ftintc010_mask,
++	.irq_unmask	= ftintc010_unmask,
++	.irq_set_type	= ftintc010_set_type,
++};
++
++/*
++ * Level trigger IRQ chip methods
++ */
++static void ftintc010_level_ack(struct irq_data *data)
++{
++	/* do nothing */
++	if (data)   {}
++}
++
++static struct irq_chip ftintc010_level_chip = {
++	.irq_ack	= ftintc010_level_ack,
++	.irq_mask	= ftintc010_mask,
++	.irq_unmask	= ftintc010_unmask,
++	.irq_set_type	= ftintc010_set_type,
++};
++
++/******************************************************************************
++ * initialization functions
++ *****************************************************************************/
++static void ftintc010_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_handler_data(irq);
++	struct irq_chip *chip = irq_get_chip(irq);
++	unsigned int cascade_irq, hw_irq;
++	unsigned long status;
++
++	/* defined in asm/mach/irq.h.
++	 * mask the primary's irq.
++	 */
++	chained_irq_enter(chip, desc);
++
++	status = readl(chip_data->base + FTINTC010_OFFSET_IRQSTATUS);
++
++	if (status) {
++		hw_irq = ffs(status) - 1;
++	} else {
++		status = readl(chip_data->base + FTINTC010_OFFSET_IRQSTATUSEX);
++
++		if (!status)
++			goto out;
++
++		hw_irq = ffs(status) - 1 + 32;
++	}
++
++	cascade_irq = hw_irq + chip_data->irq_offset;
++	generic_handle_irq(cascade_irq);
++
++out:
++	/* primary controller unmasking */
++	chained_irq_exit(chip, desc);
++}
++
++/* reconfigure the irq type. Maybe the original is edge trigger, now change to level trigger
++ * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
++ */
++int ftintc010_set_irq_type(unsigned int irq, unsigned int type)
++{
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++	case IRQ_TYPE_LEVEL_HIGH:
++		irq_set_chip(irq, &ftintc010_level_chip);
++		irq_set_handler(irq, handle_level_irq);
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++	case IRQ_TYPE_EDGE_RISING:
++		irq_set_chip(irq, &ftintc010_edge_chip);
++		irq_set_handler(irq, handle_edge_irq);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++    /* kernel function */
++	return irq_set_irq_type(irq, type);
++}
++
++/*
++ * Initialization of master interrupt controller, after this INTC is
++ * enabled, the rest of Linux initialization codes can then be completed.
++ * For example, timer interrupts and UART interrupts must be enabled during
++ * the boot process.
++ */
++void __init ftintc010_init(unsigned int ftintc010_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc010_trigger_type *trigger_type)
++{
++	int irq;
++	int i;
++
++	if (ftintc010_nr >= MAX_FTINTC010_NR)
++		BUG();
++
++	ftintc010_data[ftintc010_nr].base = base;
++	ftintc010_data[ftintc010_nr].irq_offset = irq_start;
++
++	/*
++	 * mask all interrupts
++	 */
++	writel(0, base + FTINTC010_OFFSET_IRQMASK);
++	writel(0, base + FTINTC010_OFFSET_FIQMASK);
++	writel(~0, base + FTINTC010_OFFSET_IRQCLEAR);
++	writel(~0, base + FTINTC010_OFFSET_FIQCLEAR);
++
++	writel(0, base + FTINTC010_OFFSET_IRQMASKEX);
++	writel(~0, base + FTINTC010_OFFSET_IRQCLEAREX);
++	writel(0, base + FTINTC010_OFFSET_FIQMASKEX);
++	writel(~0, base + FTINTC010_OFFSET_FIQCLEAREX);
++
++	/*
++	 * setup trigger mode and level
++	 */
++	writel(trigger_type->irqmode, base + FTINTC010_OFFSET_IRQMODE);
++	writel(trigger_type->irqlevel, base + FTINTC010_OFFSET_IRQLEVEL);
++	writel(trigger_type->fiqmode, base + FTINTC010_OFFSET_FIQMODE);
++	writel(trigger_type->fiqlevel, base + FTINTC010_OFFSET_FIQLEVEL);
++#ifdef CONFIG_FTINTC010EX
++	writel(trigger_type->irqmodeex, base + FTINTC010_OFFSET_IRQMODEEX);
++	writel(trigger_type->irqlevelex, base + FTINTC010_OFFSET_IRQLEVELEX);
++	writel(trigger_type->fiqmodeex, base + FTINTC010_OFFSET_FIQMODEEX);
++	writel(trigger_type->fiqlevelex, base + FTINTC010_OFFSET_FIQLEVELEX);
++#endif
++
++	/*
++	 * setup the linux irq subsystem.
++	 * Note: for FIQ subsystem, it not supported in linux. Instead, we have own FIQ subsystem.
++	 */
++	irq = irq_start;
++	for (i = 0; i < 32; i++) {
++		if (trigger_type->irqmode & (1 << i)) {
++		    irq_set_chip(irq, &ftintc010_edge_chip);
++			irq_set_handler(irq, handle_edge_irq);
++		} else {
++		    irq_set_chip(irq, &ftintc010_level_chip);
++			irq_set_handler(irq, handle_level_irq);
++		}
++
++		irq_set_chip_data(irq, &ftintc010_data[ftintc010_nr]);
++		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++		irq++;
++	}
++
++#ifdef CONFIG_FTINTC010EX
++    /* keep irq number counting up */
++	for (i = 0; i < 32; i++) {
++		if (trigger_type->irqmodeex & (1 << i)) {
++			irq_set_chip(irq, &ftintc010_edge_chip);
++			irq_set_handler(irq, handle_edge_irq);
++		} else {
++			irq_set_chip(irq, &ftintc010_level_chip);
++			irq_set_handler(irq, handle_level_irq);
++		}
++
++		irq_set_chip_data(irq, &ftintc010_data[ftintc010_nr]);
++		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++		irq++;
++	}
++#endif
++
++#ifdef CONFIG_GM8312
++    /* handle 8312 irq */
++    ftintc030_setup_chain_irq(0, EXT_INT_0_IRQ, ftintc010_handle_cascade_irq, &ftintc010_data[0]);
++#endif
++}
+diff --git a/arch/arm/mach-GM-Duo/ftintc030.c b/arch/arm/mach-GM-Duo/ftintc030.c
+new file mode 100644
+index 00000000..8e8f754b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/ftintc030.c
+@@ -0,0 +1,386 @@
++/*
++ *  linux/arch/arm/mach-GM-Duo/FTINTC030.c
++ *
++ *  Faraday FTINTC030 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++#include <asm/cputype.h>
++
++#include <asm/mach/irq.h>
++#include <mach/ftintc030.h>
++
++struct ftintc030_chip_data {
++	unsigned int irq_offset;
++	void __iomem *base;
++};
++
++#ifndef MAX_FTINTC030_NR
++#define MAX_FTINTC030_NR	1
++#endif
++
++static struct ftintc030_chip_data ftintc030_data[MAX_FTINTC030_NR];
++static DEFINE_SPINLOCK(ftintc030_lock);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++static inline void __iomem *ftintc030_base(unsigned int irq)
++{
++	struct ftintc030_chip_data *chip_data = irq_get_chip_data(irq);
++
++	return chip_data->base;
++}
++
++/*
++ * return hardware irq number
++ */
++static inline unsigned int ftintc030_irq(unsigned int irq)
++{
++	struct ftintc030_chip_data *chip_data = irq_get_chip_data(irq);
++
++	return irq - chip_data->irq_offset;
++}
++
++static inline void ftintc030_clear_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	mask = 1 << (hw_irq % 32);
++	if (hw_irq < 64)
++		writel(mask, base + FTINTC030_OFFSET_IRQCLEAR + (0x20 * (hw_irq / 32)));
++	else
++		writel(mask, base + FTINTC030_OFFSET_IRQCLEAR + (0x20 * ((hw_irq / 32) + 1)));
++}
++
++static inline void ftintc030_mask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int target_base, value;
++    int i = 0;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++    if (get_cpu_id() == 0x726)
++        target_base = (u32)base + FTINTC030_OFFSET_CPU_0_IRQ + (hw_irq >> 5) * 4;
++    else
++        target_base = (u32)base + FTINTC030_OFFSET_CPU_1_IRQ + (hw_irq >> 5) * 4;
++    value = readl(target_base);
++    value &= ~(1 << (hw_irq % 32));
++    writel(value, target_base);
++
++    /* FIXME: work around for IC bug */
++    while (readl(target_base) != value) {
++        writel(value, target_base);
++        i ++;
++        if (i > 10) {
++            printk("%s, ERROR! \n", __func__);
++            break;
++        }
++    }
++}
++
++static inline void ftintc030_unmask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int target_base, value;
++    int i = 0;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++    if (get_cpu_id() == 0x726)
++	    target_base = (u32)base + FTINTC030_OFFSET_CPU_0_IRQ + (hw_irq >> 5) * 4;
++    else
++        target_base = (u32)base + FTINTC030_OFFSET_CPU_1_IRQ + (hw_irq >> 5) * 4;
++    value = readl(target_base);
++    value |= (1 << (hw_irq % 32));
++    writel(value, target_base);
++
++    /* FIXME: work around for IC bug */
++    while (readl(target_base) != value) {
++        writel(value, target_base);
++        i ++;
++        if (i > 10) {
++            printk("%s, ERROR! \n", __func__);
++            break;
++        }
++    }
++}
++
++/******************************************************************************
++ * struct irq_chip functions
++ *****************************************************************************/
++static inline void ftintc030_set_trig_mode(void __iomem *base, unsigned int hw_irq, int mode)
++{
++	unsigned int irqmode, reg_offset;
++
++	/*
++	 * 0: level trigger
++	 * 1: edge trigger
++	 */
++	if (hw_irq < 64)
++	    reg_offset = 0x20 * (hw_irq >> 5);
++	else
++	    reg_offset = 0x20 * ((hw_irq >> 5) + 1);
++	    	 
++	irqmode = readl(base + FTINTC030_OFFSET_IRQMODE + reg_offset);
++
++	if(mode)
++    	irqmode |= 1 << (hw_irq % 32);
++    else
++    	irqmode &= ~(1 << (hw_irq % 32));
++
++	writel(irqmode, base + FTINTC030_OFFSET_IRQMODE + reg_offset);
++}
++
++static inline void ftintc030_set_trig_level(void __iomem *base, unsigned int hw_irq, int level)
++{
++	unsigned int irqlevel, reg_offset;
++
++	/*
++	 * 0: active-high level trigger / rising edge trigger
++	 * 1: active-low level trigger / falling edge trigger
++	 */
++	if (hw_irq < 64)
++	    reg_offset = 0x20 * (hw_irq >> 5);
++	else
++	    reg_offset = 0x20 * ((hw_irq >> 5) + 1);
++	        	    
++	irqlevel = readl(base + FTINTC030_OFFSET_IRQLEVEL + reg_offset);
++	
++	if(level)
++    	irqlevel |= 1 << (hw_irq % 32);
++    else
++    	irqlevel &= ~(1 << (hw_irq % 32));
++    	
++	writel(irqlevel, base + FTINTC030_OFFSET_IRQLEVEL + reg_offset);
++}
++
++static int ftintc030_set_type(struct irq_data *data, unsigned int type)
++{
++	unsigned int hw_irq = ftintc030_irq(data->irq);
++	void __iomem *base = ftintc030_base(data->irq);
++	int mode = 0;
++	int level = 0;
++
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_LEVEL_HIGH:
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_EDGE_RISING:
++		mode = 1;
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	spin_lock(&ftintc030_lock);
++	ftintc030_set_trig_mode(base, hw_irq, mode);
++	ftintc030_set_trig_level(base, hw_irq, level);
++	spin_unlock(&ftintc030_lock);
++	return 0;
++}
++/*
++ * Edge trigger IRQ chip methods
++ */
++static void ftintc030_edge_ack(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc030_irq(data->irq);
++	void __iomem *base = ftintc030_base(data->irq);
++
++	spin_lock(&ftintc030_lock);
++	ftintc030_clear_irq(base, hw_irq);
++	spin_unlock(&ftintc030_lock);
++}
++
++static void ftintc030_mask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc030_irq(data->irq);
++	void __iomem *base = ftintc030_base(data->irq);
++
++	spin_lock(&ftintc030_lock);
++	ftintc030_mask_irq(base, hw_irq);
++	spin_unlock(&ftintc030_lock);
++}
++
++static void ftintc030_unmask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc030_irq(data->irq);
++	void __iomem *base = ftintc030_base(data->irq);
++
++	spin_lock(&ftintc030_lock);
++	ftintc030_unmask_irq(base, hw_irq);
++	spin_unlock(&ftintc030_lock);
++}
++
++static struct irq_chip ftintc030_edge_chip = {
++	.irq_ack	= ftintc030_edge_ack,
++	.irq_mask	= ftintc030_mask,
++	.irq_unmask	= ftintc030_unmask,
++	.irq_set_type	= ftintc030_set_type,
++};
++
++/*
++ * Level trigger IRQ chip methods
++ */
++static void ftintc030_level_ack(struct irq_data *data)
++{
++	/* do nothing */
++	if (data)   {}
++}
++
++static struct irq_chip ftintc030_level_chip = {
++	.irq_ack	= ftintc030_level_ack,
++	.irq_mask	= ftintc030_mask,
++	.irq_unmask	= ftintc030_unmask,
++	.irq_set_type	= ftintc030_set_type,
++};
++
++/******************************************************************************
++ * initialization functions
++ *****************************************************************************/
++/* reconfigure the irq type. Maybe the original is edge trigger, now change to level trigger
++ * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
++ */
++int ftintc030_set_irq_type(unsigned int irq, unsigned int type)
++{
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++	case IRQ_TYPE_LEVEL_HIGH:
++		irq_set_chip(irq, &ftintc030_level_chip);
++		irq_set_handler(irq, handle_level_irq);
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++	case IRQ_TYPE_EDGE_RISING:
++		irq_set_chip(irq, &ftintc030_edge_chip);
++		irq_set_handler(irq, handle_edge_irq);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++    /* kernel function */
++	return irq_set_irq_type(irq, type);
++}
++
++/*
++ * Initialization of master interrupt controller, after this INTC is
++ * enabled, the rest of Linux initialization codes can then be completed.
++ * For example, timer interrupts and UART interrupts must be enabled during
++ * the boot process.
++ */
++void __init ftintc030_init(unsigned int ftintc030_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc030_trigger_type *trigger_type)
++{
++	int irq;
++	int i, j, offset;
++
++	if (ftintc030_nr >= MAX_FTINTC030_NR)
++		BUG();
++
++	ftintc030_data[ftintc030_nr].base = base;
++	ftintc030_data[ftintc030_nr].irq_offset = irq_start;
++
++	irq = irq_start;
++	/*
++	 * mask all interrupts
++	 */
++	for(i = 0; i < PLATFORM_IRQ_TOTALCOUNT / 32; i++) {
++	    if(i >= 2)
++		    offset = 0x20 * (i + 1);
++	    else
++		    offset = 0x20 * i;
++
++        if (get_cpu_id() == 0x726) { //only allow master cpu to configure this
++    	    writel(0xFFFFFFFF, base + FTINTC030_OFFSET_IRQENABLE + offset);   //ENABLE register
++    	    writel(~0, base + FTINTC030_OFFSET_IRQCLEAR + offset);
++
++    	    /*
++    	     * setup trigger mode and level
++    	     */
++      	    writel(trigger_type->irqmode[i], base + FTINTC030_OFFSET_IRQMODE + offset);
++      	    writel(trigger_type->irqlevel[i], base + FTINTC030_OFFSET_IRQLEVEL + offset);
++      	    writel(trigger_type->fiqmode[i], base + FTINTC030_OFFSET_IRQMODE + offset);
++      	    writel(trigger_type->fiqlevel[i], base + FTINTC030_OFFSET_IRQLEVEL + offset);
++        }
++
++  	    /*
++  	     * setup the linux irq subsystem.
++  	     * Note: for FIQ subsystem, it not supported in linux. Instead, we have own FIQ subsystem.
++  	     */
++
++  	    for (j = 0; j < 32; j++) {
++    		if (trigger_type->irqmode[i] & (1 << j)) {
++    		    irq_set_chip(irq, &ftintc030_edge_chip);
++    			irq_set_handler(irq, handle_edge_irq);
++    		} else {
++    		    irq_set_chip(irq, &ftintc030_level_chip);
++    			irq_set_handler(irq, handle_level_irq);
++    		}
++
++    		irq_set_chip_data(irq, &ftintc030_data[ftintc030_nr]);
++    		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++    		irq++;
++	    }
++	}
++}
++
++/*
++ * Set a highlevel chained flow handler for a given IRQ.
++ * ftintc030_nr: INTC030 index
++ * irq: which irq number is the cascade irq
++ * handler: the handler function of this cascade irq
++ * handler_data: private data of the handler
++ */
++void ftintc030_setup_chain_irq(unsigned int ftintc030_nr, unsigned int irq, void *handler, void *handler_data)
++{
++    if (ftintc030_nr) {}
++
++    if (irq_set_handler_data(irq, handler_data) != 0)
++		panic("%s fail! \n", __func__);
++
++    irq_set_chained_handler(irq, handler);
++}
+diff --git a/arch/arm/mach-GM-Duo/ftpmu010.c b/arch/arm/mach-GM-Duo/ftpmu010.c
+new file mode 100644
+index 00000000..9d1066b5
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/ftpmu010.c
+@@ -0,0 +1,1114 @@
++/*
++ *  Copyright (C) 2010 Grain-Media Technology.
++ *
++ * 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 <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/hardirq.h>
++#include <linux/semaphore.h>
++#include <linux/sched.h>
++#include <asm/io.h>
++#include <linux/proc_fs.h>
++#include <mach/ftpmu010.h>
++
++#define  REG_ARRAY_SZ   30      //Max value for register array
++
++/* Local Variables
++ */
++static u32 fd = 1;
++static struct proc_dir_entry *pmu_proc_root = NULL;
++static struct proc_dir_entry *attribute_proc = NULL;
++static struct proc_dir_entry *regInfo_proc = NULL;
++static struct proc_dir_entry *chipver_proc = NULL;
++
++static ftpmu010_gate_clk_t *pmu_clkgate_tbl = NULL;
++static int (*pmu_ctrl_handler) (u32 cmd, u32 data1, u32 data2) = NULL;
++
++/* Local Functions
++ */
++static int ftpmu010_proc_init(void);
++
++/* MACROs
++ */
++#define ATTR_LIST               ftpmu10.attr_list
++#define REGINFO_LIST            ftpmu10.reginfo_list
++#define LIST_LOCK               spin_lock_irqsave(&ftpmu10.spinlock, flags)
++#define LIST_UNLOCK             spin_unlock_irqrestore(&ftpmu10.spinlock, flags)
++#define REGINFO_OFFSET(x,y)     (x)->pmuReg_info.pRegArray[(y)].reg_off
++#define REGINFO_BITSMASK(x,y)   (x)->pmuReg_info.pRegArray[(y)].bits_mask
++#define REGINFO_LOCKBITS(x,y)   (x)->pmuReg_info.pRegArray[(y)].lock_bits
++#define REGINFO_NAME(x)         (x)->pmuReg_info.name
++#define REGINFO_REGCNT(x)       (x)->pmuReg_info.num
++#define REGINFO_CLKSRC          (x)->pmuReg_info.clock_src
++
++typedef struct {
++    attrInfo_t attr_info;
++    struct list_head list;
++} attrInfo_node_t;
++
++typedef struct {
++    u32 fd;                     /* unique number */
++    pmuRegInfo_t pmuReg_info;
++    struct list_head list;
++    wait_queue_head_t wait_queue;       /* wait queue */
++    int waiting;
++    int ref_cnt;
++} pmuRegInfo_node_t;
++
++/* main structure
++ */
++static struct ftpmu10_s {
++    void __iomem *base;
++#ifdef USE_SEMA
++    struct semaphore sema;
++#else
++    spinlock_t spinlock;
++#endif
++    /* attribute list */
++    struct list_head attr_list;
++    /* register list */
++    struct list_head reginfo_list;
++} ftpmu10;
++
++/* Register a clok node.
++ * return value: 0 for success, < 0 for fail.
++ */
++int ftpmu010_register_attr(attrInfo_t * attr)
++{
++    unsigned long flags;
++    attrInfo_node_t *node;
++    int ret = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        //printk("PMU: %s \n", node->attr_info.name);
++
++        if (node->attr_info.attr_type == attr->attr_type) {
++            ret = -1;
++            break;
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    if (ret < 0)
++        return ret;
++
++    ret = -1;
++    node = kzalloc(sizeof(attrInfo_node_t), GFP_ATOMIC);
++    if (node) {
++        memcpy(&node->attr_info, attr, sizeof(attrInfo_t));
++        INIT_LIST_HEAD(&node->list);
++        list_add_tail(&node->list, &ATTR_LIST);
++        try_module_get(THIS_MODULE);
++        ret = 0;
++    }
++
++    return ret;
++}
++
++/* DeRegister a clok node.
++ * return value: 0 for success, < 0 for fail.
++ */
++int ftpmu010_deregister_attr(attrInfo_t * attr)
++{
++    unsigned long flags;
++    attrInfo_node_t *node, *ne;
++    int ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry_safe(node, ne, &ATTR_LIST, list) {
++        if (node->attr_info.attr_type == attr->attr_type) {
++            list_del_init(&node->list);
++            kfree(node);
++            module_put(THIS_MODULE);
++            ret = 0;
++            break;
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return ret;
++}
++
++/* get the content of the attribute
++ * return value: 0 for fail, > 0 for success
++ */
++unsigned int ftpmu010_get_attr(ATTR_TYPE_T attr_type)
++{
++    attrInfo_node_t *node;
++    unsigned int value = -1;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        if (node->attr_info.attr_type == attr_type) {
++            value = node->attr_info.value;
++            break;
++        }
++    }
++
++    return value;
++}
++
++/* register/de-register the register table
++ * return value:
++ *  give an unique fd if return value >= 0, otherwise < 0 if fail.
++ */
++int ftpmu010_register_reg(pmuRegInfo_t * info)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node, *new_node;
++    int i, j, ret = -1;
++    u32 reg_off;
++
++    /* sanity check */
++    if (unlikely(!strlen(info->name)))
++        return -1;
++
++    /* check if the register offset is duplicated */
++    for (i = 0; i < info->num; i++) {
++        reg_off = info->pRegArray[i].reg_off;
++
++        for (j = 0; j < info->num; j++) {
++            if (i == j)
++                continue;
++
++#if 1                           /* allow gather the mask, lock_bit .... */
++            if (reg_off == info->pRegArray[j].reg_off) {
++                info->pRegArray[i].bits_mask |= info->pRegArray[j].bits_mask;
++                info->pRegArray[i].lock_bits |= info->pRegArray[j].lock_bits;
++                info->pRegArray[i].init_val |= info->pRegArray[j].init_val;
++                info->pRegArray[i].init_mask |= info->pRegArray[j].init_mask;
++            }
++#else
++            if (reg_off == info->pRegArray[j].reg_off) {
++                printk("PMU: reg_offset 0x%x is duplicated! \n", reg_off);
++                return -1;
++            }
++#endif
++        }
++    }
++
++    /* self-test, bits_mask must cover lock_bits and init_val */
++    for (i = 0; i < info->num; i++) {
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].lock_bits) {
++            printk("PMU: %s wrong lock_bits 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].lock_bits, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].init_val) {
++            printk("PMU: %s wrong init_val 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_val, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].init_mask) {
++            printk("PMU: %s wrong init_mask 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_mask, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].init_mask) & info->pRegArray[i].init_val) {
++            printk("PMU: %s wrong init_val 0x%x or init_mask 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_val, info->pRegArray[i].init_mask,
++                   info->pRegArray[i].reg_off);
++            return -1;
++        }
++    }
++
++    if (info->clock_src != ATTR_TYPE_NONE) {
++        if (ftpmu010_get_attr(info->clock_src) < 0) {
++            printk("PMU: %s registers non-existence clock source! \n", info->name);
++            return -1;
++        }
++    }
++
++    /* lock */
++    LIST_LOCK;
++
++    /* 1. check if duplicate registeration
++     */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (!strcmp(REGINFO_NAME(node), info->name)) {
++            /* allow the same node is multiple registered */
++            if ((info->num == REGINFO_REGCNT(node))
++                && !memcmp(info->pRegArray, node->pmuReg_info.pRegArray,
++                           info->num * sizeof(pmuReg_t))) {
++                node->ref_cnt++;
++                /* unlock */
++                LIST_UNLOCK;
++                return node->fd;
++            }
++            printk("PMU: %s was registed already! \n", info->name);
++            goto exit;
++        }
++    }
++
++    /* 2. check if the lockbits is overlap.
++     */
++    for (i = 0; i < info->num; i++) {
++        /* check the registers in each node */
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            for (j = 0; j < REGINFO_REGCNT(node); j++) {
++                if (info->pRegArray[i].reg_off != REGINFO_OFFSET(node, j))
++                    continue;
++
++                if (info->pRegArray[i].lock_bits & REGINFO_LOCKBITS(node, j)) {
++                    printk("PMU: lock_bits of %s is overlapped with %s in offset 0x%x! \n",
++                           info->name, REGINFO_NAME(node), info->pRegArray[i].reg_off);
++                    goto exit;
++                }
++            }                   /* loop j */
++        }
++    }                           /* loop i */
++
++    /* 3. sanity check is ok, create new node and chan it to the list
++     */
++    new_node = kzalloc(sizeof(pmuRegInfo_node_t), GFP_ATOMIC);
++    if (unlikely(!new_node)) {
++        ret = -ENOMEM;
++        goto exit;
++    }
++    new_node->fd = fd++;
++    new_node->ref_cnt = 1;
++    INIT_LIST_HEAD(&new_node->list);
++    memcpy(&new_node->pmuReg_info, info, sizeof(pmuRegInfo_t));
++    if (info->num >= REG_ARRAY_SZ)
++        panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++    new_node->pmuReg_info.pRegArray = kzalloc(REG_ARRAY_SZ * sizeof(pmuReg_t), GFP_ATOMIC);
++    if (unlikely(!new_node->pmuReg_info.pRegArray)) {
++        kfree(new_node);
++        ret = -ENOMEM;
++        goto exit;
++    }
++
++    /* init waitQ */
++    init_waitqueue_head(&new_node->wait_queue);
++
++    /* copy register array body */
++    if (info->num)
++        memcpy(new_node->pmuReg_info.pRegArray, info->pRegArray, info->num * sizeof(pmuReg_t));
++
++    list_add_tail(&new_node->list, &REGINFO_LIST);
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    ret = new_node->fd;
++    try_module_get(THIS_MODULE);
++
++    /* update to hardware */
++    for (i = 0; i < info->num; i++)
++        ftpmu010_write_reg(new_node->fd, info->pRegArray[i].reg_off, info->pRegArray[i].init_val,
++                           info->pRegArray[i].init_mask);
++
++    return ret;
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_deregister_reg(int fd)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node, *ne;
++    int ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry_safe(node, ne, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            if (--node->ref_cnt) {
++                ret = 0;
++                goto exit;
++            }
++            //printk("PMU: %s is deregistered. \n", node->pmuReg_info.name);
++            list_del_init(&node->list);
++            if (node->pmuReg_info.pRegArray)
++                kfree(node->pmuReg_info.pRegArray);
++            kfree(node);
++            module_put(THIS_MODULE);
++            ret = 0;
++            break;
++        }
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* lock/unlock/replace the bits in lock_bits field
++ * return value:
++ *  0 for success, < 0 for fail
++ */
++int ftpmu010_add_lockbits(int fd, unsigned int reg_off, unsigned int lock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    u32 *pLock_bits = NULL;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* do overlap check */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {   /* self check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                pLock_bits = &REGINFO_LOCKBITS(node, i);
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & lock_bits) {
++                    printk("PMU: %s new %#x is out of bits_mask %#x!\n", REGINFO_NAME(node),
++                           lock_bits, REGINFO_BITSMASK(node, i));
++                    goto exit;
++                }
++                ret = 0;
++                break;
++            }                   /* for i */
++        } else {
++            /* conflict check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                if (REGINFO_LOCKBITS(node, i) & lock_bits) {
++                    printk("PMU: %#x conflicts with lock_bits %#x of %s in off: %#x\n", lock_bits,
++                           REGINFO_LOCKBITS(node, i), REGINFO_NAME(node), reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }                       /* fd */
++    }
++
++    if (!ret)
++        *pLock_bits |= lock_bits;
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_del_lockbits(int fd, unsigned int reg_off, unsigned int unlock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            REGINFO_LOCKBITS(node, i) &= ~unlock_bits;
++            ret = 0;
++            break;
++        }
++        break;
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_update_lockbits(int fd, unsigned int reg_off, unsigned int new_lock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    u32 *pLock_bits = NULL;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                pLock_bits = &REGINFO_LOCKBITS(node, i);
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & new_lock_bits) {
++                    printk("PMU: %s new 0x%x is out of bits_mask 0x%x!\n", REGINFO_NAME(node),
++                           new_lock_bits, REGINFO_BITSMASK(node, i));
++                    goto exit;
++                }
++                ret = 0;
++                break;
++            }                   /* for i */
++        } else {
++            /* conflict check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                if (REGINFO_LOCKBITS(node, i) & new_lock_bits) {
++                    printk("PMU: new 0x%x conflicts with lock_bits 0x%x of %s\n", new_lock_bits,
++                           REGINFO_LOCKBITS(node, i), REGINFO_NAME(node));
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }
++    }
++
++    if (!ret)
++        *pLock_bits = new_lock_bits;
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* @int ftpmu010_bits_is_locked(int fd, int reg_off, unsigned int bits)
++ * @Purpose: This function is used to check if the bits are locked by any module or not.
++ * @Parameter:
++ *   reg_off: register offset
++ *   bits: the checked bits
++ * @Return:
++ *      If the any bit in bits is locked, then the returned value will be 0
++ *      otherwise, -1 is returned to indicates all bits are available.
++ *
++ */
++int ftpmu010_bits_is_locked(int fd, unsigned int reg_off, unsigned int bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        /* conflict check */
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            if (REGINFO_LOCKBITS(node, i) & bits) {
++                ret = 0;
++                goto exit;
++            }
++            break;
++        }
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* PMU register read/write
++ */
++unsigned int ftpmu010_read_reg(unsigned int reg_off)
++{
++    return ioread32(ftpmu10.base + reg_off);
++}
++
++/* return value < 0 for fail */
++int ftpmu010_write_reg(int fd, unsigned int reg_off, unsigned int val, unsigned int mask)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* sanity check */
++    if (unlikely(val & (~mask))) {
++        printk("%s: wrong mask:%#x or value:%#x in offset:%#x! \n", __func__, mask, val, reg_off);
++        goto exit;
++    }
++
++    if (unlikely(!mask)) {
++        ret = 0;
++        goto exit;              /* do nothing */
++    }
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            ret = -1;
++            /* check if reg_off had been registered already */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & mask) {
++                    printk("PMU: %s writes with wrong mask 0x%x in off:%#x! \n",
++                           REGINFO_NAME(node), mask, reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                ret = 0;
++            }
++        }
++#if 0                           /* Bug fix, 2011/12/20 11:10�W��
++                                 * We don't need to check if my operation mask conflicts with the lockbits of others
++                                 */
++        else {
++            /* check if the bits is on lock_bits of others */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                /* is lock_bits conflicts with the input mask ? */
++                if (REGINFO_LOCKBITS(node, i) & mask) {
++                    printk("PMU: Wrong mask 0x%x conflicts with %s in off:%#x! \n", mask,
++                           REGINFO_NAME(node), reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }
++#endif
++    }
++
++    if (!ret) {
++        u32 tmp;
++
++        tmp = (ftpmu010_read_reg(reg_off) & (~mask));
++        tmp |= (val & mask);
++        iowrite32(tmp, ftpmu10.base + reg_off);
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++
++    if (ret < 0) {
++        dump_stack();
++        panic("Configure PMU fail! \n");
++    }
++
++    return ret;
++}
++
++/* PMU init function
++ * Input parameters: virtual address of PMU
++ *  tbl: clock gating table for IPs
++ *  pmu_handler: the callback from pmu to reload/reconfigure pmu. NULL if unecessary
++ * Return: 0 for success, < 0 for fail
++ */
++int __init ftpmu010_init(void __iomem * base, ftpmu010_gate_clk_t * tbl, void *pmu_handler)
++{
++    int i = 0;
++    ftpmu010_gate_clk_t *table = tbl;
++
++    ftpmu10.base = base;
++    spin_lock_init(&ftpmu10.spinlock);
++    INIT_LIST_HEAD(&ftpmu10.attr_list);
++    INIT_LIST_HEAD(&ftpmu10.reginfo_list);
++    /* proc function */
++    ftpmu010_proc_init();
++
++    /* self test */
++    while (table->midx != FTPMU_NONE) {
++        for (i = 0; i < table->num; i++) {
++            if (table->reg[i].bit_val & ~table->reg[i].bit_mask)
++                panic("%s, error gating clock table in ofs 0x%x of midx:%d! \n", __func__,
++                      table->reg[i].ofs, table->midx);
++        }
++        table++;
++    }
++
++    pmu_clkgate_tbl = tbl;
++    /* register the callback from pmu */
++    pmu_ctrl_handler = pmu_handler;
++
++    return 0;
++}
++
++/* Purpose: calculate the divisor by input clock
++ * Input: fd, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor(int fd, unsigned int in_clock, int near)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    unsigned int clock = 0;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        clock = ftpmu010_get_attr(node->pmuReg_info.clock_src);
++        if (clock == (u32) - 1)
++            return 0;
++
++        if (near)
++            clock += (in_clock >> 1);
++        /* n = n / base; return rem; */
++        do_div(clock, in_clock);
++        break;
++    }
++
++    LIST_UNLOCK;
++
++    return clock;
++}
++
++/* Purpose: calculate the divisor by input clock attribute
++ * Input: clock_src, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor2(ATTR_TYPE_T clock_src, unsigned int in_clock, int near)
++{
++    unsigned int clock = 0;
++
++    clock = ftpmu010_get_attr(clock_src);
++    if (clock == (u32) - 1)
++        return 0;
++    if (near)
++        clock += (in_clock >> 1);
++    /* n = n / base; return rem; */
++    do_div(clock, in_clock);
++
++    return clock;
++}
++
++/* @Purpose: request the pmu PIN
++ * @Parameter:
++ *      fd: unique identifier
++ *      reg_off: register offset
++ *      req_bits: request registers
++ *      b_wait: 1 for blocking until the resource is available
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_request_pins(int fd, unsigned int reg_off, unsigned int req_bits, int b_wait)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ofs, is_new, ret = 0;
++
++    if (b_wait) {
++        if (in_interrupt() || in_atomic())
++            panic("%s, wrong context in interrupt or atomic \n", __func__);
++    }
++
++    /* lock */
++    LIST_LOCK;
++    if (ftpmu010_bits_is_locked(fd, reg_off, req_bits) == -1) {
++        /* the bits are available */
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            if (node->fd != fd)
++                continue;
++
++            /* check if the offset exists ? */
++            is_new = 1;
++            for (i = 0; i < REGINFO_REGCNT(node); i ++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                REGINFO_BITSMASK(node, i) |= req_bits;
++                REGINFO_LOCKBITS(node, i) |= req_bits;
++                is_new = 0; /* this is not a new offset */
++                break;
++            }
++
++            if (is_new) { /* new node */
++                ofs = REGINFO_REGCNT(node);
++                if (ofs >= REG_ARRAY_SZ)
++                    panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++
++                REGINFO_OFFSET(node, ofs) = reg_off;
++                REGINFO_BITSMASK(node, ofs) = req_bits;
++                REGINFO_LOCKBITS(node, ofs) = req_bits;
++
++                REGINFO_REGCNT(node) ++;
++            }
++            break;
++        }
++    } else {
++        /* the bits are locked by others */
++        if (!b_wait) {
++            ret = -1;
++            goto exit;
++        }
++
++        ret = -1;
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            if (node->fd != fd)
++                continue;
++            ret = 0;
++            break;
++        }
++
++        if (ret == -1)
++            panic("%s, can't find fd in pmu module! \n", __func__);
++
++        node->waiting = 0;
++
++keep_wait:
++        LIST_UNLOCK;
++        wait_event_interruptible(node->wait_queue, node->waiting);
++        if (signal_pending(current))
++			return -ERESTARTSYS;
++        node->waiting = 0;
++
++        LIST_LOCK;
++
++        /* bits are freed */
++        if (ftpmu010_bits_is_locked(fd, reg_off, req_bits) == -1) {
++            ret = -1;
++            /* find the existed offset */
++            for (i = 0; i < REGINFO_REGCNT(node); i ++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                REGINFO_BITSMASK(node, i) |= req_bits;
++                REGINFO_LOCKBITS(node, i) |= req_bits;
++                ret = 0;
++                break;
++            }
++
++            if (ret == -1) {
++                /* new offset */
++                ofs = REGINFO_REGCNT(node);
++                if (ofs >= REG_ARRAY_SZ)
++                    panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++                REGINFO_OFFSET(node, ofs) = reg_off;
++                REGINFO_BITSMASK(node, ofs) = req_bits;
++                REGINFO_LOCKBITS(node, ofs) = req_bits;
++                REGINFO_REGCNT(node) ++;
++                ret = 0;
++            }
++        } else {
++            goto keep_wait;
++        }
++    }
++
++exit:
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* Purpose: release the pmu PIN
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_release_pins(int fd, unsigned int reg_off, unsigned int req_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            if (REGINFO_LOCKBITS(node, i) & req_bits) {
++                REGINFO_BITSMASK(node, i) &= ~req_bits;
++                REGINFO_LOCKBITS(node, i) &= ~req_bits;
++                ret = 0;
++            }
++            break;
++        }
++
++        break;
++    }
++
++    /* wake up the ones who are waiting for the pins */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        node->waiting = 1;
++        wake_up(&node->wait_queue);
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    return ret;
++}
++
++/* Purpose: check if the PINs was requested by others except myself.
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: those pins occupied by others. zero indicates the pin are available.
++ */
++unsigned int ftpmu010_pins_is_requested(int fd, unsigned int reg_off, unsigned int req_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            req_bits &= REGINFO_LOCKBITS(node, i);
++            break;
++        }
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    return req_bits;
++}
++
++/*
++ * This function is used to call pmu handler to reconfigure/reload the pmu setting
++ */
++int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2)
++{
++    int ret = -1;
++
++    if (pmu_ctrl_handler)
++        ret = (*pmu_ctrl_handler) (cmd, data1, data2);
++    else
++        printk("%s, pmu_ctrl_handler is not registered yet! \n", __func__);
++
++    return ret;
++}
++
++/* ------------------------------------------------------------------------------------
++ *  Proc function
++ * ------------------------------------------------------------------------------------
++ */
++
++ /* Attribute info
++  */
++static int proc_read_attribute_info(char *page, char **start, off_t off, int count, int *eof,
++                                    void *data)
++{
++    unsigned long flags;
++    attrInfo_node_t *node;
++    int len = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        len += sprintf(page + len, "Attribute name : %s \n", node->attr_info.name);
++        len += sprintf(page + len, "Attribute type : %d \n", node->attr_info.attr_type);
++        if (node->attr_info.attr_type == ATTR_TYPE_CHIPVER) {
++            len += sprintf(page + len, "Attribute value: 0x%x \n\n", node->attr_info.value);
++        } else {
++            len += sprintf(page + len, "Attribute value: %d \n\n", node->attr_info.value);
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return len;
++}
++
++/* Register info
++ */
++static int proc_read_reginfo(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, len = 0, pos, begin = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        pos = begin + len;
++        if (pos < off) {
++            len = 0;
++            begin = pos;
++        }
++
++        if (pos > off + count)
++            goto exit;
++
++        len +=
++            sprintf(page + len, "name: %s, fd = %d, attribute type = %d \n", REGINFO_NAME(node),
++                    node->fd, node->pmuReg_info.clock_src);
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            len += sprintf(page + len, "    reg_off: 0x%x, bits_mask: 0x%x, lock_bits: 0x%x\n",
++                           REGINFO_OFFSET(node, i), REGINFO_BITSMASK(node, i),
++                           REGINFO_LOCKBITS(node, i));
++        }
++        len += sprintf(page + len, "\n");
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return len;
++
++exit:
++    /* unlock */
++    LIST_UNLOCK;
++
++    *start = page + (off - begin);
++    len -= (off - begin);
++
++    if (len > count)
++        len = count;
++    else if (len < 0)
++        len = 0;
++
++    return len;
++}
++
++/* chip version info
++ */
++static int proc_read_chip_version(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned int value;
++    int len = 0;
++
++    value = ftpmu010_get_attr(ATTR_TYPE_CHIPVER);
++
++    len += sprintf(page + len, "%x\n", value);
++    //len += sprintf(page + len, "#### Hex format, least 4 bytes: 0 for version A, 1 for version B, .... ####\n");
++
++    return len;
++}
++
++static int ftpmu010_proc_init(void)
++{
++    int ret = 0;
++    struct proc_dir_entry *p;
++
++    p = create_proc_entry("pmu", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (p == NULL) {
++        return -ENOMEM;
++    }
++    pmu_proc_root = p;
++    /* pmu_proc_root->data = ;  */
++    /*
++     * attribute
++     */
++    attribute_proc = create_proc_entry("attribute", S_IRUGO, pmu_proc_root);
++    if (attribute_proc == NULL) {
++        printk("PMU: Fail to create proc attribute!\n");
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    attribute_proc->read_proc = (read_proc_t *) proc_read_attribute_info;
++    attribute_proc->write_proc = NULL;
++
++    /*
++     * regInfo
++     */
++    regInfo_proc = create_proc_entry("reginfo", S_IRUGO, pmu_proc_root);
++    if (regInfo_proc == NULL) {
++        printk("PMU: Fail to create proc regInfo!\n");
++        remove_proc_entry(attribute_proc->name, pmu_proc_root);
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    regInfo_proc->read_proc = (read_proc_t *) proc_read_reginfo;
++    regInfo_proc->write_proc = NULL;
++
++    /* IC version, for some AP easy to read */
++    chipver_proc = create_proc_entry("chipver", S_IRUGO, pmu_proc_root);
++    if (chipver_proc == NULL) {
++        printk("PMU: Fail to create proc regInfo!\n");
++        remove_proc_entry(attribute_proc->name, pmu_proc_root);
++        remove_proc_entry(regInfo_proc->name, pmu_proc_root);
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    chipver_proc->read_proc = (read_proc_t *) proc_read_chip_version;
++    chipver_proc->write_proc = NULL;
++
++  end:
++    return ret;
++}
++
++EXPORT_SYMBOL(ftpmu010_register_attr);
++EXPORT_SYMBOL(ftpmu010_deregister_attr);
++EXPORT_SYMBOL(ftpmu010_get_attr);
++EXPORT_SYMBOL(ftpmu010_register_reg);
++EXPORT_SYMBOL(ftpmu010_deregister_reg);
++EXPORT_SYMBOL(ftpmu010_add_lockbits);
++EXPORT_SYMBOL(ftpmu010_del_lockbits);
++EXPORT_SYMBOL(ftpmu010_bits_is_locked);
++EXPORT_SYMBOL(ftpmu010_update_lockbits);
++EXPORT_SYMBOL(ftpmu010_read_reg);
++EXPORT_SYMBOL(ftpmu010_write_reg);
++EXPORT_SYMBOL(ftpmu010_clock_divisor);
++EXPORT_SYMBOL(ftpmu010_request_pins);
++EXPORT_SYMBOL(ftpmu010_release_pins);
++EXPORT_SYMBOL(ftpmu010_pins_is_requested);
++EXPORT_SYMBOL(ftpmu010_pmu_doaction);
++EXPORT_SYMBOL(ftpmu010_clock_divisor2);
++
++MODULE_AUTHOR("Grain-Media");
++MODULE_DESCRIPTION("FTPMU010 core");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-Duo/ftpmu010_pcie.c b/arch/arm/mach-GM-Duo/ftpmu010_pcie.c
+new file mode 100644
+index 00000000..37a061d5
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/ftpmu010_pcie.c
+@@ -0,0 +1,556 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <mach/platform/platform_io.h>
++#include <linux/platform_device.h>
++#include <linux/gfp.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <mach/ftpmu010.h>
++#include <mach/ftpmu010_pcie.h>
++#include <mach/platform/board.h>
++
++#define  REG_ARRAY_SZ   30  //Max value for register array
++
++
++/* Local Variables
++ */
++static u32  fd = 1;
++static struct proc_dir_entry *pmu_proc_root = NULL;
++static struct proc_dir_entry *attribute_proc = NULL;
++static struct proc_dir_entry *regInfo_proc = NULL;
++static ftpmu010_pcie_gate_clk_t  *pmu_clkgate_tbl = NULL;
++static int (*pmu_ctrl_handler)(u32 cmd, u32 data1, u32 data2) = NULL;
++
++/* Local Functions
++ */
++static int ftpmu010_pcie_proc_init(void);
++
++/* MACROs
++ */
++#define ATTR_LIST               ftpmu10_pcie.attr_list
++#define REGINFO_LIST            ftpmu10_pcie.reginfo_list
++#define LIST_LOCK               spin_lock_irqsave(&ftpmu10_pcie.spinlock, flags)
++#define LIST_UNLOCK             spin_unlock_irqrestore(&ftpmu10_pcie.spinlock, flags)
++#define REGINFO_OFFSET(x,y)     (x)->pmuReg_info.pRegArray[(y)].reg_off
++#define REGINFO_BITSMASK(x,y)   (x)->pmuReg_info.pRegArray[(y)].bits_mask
++#define REGINFO_LOCKBITS(x,y)   (x)->pmuReg_info.pRegArray[(y)].lock_bits
++#define REGINFO_NAME(x)         (x)->pmuReg_info.name
++#define REGINFO_REGCNT(x)       (x)->pmuReg_info.num
++#define REGINFO_CLKSRC          (x)->pmuReg_info.clock_src
++
++typedef struct {
++    attrPcieInfo_t      attr_info;
++    struct list_head    list;
++} attrPcieInfo_node_t;
++
++typedef struct {
++    u32                 fd; /* unique number */
++    pmuPcieRegInfo_t    pmuReg_info;
++    struct list_head    list;
++    wait_queue_head_t   wait_queue;     /* wait queue */
++    int	                waiting;
++    int                 ref_cnt;    
++} pmuPcieRegInfo_node_t;
++
++/* main structure
++ */
++static struct ftpmu10_pcie_s
++{
++    void __iomem        *base;
++    spinlock_t          spinlock;
++    /* attribute list */
++    struct list_head    attr_list;
++    /* register list */
++    struct list_head    reginfo_list;
++} ftpmu10_pcie;
++
++/* Register a clok node.
++ * return value: 0 for success, < 0 for fail.
++ */
++int ftpmu010_pcie_register_attr(attrPcieInfo_t *attr)
++{
++    unsigned long       flags;
++    attrPcieInfo_node_t *node;
++    int                 ret = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list)
++    {
++        //printk("PMU: %s \n", node->attr_info.name);
++
++        if (node->attr_info.attr_type == attr->attr_type)
++        {
++            ret = -1;
++            break;
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    if (ret < 0)
++        return ret;
++
++    ret = -1;
++    node = kzalloc(sizeof(attrPcieInfo_node_t), GFP_ATOMIC);
++    if (node)
++    {
++        memcpy(&node->attr_info, attr, sizeof(attrPcieInfo_t));
++        INIT_LIST_HEAD(&node->list);
++        list_add_tail(&node->list, &ATTR_LIST);
++        try_module_get(THIS_MODULE);
++        ret = 0;
++    }
++
++    return ret;
++}
++
++/* DeRegister a clok node.
++ * return value: 0 for success, < 0 for fail.
++ */
++int ftpmu010_pcie_deregister_attr(attrPcieInfo_t *attr)
++{
++    unsigned long flags;
++    attrPcieInfo_node_t  *node, *ne;
++    int     ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry_safe(node, ne, &ATTR_LIST, list)
++    {
++        if (node->attr_info.attr_type == attr->attr_type)
++        {
++            list_del_init(&node->list);
++            kfree(node);
++            module_put(THIS_MODULE);
++            ret = 0;
++            break;
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return ret;
++}
++
++/* get the content of the attribute
++ * return value: 0 for fail, > 0 for success
++ */
++unsigned int ftpmu010_pcie_get_attr(ATTR_PCIE_TYPE_T  attr_type)
++{
++    attrPcieInfo_node_t  *node;
++    unsigned int     value = -1;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list)
++    {
++        if (node->attr_info.attr_type == attr_type)
++        {
++            value = node->attr_info.value;
++            break;
++        }
++    }
++
++    return value;
++}
++
++/* register/de-register the register table
++ * return value:
++ *  give an unique fd if return value >= 0, otherwise < 0 if fail.
++ */
++int ftpmu010_pcie_register_reg(pmuPcieRegInfo_t *info)
++{
++    unsigned long   flags;
++    pmuPcieRegInfo_node_t   *node, *new_node;
++    int     i, j, ret = -1;
++    u32     reg_off;
++
++    /* sanity check */
++    if (unlikely(!strlen(info->name)))
++        return -1;
++
++    /* check if the register offset is duplicated */
++    for (i = 0; i < info->num; i ++)
++    {
++        reg_off = info->pRegArray[i].reg_off;
++
++        for (j = 0; j < info->num; j ++)
++        {
++            if (i == j)
++                continue;
++            if (reg_off == info->pRegArray[j].reg_off)
++            {
++                printk("PMU: reg_offset 0x%x is duplicated! \n", reg_off);
++                return -1;
++            }
++        }
++    }
++
++    /* self-test, bits_mask must cover lock_bits and init_val */
++    for (i = 0; i < info->num; i ++)
++    {
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].lock_bits)
++        {
++            printk("PMU: %s wrong lock_bits! \n", info->name);
++            return -1;
++        }
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].init_val)
++        {
++            printk("PMU: %s wrong init_val! \n", info->name);
++            return -1;
++        }
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].init_mask)
++        {
++            printk("PMU: %s wrong init_mask! \n", info->name);
++            return -1;
++        }
++        if ((~info->pRegArray[i].init_mask) & info->pRegArray[i].init_val)
++        {
++            printk("PMU: %s wrong init_val or init_mask! \n", info->name);
++            return -1;
++        }
++    }
++
++    if (info->clock_src != ATTR_TYPE_PCIE_NONE)
++    {
++        if (ftpmu010_get_attr(info->clock_src) < 0)
++        {
++            printk("PMU: %s registers non-existence clock source! \n", info->name);
++            return -1;
++        }
++    }
++
++    /* lock */
++    LIST_LOCK;
++
++    /* 1. check if duplicate registeration
++     */
++    list_for_each_entry(node, &REGINFO_LIST, list)
++    {
++        if (!strcmp(REGINFO_NAME(node), info->name))
++        {
++            /* allow the same node is multiple registered */
++            if ((info->num == REGINFO_REGCNT(node)) && !memcmp(info->pRegArray, node->pmuReg_info.pRegArray, info->num * sizeof(pmuReg_t)))
++            {
++                node->ref_cnt ++;
++                /* unlock */
++                LIST_UNLOCK;
++                return node->fd;
++            }            
++            printk("PMU: %s was registed already! \n", info->name);
++            goto exit;
++        }
++    }
++
++    /* 2. check if the lockbits is overlap.
++     */
++    for (i = 0; i < info->num; i ++)
++    {
++        /* check the registers in each node */
++        list_for_each_entry(node, &REGINFO_LIST, list)
++        {
++            for (j = 0; j < REGINFO_REGCNT(node); j ++)
++            {
++                if (info->pRegArray[i].reg_off != REGINFO_OFFSET(node, j))
++                    continue;
++
++                if (info->pRegArray[i].lock_bits & REGINFO_LOCKBITS(node, j))
++                {
++                    printk("PMU: lock_bits of %s is overlapped with %s in offset 0x%x! \n",
++                            info->name, REGINFO_NAME(node), info->pRegArray[i].reg_off);
++                    goto exit;
++                }
++            } /* loop j */
++        }
++    } /* loop i */
++
++    /* 3. sanity check is ok, create new node and chan it to the list
++     */
++    new_node = kzalloc(sizeof(pmuPcieRegInfo_node_t), GFP_ATOMIC);
++    if (unlikely(!new_node))
++    {
++        ret = -ENOMEM;
++        goto exit;
++    }
++    new_node->fd = fd++;
++    INIT_LIST_HEAD(&new_node->list);
++    memcpy(&new_node->pmuReg_info, info, sizeof(pmuPcieRegInfo_t));
++    if (info->num >= REG_ARRAY_SZ)
++        panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++    new_node->pmuReg_info.pRegArray = kzalloc(REG_ARRAY_SZ * sizeof(pmuPcieReg_t), GFP_ATOMIC);
++    if (unlikely(!new_node->pmuReg_info.pRegArray))
++    {
++        kfree(new_node);
++        ret = -ENOMEM;
++        goto exit;
++    }
++
++    /* init waitQ */
++    init_waitqueue_head(&new_node->wait_queue);
++
++    /* copy register array body */
++    if (info->num)
++        memcpy(new_node->pmuReg_info.pRegArray, info->pRegArray, info->num * sizeof(pmuPcieReg_t));
++
++    list_add_tail(&new_node->list, &REGINFO_LIST);
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    ret = new_node->fd;
++    try_module_get(THIS_MODULE);
++
++    /* update to hardware */
++    for (i = 0; i < info->num; i ++)
++        ftpmu010_pcie_write_reg(new_node->fd, info->pRegArray[i].reg_off, info->pRegArray[i].init_val, info->pRegArray[i].init_mask);
++
++    return ret;
++
++exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_pcie_deregister_reg(int fd)
++{
++    unsigned long flags;
++    pmuPcieRegInfo_node_t   *node, *ne;
++    int     ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry_safe(node, ne, &REGINFO_LIST, list)
++    {
++        if (node->fd == fd)
++        {
++            if (-- node->ref_cnt) {
++                ret = 0;
++                goto exit;
++            }
++            
++            //printk("PMU: %s is deregistered. \n", node->pmuReg_info.name);
++            list_del_init(&node->list);
++            if (node->pmuReg_info.pRegArray)
++                kfree(node->pmuReg_info.pRegArray);
++            kfree(node);
++            module_put(THIS_MODULE);
++            ret = 0;
++            break;
++        }
++    }
++
++exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* PMU register read/write
++ */
++unsigned int ftpmu010_pcie_read_reg(unsigned int reg_off)
++{
++    return ioread32(ftpmu10_pcie.base + reg_off);
++}
++
++/* return value < 0 for fail */
++int ftpmu010_pcie_write_reg(int fd, unsigned int reg_off, unsigned int val, unsigned int mask)
++{
++    pmuPcieRegInfo_node_t   *node;
++    int                 i, ret = -1;
++
++    /* sanity check */
++    if (unlikely(val & (~mask))) {
++        printk("%s: wrong mask:%#x or value:%#x in offset:%#x! \n", __func__, mask, val, reg_off);
++        goto exit;
++    }
++
++    if (unlikely(!mask)) {
++        ret = 0;
++	    goto exit;	/* do nothing */
++    }
++
++    list_for_each_entry(node, &REGINFO_LIST, list)
++    {
++        if (node->fd == fd)
++        {
++            ret = -1;
++            /* check if reg_off had been registered already */
++            for (i = 0; i < REGINFO_REGCNT(node); i ++)
++            {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & mask)
++                {
++                    printk("PMU: %s writes with wrong mask 0x%x in off:%#x! \n",
++                        REGINFO_NAME(node), mask, reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                ret = 0;
++            }
++        }
++    }
++
++    if (!ret)
++    {
++        u32     tmp;
++
++        tmp = (ftpmu010_pcie_read_reg(reg_off) & (~mask));
++        tmp |= (val & mask);
++        iowrite32(tmp, ftpmu10_pcie.base + reg_off);
++    }
++
++exit:
++    if (ret < 0) {
++        dump_stack();
++        panic("Configure PMU fail! \n");
++    }
++
++    return ret;
++}
++
++/* PMU init function
++ * Input parameters: virtual address of PMU
++ * Return: 0 for success, < 0 for fail
++ */
++int __init ftpmu010_pcie_init(void __iomem  *base, ftpmu010_pcie_gate_clk_t *tbl, void *pmu_handler)
++{
++    int     i = 0;
++    ftpmu010_pcie_gate_clk_t *table = tbl;
++    
++    ftpmu10_pcie.base = base;
++    spin_lock_init(&ftpmu10_pcie.spinlock);
++    INIT_LIST_HEAD(&ftpmu10_pcie.attr_list);
++    INIT_LIST_HEAD(&ftpmu10_pcie.reginfo_list);
++    /* proc function */
++    ftpmu010_pcie_proc_init();
++
++    /* self test */
++    while (table->midx != FTPMU_PCIE_NONE) {
++        for (i = 0; i < table->num; i ++) {
++            if (table->reg[i].bit_val & ~table->reg[i].bit_mask)
++                panic("%s, error gating clock table in ofs 0x%x of midx:%d! \n", __func__,
++                        table->reg[i].ofs, table->midx);
++        }
++        table ++;
++    }
++
++    pmu_clkgate_tbl = tbl;
++    /* register the callback from pmu */
++    pmu_ctrl_handler = pmu_handler;
++    
++    return 0;
++}
++
++/* ------------------------------------------------------------------------------------
++ *  Proc function
++ * ------------------------------------------------------------------------------------
++ */
++
++ /* Attribute info
++  */
++static int proc_read_attribute_info(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned long flags;
++    attrPcieInfo_node_t *node;
++    int     len = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list)
++    {
++        len += sprintf(page+len, "Attribute name : %s \n", node->attr_info.name);
++        len += sprintf(page+len, "Attribute type : %d \n", node->attr_info.attr_type);
++        len += sprintf(page+len, "Attribute value: %d \n\n", node->attr_info.value);
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return len;
++}
++
++/* Register info
++ */
++static int proc_read_reginfo(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned long flags;
++    pmuPcieRegInfo_node_t *node;
++    int     i, len = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &REGINFO_LIST, list)
++    {
++        len += sprintf(page+len, "name: %s, fd = %d, attribute type = %d \n", REGINFO_NAME(node), node->fd, node->pmuReg_info.clock_src);
++        for (i = 0; i < REGINFO_REGCNT(node); i ++)
++        {
++            len += sprintf(page+len,"    reg_off: 0x%x, bits_mask: 0x%x, lock_bits: 0x%x\n",
++                        REGINFO_OFFSET(node, i), REGINFO_BITSMASK(node, i), REGINFO_LOCKBITS(node, i));
++        }
++        len += sprintf(page+len, "\n");
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return len;
++}
++
++static int ftpmu010_pcie_proc_init(void)
++{
++    int     ret = 0;
++    struct proc_dir_entry   *p;
++
++	p = create_proc_entry("pmu_pcie", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++	if (p == NULL) {
++		return -ENOMEM;
++	}
++	pmu_proc_root = p;
++
++	/*
++     * attribute
++     */
++	attribute_proc = create_proc_entry("attribute", S_IRUGO, pmu_proc_root);
++	if (attribute_proc == NULL) {
++		printk("PMU: Fail to create proc attribute!\n");
++		remove_proc_entry(pmu_proc_root->name, NULL);
++		ret = -EINVAL;
++		goto end;
++	}
++	attribute_proc->read_proc = (read_proc_t *) proc_read_attribute_info;
++	attribute_proc->write_proc = NULL;
++
++    /*
++     * regInfo
++     */
++    regInfo_proc = create_proc_entry("reginfo", S_IRUGO, pmu_proc_root);
++	if (regInfo_proc == NULL) {
++		printk("PMU: Fail to create proc regInfo!\n");
++		remove_proc_entry(attribute_proc->name, pmu_proc_root);
++		remove_proc_entry(pmu_proc_root->name, NULL);
++		ret = -EINVAL;
++		goto end;
++	}
++	regInfo_proc->read_proc = (read_proc_t *) proc_read_reginfo;
++	regInfo_proc->write_proc = NULL;
++end:
++	return ret;
++}
++
++EXPORT_SYMBOL(ftpmu010_pcie_get_attr);
++EXPORT_SYMBOL(ftpmu010_pcie_register_reg);
++EXPORT_SYMBOL(ftpmu010_pcie_deregister_reg);
++EXPORT_SYMBOL(ftpmu010_pcie_read_reg);
++EXPORT_SYMBOL(ftpmu010_pcie_write_reg);
+diff --git a/arch/arm/mach-GM-Duo/fttmr010.c b/arch/arm/mach-GM-Duo/fttmr010.c
+new file mode 100644
+index 00000000..7bd612df
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/fttmr010.c
+@@ -0,0 +1,306 @@
++/*
++ *  Faraday FTTMR010 Timer
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <asm/io.h>
++#include <asm/cputype.h>
++#include <asm/mach/irq.h>
++#include <mach/fttmr010.h>
++#include <mach/gm_jiffies.h>
++
++#ifdef CONFIG_PLATFORM_GM8210
++#include <mach/platform/board.h>
++#endif
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static const unsigned int fttmr010_cr_mask[3] = {
++	FTTMR010_TM1_ENABLE | FTTMR010_TM1_CLOCK |
++	FTTMR010_TM1_OFENABLE | FTTMR010_TM1_UPDOWN,
++
++	FTTMR010_TM2_ENABLE | FTTMR010_TM2_CLOCK |
++	FTTMR010_TM2_OFENABLE | FTTMR010_TM2_UPDOWN,
++
++	FTTMR010_TM3_ENABLE | FTTMR010_TM3_CLOCK |
++	FTTMR010_TM3_OFENABLE | FTTMR010_TM3_UPDOWN,
++};
++
++/* we always use down counter */
++static const unsigned int fttmr010_cr_enable_flag[3] = {
++	FTTMR010_TM1_ENABLE | FTTMR010_TM1_OFENABLE,
++	FTTMR010_TM2_ENABLE | FTTMR010_TM2_OFENABLE,
++	FTTMR010_TM3_ENABLE | FTTMR010_TM3_OFENABLE,
++};
++
++static const unsigned int fttmr010_cr_enable_noirq_flag[3] = {
++	FTTMR010_TM1_ENABLE,
++	FTTMR010_TM2_ENABLE,
++	FTTMR010_TM3_ENABLE,
++};
++
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++/* TmxEnable + overflow interrupt enable
++ */
++static void fttmr010_enable(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];    /* maskout the mask, all setting goes to zero. */
++	cr |= fttmr010_cr_enable_flag[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++/* Just no overflow interrupt enable bit
++ */
++static void fttmr010_enable_noirq(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	cr |= fttmr010_cr_enable_noirq_flag[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static void fttmr010_disable(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static inline void fttmr010_write_timer(void __iomem *base, unsigned int id,
++		unsigned int reg, unsigned int value)
++{
++	void __iomem *addr = base + FTTMR010_OFFSET_TIMER(id) + reg;
++	writel (value, addr);
++}
++
++static inline unsigned int fttmr010_read_timer(void __iomem *base,
++		unsigned int id, unsigned int reg)
++{
++	void __iomem *addr = base + FTTMR010_OFFSET_TIMER(id) + reg;
++	return readl(addr);
++}
++
++static void fttmr010_set_counter(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_COUNTER, value);
++}
++
++static unsigned int fttmr010_get_counter(void __iomem *base, unsigned int id)
++{
++	return fttmr010_read_timer(base, id, FTTMR010_OFFSET_COUNTER);
++}
++
++static void fttmr010_set_reload(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_LOAD, value);
++}
++
++static void fttmr010_set_match1(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_MATCH1, value);
++}
++
++static void fttmr010_set_match2(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_MATCH2, value);
++}
++
++/******************************************************************************
++ * clockevent functions. Set the next trigger event
++ *****************************************************************************/
++static int fttmr010_set_next_event(unsigned long clc, struct clock_event_device *ce)
++{
++	struct fttmr010_clockevent *fttmr010;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++	fttmr010_set_counter(fttmr010->base, fttmr010->id, clc);
++
++	return 0;
++}
++
++static void fttmr010_set_mode(enum clock_event_mode mode, struct clock_event_device *ce)
++{
++	struct fttmr010_clockevent *fttmr010;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++
++	switch (mode) {
++	case CLOCK_EVT_MODE_PERIODIC:
++		fttmr010_set_reload(fttmr010->base, fttmr010->id, fttmr010->reload);
++		fttmr010_set_counter(fttmr010->base, fttmr010->id, fttmr010->reload);
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_RESUME:
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_ONESHOT:
++		fttmr010_set_reload(fttmr010->base, fttmr010->id, 0);
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_UNUSED:
++	case CLOCK_EVT_MODE_SHUTDOWN:
++	default:
++		fttmr010_disable(fttmr010->base, fttmr010->id);
++		break;
++	}
++}
++
++static irqreturn_t fttmr010_clockevent_interrupt(int irq, void *dev_id)
++{
++	struct clock_event_device *ce = dev_id;
++	struct fttmr010_clockevent *fttmr010;
++    unsigned int tmp;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++
++    /* Level Trigger needs this fix */
++	tmp = readl(fttmr010->base + FTTMR010_OFFSET_INTR_STATE);
++	writel(tmp, fttmr010->base + FTTMR010_OFFSET_INTR_STATE);
++
++	ce->event_handler(ce);
++
++#ifdef CONFIG_PLATFORM_GM8210
++    if (get_cpu_id() == 0x626) {
++        /* workaround, FA626 must update its jiffies to the shared memory. And FA726 will report this
++         * jiffies to the user. Terry provides this reigster. 0x54, 0x64, 0x6C is useful
++         */
++        iowrite32((u32)gm_jiffies, PMU_FTPMU010_VA_BASE + 0x64);
++    }
++#endif
++	return IRQ_HANDLED;
++}
++
++void __init fttmr010_clockevent_init(struct fttmr010_clockevent *fttmr010)
++{
++	struct clock_event_device *ce = &fttmr010->clockevent;
++	struct irqaction *action = &fttmr010->irqaction;
++
++	if (!fttmr010->base || fttmr010->id >= 3)
++		BUG();
++
++	/* initialize to a known state */
++	fttmr010_disable(fttmr010->base, fttmr010->id);
++	fttmr010_set_match1(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_match2(fttmr010->base, fttmr010->id, 0);
++
++	/* setup reload value for periodic clockevents */
++	fttmr010->reload	= (fttmr010->freq / HZ) - 1;    /* FIX */
++
++	/* Make irqs happen for the system timer */
++	action->name		= ce->name;
++	action->handler		= fttmr010_clockevent_interrupt;
++	action->flags		= IRQF_DISABLED | IRQF_TIMER;
++	action->dev_id		= ce;
++
++	setup_irq(ce->irq, action);
++
++	/* setup struct clock_event_device */
++	ce->features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
++	ce->shift		= 32;
++	ce->rating		= 200;
++	ce->cpumask		= cpumask_of(0);    //CPU_MASK_ALL,
++
++	ce->mult		= div_sc(fttmr010->freq, NSEC_PER_SEC, ce->shift);
++	ce->max_delta_ns	= clockevent_delta2ns(0xffffffff, ce);
++	ce->min_delta_ns	= clockevent_delta2ns(0xff, ce);
++
++	ce->set_next_event	= fttmr010_set_next_event;
++	ce->set_mode		= fttmr010_set_mode;
++
++	clockevents_register_device(ce);
++#ifdef CONFIG_PLATFORM_GM8210
++    if (get_cpu_id() == 0x626) {
++        /* workaround, FA626 must update its jiffies to the shared memory. And FA726 will report this
++         * jiffies to the user. Terry provides this reigster. 0x54, 0x64, 0x6C is useful
++         */
++        iowrite32((u32)100, PMU_FTPMU010_VA_BASE + 0x54);
++    }
++#endif
++}
++
++/******************************************************************************
++ * clocksource functions
++ *****************************************************************************/
++
++/*
++ * We support only one instance now.
++ *
++ * After 2.6.30, clocksource->read() has a parameter, and we can use it with
++ * container_of() to get the private data for each instance.
++ */
++static cycle_t fttmr010_clocksource_read(struct clocksource *cs)
++{
++    struct fttmr010_clocksource *fttmr010;
++	cycle_t counter;
++
++    fttmr010 = container_of(cs, struct fttmr010_clocksource, clocksource);
++	counter = fttmr010_get_counter(fttmr010->base, fttmr010->id);
++	return ~counter;
++}
++
++void __init fttmr010_clocksource_init(struct fttmr010_clocksource *fttmr010)
++{
++	struct clocksource *cs = &fttmr010->clocksource;
++
++	if (!fttmr010->base || fttmr010->id >= 3)
++		BUG();
++
++	cs->rating	= 300;
++	cs->read	= fttmr010_clocksource_read;
++	cs->mask	= CLOCKSOURCE_MASK(32);
++	cs->shift	= 20;
++	cs->flags	= CLOCK_SOURCE_IS_CONTINUOUS;
++	cs->mult	= clocksource_hz2mult(fttmr010->freq, cs->shift);
++
++	/* setup as free-running clocksource */
++	fttmr010_disable(fttmr010->base, fttmr010->id);
++	fttmr010_set_match1(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_match2(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_reload(fttmr010->base, fttmr010->id, 0xffffffff);
++	fttmr010_set_counter(fttmr010->base, fttmr010->id, 0xffffffff);
++	fttmr010_enable_noirq(fttmr010->base, fttmr010->id);
++
++	clocksource_register(cs);
++
++	if (1) {
++        extern int gm_jiffies_init(void *);
++	    gm_jiffies_init((void *)fttmr010);
++	}
++}
++
+diff --git a/arch/arm/mach-GM-Duo/gm_jiffies.c b/arch/arm/mach-GM-Duo/gm_jiffies.c
+new file mode 100644
+index 00000000..f0962b36
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/gm_jiffies.c
+@@ -0,0 +1,141 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <linux/proc_fs.h>
++#include <linux/timer.h>
++#include <mach/fttmr010.h>
++#include <mach/gm_jiffies.h>
++
++/*
++ * Macro definitions
++ */
++#define HEART_BEAT_INTVAL   (10 * HZ)
++#define time_disance(a, b)  ((long)(b) - (long)(a))
++
++/*
++ * Local variables
++ */
++static unsigned long __gm_jiffies = 0;  /* 1ms granularity */
++static u64  __gm_jiffies_u64 = 0;       /* 1ms granularity */
++static unsigned long clk_khz = 0;
++static struct timer_list  gm_jiffies_tmr;
++static spinlock_t spinlock;
++static unsigned int refer_cnt = 0;
++static struct fttmr010_clocksource *pGmClkSrc = NULL;
++static struct proc_dir_entry *gm_jiffies_proc = NULL;
++
++/*
++ * Local functions
++ */
++static int proc_read_gm_jiffies(char *page, char **start, off_t off, int count, int *eof, void *data);
++
++static unsigned int distance = 0;
++
++/* get 1m jiffies */
++unsigned long get_gm_jiffies(void)
++{
++    static unsigned long keep_clk_val = 0;
++    unsigned long flags, new_clk_val;
++
++    if (pGmClkSrc == NULL)
++        return 0;
++
++    /* lock */
++    spin_lock_irqsave(&spinlock, flags);
++    new_clk_val = pGmClkSrc->clocksource.read(&pGmClkSrc->clocksource);
++    if (!keep_clk_val && !new_clk_val) {  /* not start yet */
++        spin_unlock_irqrestore(&spinlock, flags);
++        return 0;
++    }
++
++    distance += time_disance(keep_clk_val, new_clk_val);
++    keep_clk_val = new_clk_val;
++
++    if (distance >= clk_khz) {
++        unsigned long value = distance / clk_khz;
++
++        __gm_jiffies += value;
++        __gm_jiffies_u64 += value;
++        distance = distance % clk_khz;
++    }
++
++    /* unlock */
++    spin_unlock_irqrestore(&spinlock, flags);
++
++    refer_cnt ++;
++
++    return __gm_jiffies;
++}
++EXPORT_SYMBOL(get_gm_jiffies);
++
++/* get 1m jiffies */
++u64 get_gm_jiffies_u64(void)
++{
++    get_gm_jiffies();
++
++    return __gm_jiffies_u64;
++}
++EXPORT_SYMBOL(get_gm_jiffies_u64);
++
++/*
++ * A function to update __gm_jiffies periodically if there is no caller to call get_gm_jiffies()
++ *   in a long interval.
++ */
++void gm_heatbeat_handler(unsigned long data)
++{
++    struct fttmr010_clocksource *pGmClkSrc = (struct fttmr010_clocksource *)data;
++
++
++    /* in order to prevent __gm_jiffies not update in a long time */
++    get_gm_jiffies();
++
++    gm_jiffies_tmr.function = gm_heatbeat_handler;
++    gm_jiffies_tmr.data = (unsigned long)pGmClkSrc;
++    mod_timer(&gm_jiffies_tmr, jiffies + HEART_BEAT_INTVAL);
++
++    if (gm_jiffies_proc == NULL) {
++        gm_jiffies_proc = create_proc_entry("gm_jiffies", S_IRUGO, NULL);
++        if (gm_jiffies_proc == NULL)
++            panic("%s, error in create proc! \n", __func__);
++
++        gm_jiffies_proc->read_proc = (read_proc_t *) proc_read_gm_jiffies;
++        gm_jiffies_proc->write_proc = NULL;
++    }
++}
++
++int __init gm_jiffies_init(void *data)
++{
++    pGmClkSrc = (struct fttmr010_clocksource *)data;
++    if (pGmClkSrc == NULL)
++        panic("%s, data is NULL! \n", __func__);
++
++    clk_khz = pGmClkSrc->freq / 1000;
++
++    /* sanity check */
++    if ((HEART_BEAT_INTVAL / HZ) >= (0xffffffff / pGmClkSrc->freq))
++        panic("%s, HEART_BEAT_INTVAL = %d out of range! \n", __func__, HEART_BEAT_INTVAL / HZ);
++
++    spin_lock_init(&spinlock);
++    init_timer(&gm_jiffies_tmr);
++    gm_jiffies_tmr.function = gm_heatbeat_handler;
++    gm_jiffies_tmr.data = (unsigned long)pGmClkSrc;
++    mod_timer(&gm_jiffies_tmr, jiffies + HZ);
++    printk("%s, system HZ: %d, pClk: %d \n", __func__, HZ, pGmClkSrc->freq);
++
++    return 0;
++}
++
++static int proc_read_gm_jiffies(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    int len = 0;
++
++    len += sprintf(page + len, "gm jiffies: 0x%x, HZ = %d \n", (u32)gm_jiffies, HZ);
++    len += sprintf(page + len, "reference count: 0x%d \n", refer_cnt);
++
++    return len;
++}
++
++MODULE_AUTHOR("Grain Media Corp.");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-Duo/include/mach/debug-macro.S b/arch/arm/mach-GM-Duo/include/mach/debug-macro.S
+new file mode 100644
+index 00000000..c7b2406f
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/debug-macro.S
+@@ -0,0 +1,44 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/debug-macro.S
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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 <linux/linkage.h>
++#include <mach/hardware.h>
++#include <mach/serial.h>
++
++		.macro	addruart, rp, rv, tmp
++		ldr	\rp, =DEBUG_LL_FTUART010_PA_BASE	@ physical base address of UART
++		ldr	\rv, =DEBUG_LL_FTUART010_VA_BASE	@ virtual base address of UART
++		.endm
++
++		.macro	senduart, rd, rx
++		strb	\rd, [\rx, #SERIAL_THR]
++		.endm
++
++		.macro	waituart, rd, rx
++1001:		ldrb	\rd, [\rx, #SERIAL_LSR]	@ LSR
++		tst	\rd, #SERIAL_LSR_THRE	@ test empty
++		beq	1001b
++		.endm
++
++		.macro	busyuart, rd, rx
++		mov	\rd, #0x100
++1010:		subs	\rd, \rd, #1
++		bne	1010b
++		.endm
+diff --git a/arch/arm/mach-GM-Duo/include/mach/dma_gm.h b/arch/arm/mach-GM-Duo/include/mach/dma_gm.h
+new file mode 100644
+index 00000000..0f1f707b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/dma_gm.h
+@@ -0,0 +1,33 @@
++#ifndef __DMA_GM_H
++#define __DMA_GM_H
++
++enum dma_kind {
++	APB_DMA,
++	AHB_DMA,
++	AXI_DMA,
++};
++
++/** 
++* @brief memory copy used by DMA
++* 
++* @style: choose DMA style (APB, AHB, AXI)
++* @dest: DMA memory copy's destination address
++* @src: DMA memory copy's source address 
++* @len: DMA memory copy's memory length 
++* 
++* @return 0: success, other: failed 
++*/
++int dma_memcpy(enum dma_kind style, dma_addr_t dest, dma_addr_t src, size_t len);
++
++/** 
++* @brief memory set used by DMA
++* 
++* @style: choose DMA style (APB, AHB, AXI)
++* @dest: DMA memory set's destination address
++* @value: DMA memory set's value
++* @len: DMA memory set's memory length 
++* 
++* @return 0: success, other: failed 
++*/
++int dma_memset(enum dma_kind style, dma_addr_t dest, int value, size_t len);
++#endif /* __DMA_GM_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/entry-macro.S b/arch/arm/mach-GM-Duo/include/mach/entry-macro.S
+new file mode 100644
+index 00000000..62da9260
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/entry-macro.S
+@@ -0,0 +1,327 @@
++/*
++ * arch/arm/mach-GM-Duo/include/mach/entry-macro.S
++ *
++ * Faraday Low-level Interrupt Vector Interface Macros
++ *
++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef CONFIG_CPU_FMP626
++
++#include <mach/irqs.h>
++#include <mach/ftintc030.h>
++#include <mach/ftintc010.h>
++
++	.macro	check_status, irqstat, tmp
++	//???
++	stmfd	sp!, {r7}
++#ifdef CONFIG_PLATFORM_GM8210
++    mrc p15, 0, r7, c0, c0  @ get processor ID
++    ldr r4, =0x66057261     @ check id if fa726 exists
++    cmp r7, r4
++    beq 8210726f            @ must be long label, cannot be short, such as 1
++	ldr	r7, =ftintc030_base_cpu_1_irq_base
++    b   8210000f
++8210726:
++    ldr r7, =ftintc030_base_cpu_0_irq_base
++8210000:
++#endif
++	ldr	r7, [r7]
++	mov 	r4, \tmp
++	mov	r4, r4, lsr #3				/* >>= 5, then << 2 calc INT offset */
++	ldr	r4, [r7, r4]
++	and	\irqstat, \irqstat, r4
++	ldmfd	sp!, {r7}
++	.endm
++
++	.macro	disable_fiq
++	.endm
++
++	.macro	get_irqnr_preamble, base, tmp
++#ifdef CONFIG_FTINTC030
++	ldr	\base, =ftintc030_base_addr
++#else
++	ldr	\base, =ftintc010_base_addr
++#endif
++	ldr	\base, [\base]
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++#if __LINUX_ARM_ARCH__ >= 5
++	.macro	__get_int_nr_and_base, irqnr, irqstat, tmp
++	clz	\irqnr, \irqstat				/* 32 if no bits are set, and zero if bit 31 is set */
++	rsb	\irqnr, \irqnr, #31			/* irqnr = 31 - irqnr, get irq number */
++	.endm
++#else
++	/*
++	 * An O(1) optimized version for getting IRQ/FIQ number
++	 * 08/29/2005 Luke Lee
++	 * Input/output: irqnr (initial value), irqstat (the word to scan)
++	 * Local R/W:	tmp
++	 */
++	.macro	__get_int_nr_and_base, irqnr, irqstat, tmp
++	mov	\tmp, \irqstat, lsl #16	/* check if lower 16 bits = zero */
++	cmp	\tmp, #0
++	movne	\irqstat, \irqstat, lsl #16	/* irqstat <<= 16 */
++	subne	\irqnr, \irqnr, #16	/* irqnr -= 16 */
++	tst	\irqstat, #0x00FF0000
++	movne	\irqstat, \irqstat, lsl #8	/* irqstat <<= 8 */
++	subne	\irqnr, \irqnr, #8	/* irqnr -= 8 */
++	tst	\irqstat, #0x0F000000
++	movne	\irqstat, \irqstat, lsl #4	/* irqstat <<= 4 */
++	subne	\irqnr, \irqnr, #4	/* irqnr -= 4 */
++	tst	\irqstat, #0x30000000
++	movne	\irqstat, \irqstat, lsl #2	/* irqstat <<= 2 */
++	subne	\irqnr, \irqnr, #2	/* irqnr -= 2 */
++	tst	\irqstat, #0x40000000
++	subne	\irqnr, \irqnr, #1	/* irqnr -= 1 */
++	.endm
++#endif
++
++#ifdef CONFIG_FTINTC010EX
++	/*
++	 * Get EXTEND IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp, base, offset
++   * 					base: irq IP base address
++   * 					offset: register offset
++	 */
++	.macro	__get_ex_nr, irqnr, irqstat, tmp, base, offset
++	ldr	\irqstat, [\base, \offset]
++	cmp	\irqstat, #0
++	beq	15f
++	mov	\irqnr, #31
++
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++
++	add	\irqnr, \irqnr, #32
++	cmp	\irqnr, #NR_IRQS
++15:
++	.endm	/* get_ex_nr */
++#endif
++
++#ifdef CONFIG_FTINTC030
++	/*
++	 * Get SPI INTC030 IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp, base, r5
++   * 					irqstat: spi status
++   * 					tmp: register offset
++   * 					base: irq IP base address
++   * 					offset: register offset
++   * 					r3: irq number base
++	 */
++	.macro	__get_spi_nr, irqnr, irqstat, tmp, base, offset, mode
++	ldr	\irqstat, [\base, \offset]	/* read IRQ status, irq group 1 */
++
++	add \base, \base, #0x20
++	mov \tmp, #32
++	mov r3, #32										/* move spi base to 32 */
++//	???
++	check_status \irqstat, r3
++	cmp	\irqstat, #0
++	beq	7f
++
++	mov	\irqnr, #31								/* irq between this range */
++6:
++	sub \base, \base, \tmp
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++
++	add	\irqnr, \irqnr, r3					/* add irq base and return value */
++	cmp	r3, #(NR_IRQS - 32)
++	b 9f
++7:
++	cmp	r3, #(NR_IRQS - 32)				/* check irq overflow */
++	bge	9f
++	add \tmp, \tmp, #0x20					/* shift to next register offset */
++	add \base, \base, #0x20
++	ldr	\irqstat, [\base, \offset]	/* read IRQ status, irq group 2~14 */
++	add	r3, r3, #32								/* add IRQ number base */
++//	???
++	check_status \irqstat, r3
++	cmp	\irqstat, #0
++	beq	7b
++	b 6b
++9:
++
++	.endm	/* get_spi_nr */
++#endif
++
++	/*
++	 * Get IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp
++	 */
++	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++
++	mov	\irqnr, #0
++#ifdef CONFIG_FTINTC030
++	ldr	\irqstat, [\base, #FTINTC030_OFFSET_IRQPEND]	/* irq group 0 */
++
++	check_status \irqstat, \irqnr
++//???
++#else
++	ldr	\irqstat, [\base, #FTINTC010_OFFSET_IRQSTATUS]/* irq group 0 */
++#endif
++
++	cmp	\irqstat, #0
++	beq	3f
++
++#ifdef CONFIG_PLATFORM_GM8210
++    /* 
++     * H264E will be highest priority
++     *
++     */
++    tst \irqstat, #1 << 28
++    movne \irqstat, #1 << 28
++    tst \irqstat, #1 << 29
++    movne \irqstat, #1 << 29
++#endif
++
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++	cmp	\irqnr, #NR_IRQS
++#if (defined(CONFIG_FTINTC010EX) || defined(CONFIG_FTINTC030))
++	b	5f
++#endif
++3:
++#ifdef CONFIG_FTINTC010EX
++	__get_ex_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC010_OFFSET_IRQSTATUSEX	/* irq group 1 */
++5:
++#endif
++#ifdef CONFIG_FTINTC030
++	__get_spi_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC030_OFFSET_IRQPEND1	, #0	/* irq group 1~14 */
++	cmp \irqnr, #0
++5:
++#endif
++	.endm	/* get_irqnr_and_base */
++
++#ifdef CONFIG_FIQ
++    /*
++    * Get FIQ number and base
++	* Input: none
++	* Output: irqnr, Z flag
++	* Local R/W: irqstat, base, tmp
++	*/
++	.macro get_fiqnr_and_base, irqnr, irqstat, base, tmp
++#ifdef CONFIG_FTINTC030
++	ldr \irqstat, [\base, #FTINTC030_OFFSET_IRQPEND]		/* fiq group 0 */
++#else
++	ldr \irqstat, [\base, #FTINTC010_OFFSET_FIQSTATUS]	/* fiq group 0 */
++#endif
++	cmp	\irqstat, #0
++	beq	2003f
++	mov	\irqnr, #0
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++	cmp	\irqnr, #NR_IRQS
++#if (defined(CONFIG_FTINTC010EX) || defined(CONFIG_FTINTC030))
++    b   2005f
++#endif
++2003:
++#ifdef CONFIG_FTINTC010EX
++	__get_ex_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC010_OFFSET_FIQSTATUSEX	/* fiq group 1 */
++2005:
++#endif
++#ifdef CONFIG_FTINTC030
++	__get_spi_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC030_OFFSET_IRQPEND1, #1		/* fiq group 1~14 */
++2005:
++#endif
++    .endm	/* get_fiqnr_and_base */
++
++#endif /* CONFIG_FIQ */
++
++
++#else	/* CONFIG_CPU_FMP626 */
++
++#include <mach/hardware.h>
++#include <asm/hardware/gic.h>
++
++	.macro	disable_fiq
++	.endm
++
++	.macro	get_irqnr_preamble, base, tmp
++	ldr	\base, =gic_cpu_base_addr
++	ldr	\base, [\base]
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++	/*
++	 * The interrupt numbering scheme is defined in the
++	 * interrupt controller spec.  To wit:
++	 *
++	 * Interrupts 0-15 are IPI
++	 * 16-28 are reserved
++	 * 29-31 are local.  We allow 30 to be used for the watchdog.
++	 * 32-1020 are global
++	 * 1021-1022 are reserved
++	 * 1023 is "spurious" (no interrupt)
++	 *
++	 * For now, we ignore all local interrupts so only return an interrupt if it's
++	 * between 30 and 1020.  The test_for_ipi routine below will pick up on IPIs.
++	 *
++	 * A simple read from the controller will tell us the number of the highest
++	 * priority enabled interrupt.  We then just need to check whether it is in the
++	 * valid range for an IRQ (30-1020 inclusive).
++	 */
++
++	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++
++	ldr	\irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 = src CPU, 9-0 = int # */
++
++	ldr	\tmp, =1021
++
++	bic	\irqnr, \irqstat, #0x1c00
++
++	cmp	\irqnr, #29
++	cmpcc	\irqnr, \irqnr
++	cmpne	\irqnr, \tmp
++	cmpcs	\irqnr, \irqnr
++
++	.endm
++
++	/* We assume that irqstat (the raw value of the IRQ acknowledge
++	 * register) is preserved from the macro above.
++	 * If there is an IPI, we immediately signal end of interrupt on the
++	 * controller, since this requires the original irqstat value which
++	 * we won't easily be able to recreate later.
++	 */
++
++	.macro	test_for_ipi, irqnr, irqstat, base, tmp
++	bic	\irqnr, \irqstat, #0x1c00
++	cmp	\irqnr, #16
++	strcc	\irqstat, [\base, #GIC_CPU_EOI]
++	cmpcs	\irqnr, \irqnr
++	.endm
++
++	/* As above, this assumes that irqstat and base are preserved.. */
++
++	.macro	test_for_ltirq, irqnr, irqstat, base, tmp
++	bic	\irqnr, \irqstat, #0x1c00
++	mov 	\tmp, #0
++	cmp	\irqnr, #29
++	moveq	\tmp, #1
++	streq	\irqstat, [\base, #GIC_CPU_EOI]
++	cmp	\tmp, #0
++	.endm
++
++#endif	/* CONFIG_CPU_FMP626 */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/fmem.h b/arch/arm/mach-GM-Duo/include/mach/fmem.h
+new file mode 100644
+index 00000000..59a91299
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/fmem.h
+@@ -0,0 +1,98 @@
++#ifndef __FMEM_H
++#define __FMEM_H
++#include <linux/mm.h>
++#include <asm/io.h>
++#include <asm/setup.h>
++#include <linux/list.h>
++#include <linux/dma-direction.h>
++
++#define MAX_DDR_CHUNKS 2   /* include system memory */
++
++typedef struct g_page_info_s
++{
++    int         nr_node;        /* number of active DDRs */
++    int         block_sz;       /* page allocation size once */
++    int         node_sz[MAX_DDR_CHUNKS];    /* the size for the DDR node */
++    dma_addr_t  phy_start[MAX_DDR_CHUNKS];  /* the min physical start */
++    struct list_head list[MAX_DDR_CHUNKS];  /* page node list */
++} g_page_info_t;
++
++/* page node for each pages allocation */
++typedef struct {
++    struct page     *page;
++    dma_addr_t      phy_start;
++    unsigned int    size;   /* the real size */
++    int             ddr_id; /* belong to which DDR */
++    struct list_head list;
++} page_node_t;
++
++void fmem_get_pageinfo(g_page_info_t **data_ptr);
++int  fmem_give_pages(int node_id, unsigned int give_sz);
++void fmem_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi);
++
++void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle);
++void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id);
++
++/**
++ * @brief to resolve the virtual address (including direct mapping, ioremap or user space address to
++ *      its real physical address.
++ *
++ * @parm vaddr indicates any virtual address
++ *
++ * @return  >= 0 for success, 0xFFFFFFFF for fail
++ */
++phys_addr_t fmem_lookup_pa(unsigned int vaddr);
++
++/*
++ *  * @This function is used to read CPU id and pci id
++ *   * @Return value: 0 for success, -1 for fail
++ *    */
++typedef enum {
++    FMEM_CPU_FA726 = 0,
++    FMEM_CPU_FA626,
++    FMEM_CPU_UNKNOWN,
++} fmem_cpu_id_t;
++
++typedef enum {
++    FMEM_PCI_HOST = 0,
++    FMEM_PCI_DEV0,
++} fmem_pci_id_t;
++
++int fmem_get_identifier(fmem_pci_id_t *pci_id, fmem_cpu_id_t *cpu_id);
++
++/* @this function is a data cache operation function,
++ * @parm: vaddr: any virtual address
++ * @parm: dir will be:
++ * DMA_BIDIRECTIONAL = 0, it means flush operation.
++ * DMA_TO_DEVICE = 1, it means clean operation.
++ * DMA_FROM_DEVICE = 2, it means invalidate operation.
++ * DMA_NONE = 3,
++ */
++void fmem_dcache_sync(void *vaddr, u32 len, enum dma_data_direction dir);
++
++/* @this function is used to set outbound window of EP
++ * @parm: phy_addr: start physical address
++ * @parm: size: window size
++ * return value: 0 for success, -1 for fail.
++ * Note: This function is only called in RC.
++ */
++int fmem_set_ep_outbound_win(u32 phy_addr, u32 size);
++
++/* @this function is used to translate local axi address to pcie address
++ * @parm: axi_phy_addr indicates local axi address
++ * return value: PCIe address. 0xFFFFFFFF if fail.
++ * Note: This function is only called in RC.
++ */
++u32 fmem_get_pcie_addr(u32 axi_phy_addr);
++
++/* @this function is used to translate pcie to local axi address
++ * @parm: pcie_phy_addr indicates pcie address
++ * return value: local axi address. 0xFFFFFFFF if fail.
++ * Note: This function is only called in RC.
++ */
++u32 fmem_get_axi_addr(u32 pcie_phy_addr);
++
++#endif /* __FMEM_H */
++
++
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/ftapbb020.h b/arch/arm/mach-GM-Duo/include/mach/ftapbb020.h
+new file mode 100644
+index 00000000..d135705c
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/ftapbb020.h
+@@ -0,0 +1,139 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftapbb020.h
++ *
++ *  Faraday FTAPBB020 APB Bridge with DMA function
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTAPBB020_H
++#define __FTAPBB020_H
++
++#define FTAPBB020_OFFSET_BSR(x)		((x) * 0x4)		/* BSR of slave x */
++#define FTAPBB020_OFFSET_SAR(x)		(0x80 + (x) * 0x10)	/* src addr of channel x */
++#define FTAPBB020_OFFSET_DAR(x)		(0x84 + (x) * 0x10)	/* dst addr of channel x */
++#define FTAPBB020_OFFSET_CYC(x)		(0x88 + (x) * 0x10)	/* cycles of channel x */
++#define FTAPBB020_OFFSET_CMD(x)		(0x8c + (x) * 0x10)	/* command of channel x */
++#define FTAPBB020_OFFSET_CR		0xc0
++#define FTAPBB020_OFFSET_SR		0xc4
++#define FTAPBB020_OFFSET_REV		0xc8
++
++/*
++ * Base/size of each slave
++ */
++#define FTAPBB020_BSR_SIZE_1M		(0 << 16)
++#define FTAPBB020_BSR_SIZE_2M		(1 << 16)
++#define FTAPBB020_BSR_SIZE_4M		(2 << 16)
++#define FTAPBB020_BSR_SIZE_8M		(3 << 16)
++#define FTAPBB020_BSR_SIZE_16M		(4 << 16)
++#define FTAPBB020_BSR_SIZE_32M		(5 << 16)
++#define FTAPBB020_BSR_SIZE_64M		(6 << 16)
++#define FTAPBB020_BSR_SIZE_128M		(7 << 16)
++#define FTAPBB020_BSR_SIZE_256M		(8 << 16)
++#define FTAPBB020_BSR_BASE(x)		((x) & (0x3ff << 20))
++
++/*
++ * Cycle count of each DMA channel
++ */
++#define FTAPBB020_CYC_MASK		0x00ffffff
++
++/*
++ * Command of each DMA channel
++ */
++#define FTAPBB020_CMD_ENABLE		(1 << 0)
++#define FTAPBB020_CMD_FININT_S		(1 << 1)
++#define FTAPBB020_CMD_FININT_E		(1 << 2)
++#define FTAPBB020_CMD_BURST		(1 << 3)
++#define FTAPBB020_CMD_ERRINT_S		(1 << 4)
++#define FTAPBB020_CMD_ERRINT_E		(1 << 5)
++#define FTAPBB020_CMD_SRC_TYPE_AHB	(1 << 6)
++#define FTAPBB020_CMD_DST_TYPE_AHB	(1 << 7)
++#define FTAPBB020_CMD_SRC_MODE_FIXED	(0 << 8)
++#define FTAPBB020_CMD_SRC_MODE_BYTE_INC	(1 << 8)
++#define FTAPBB020_CMD_SRC_MODE_HALF_INC	(2 << 8)
++#define FTAPBB020_CMD_SRC_MODE_WORD_INC	(3 << 8)
++#define FTAPBB020_CMD_SRC_MODE_BYTE_DEC	(5 << 8)
++#define FTAPBB020_CMD_SRC_MODE_HALF_DEC	(6 << 8)
++#define FTAPBB020_CMD_SRC_MODE_WORD_DEC	(7 << 8)
++#define FTAPBB020_CMD_DST_MODE_FIXED	(0 << 12)
++#define FTAPBB020_CMD_DST_MODE_BYTE_INC	(1 << 12)
++#define FTAPBB020_CMD_DST_MODE_HALF_INC	(2 << 12)
++#define FTAPBB020_CMD_DST_MODE_WORD_INC	(3 << 12)
++#define FTAPBB020_CMD_DST_MODE_BYTE_DEC	(5 << 12)
++#define FTAPBB020_CMD_DST_MODE_HALF_DEC	(6 << 12)
++#define FTAPBB020_CMD_DST_MODE_WORD_DEC	(7 << 12)
++#define FTAPBB020_CMD_DST_HANDSHAKE(x)	(((x) & 0xf) << 16)	/* destination handshake channel */
++#define FTAPBB020_CMD_WIDTH_WORD	(0 << 20)
++#define FTAPBB020_CMD_WIDTH_HALF	(1 << 20)
++#define FTAPBB020_CMD_WIDTH_BYTE	(2 << 20)
++#define FTAPBB020_CMD_SRC_HANDSHAKE(x)	(((x) & 0xf) << 24)	/* source handshake channel */
++
++/*
++ * Control register
++ */
++#define FTAPBB020_CR_BUF_NORMAL		(0 << 0)
++#define FTAPBB020_CR_BUF_ALWAYS		(1 << 0)
++#define FTAPBB020_CR_BUF_NEVER		(2 << 0)
++#define FTAPBB020_CR_BWERRINT_E		(1 << 2)
++
++/*
++ * Status register
++ */
++#define FTAPBB020_SR_BWERRINT		(1 << 0)
++
++/*
++ * Revision register
++ */
++#define FTAPBB020_REV_REVISION(rev)	((rev) & ~(0xff << 24))
++
++enum ftapbb020_bus_type {
++	FTAPBB020_BUS_TYPE_AHB,
++	FTAPBB020_BUS_TYPE_APB,
++};
++
++enum ftapbb020_channels {
++	FTAPBB020_CHANNEL_0 = (1 << 0),
++	FTAPBB020_CHANNEL_1 = (1 << 1),
++	FTAPBB020_CHANNEL_2 = (1 << 2),
++	FTAPBB020_CHANNEL_3 = (1 << 3),
++	FTAPBB020_CHANNEL_ALL = 0xf,
++};
++
++/**
++ * struct ftapbb020_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @type: bus type of the device
++ * @channels: bitmap of usable DMA channels
++ * @handshake: hardware handshake number
++ */
++struct ftapbb020_dma_slave {
++	struct dma_slave_config common;
++	int id;
++	enum ftapbb020_bus_type type;
++//	enum ftapbb020_channels channels;
++	unsigned int handshake;
++};
++
++/**
++ * ftapbb020_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftapbb020_dma_slave
++ */
++bool ftapbb020_chan_filter(struct dma_chan *chan, void *data);
++
++#endif	/* __FTAPBB020_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/ftdmac020.h b/arch/arm/mach-GM-Duo/include/mach/ftdmac020.h
+new file mode 100644
+index 00000000..6a4a9bd2
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/ftdmac020.h
+@@ -0,0 +1,236 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftdmac020.h
++ *
++ *  Faraday FTDMAC020 DMA controller
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTDMAC020_H
++#define __FTDMAC020_H
++
++#include <linux/dmaengine.h>
++
++#define FTDMAC020_OFFSET_ISR		0x0
++#define FTDMAC020_OFFSET_TCISR		0x4
++#define FTDMAC020_OFFSET_TCICR		0x8
++#define FTDMAC020_OFFSET_EAISR		0xc
++#define FTDMAC020_OFFSET_EAICR		0x10
++#define FTDMAC020_OFFSET_TCRAW		0x14
++#define FTDMAC020_OFFSET_EARAW		0x18
++#define FTDMAC020_OFFSET_CH_ENABLED	0x1c
++#define FTDMAC020_OFFSET_CH_BUSY	0x20
++#define FTDMAC020_OFFSET_CR		    0x24
++#define FTDMAC020_OFFSET_SYNC		0x28
++#define FTDMAC020_OFFSET_REVISION	0x2c
++#define FTDMAC020_OFFSET_FEATURE	0x30
++
++#define FTDMAC020_OFFSET_CCR_CH(x)	(0x100 + (x) * 0x20)
++#define FTDMAC020_OFFSET_CFG_CH(x)	(0x104 + (x) * 0x20)
++#define FTDMAC020_OFFSET_SRC_CH(x)	(0x108 + (x) * 0x20)
++#define FTDMAC020_OFFSET_DST_CH(x)	(0x10c + (x) * 0x20)
++#define FTDMAC020_OFFSET_LLP_CH(x)	(0x110 + (x) * 0x20)
++#define FTDMAC020_OFFSET_CYC_CH(x)	(0x114 + (x) * 0x20)
++
++/*
++ * Error/abort interrupt status/clear register
++ * Error/abort status register
++ */
++#define FTDMAC020_EA_ERR_CH(x)		(1 << (x))
++#define FTDMAC020_EA_ABT_CH(x)		(1 << ((x) + 16))
++
++/*
++ * Main configuration status register
++ */
++#define FTDMAC020_CR_ENABLE		(1 << 0)
++#define FTDMAC020_CR_M0_BE		(1 << 1)	/* master 0 big endian */
++#define FTDMAC020_CR_M1_BE		(1 << 2)	/* master 1 big endian */
++
++/*
++ * Channel control register
++ */
++#define FTDMAC020_CCR_ENABLE		(1 << 0)
++#define FTDMAC020_CCR_DST_M1		(1 << 1)
++#define FTDMAC020_CCR_SRC_M1		(1 << 2)
++#define FTDMAC020_CCR_DST_INC		(0x0 << 3)
++#define FTDMAC020_CCR_DST_DEC		(0x1 << 3)
++#define FTDMAC020_CCR_DST_FIXED		(0x2 << 3)
++#define FTDMAC020_CCR_SRC_INC		(0x0 << 5)
++#define FTDMAC020_CCR_SRC_DEC		(0x1 << 5)
++#define FTDMAC020_CCR_SRC_FIXED		(0x2 << 5)
++#define FTDMAC020_CCR_HANDSHAKE		(1 << 7)
++#define FTDMAC020_CCR_DST_WIDTH_8	(0x0 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_16	(0x1 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_32	(0x2 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_64	(0x3 << 8)
++#define FTDMAC020_CCR_SRC_WIDTH_8	(0x0 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_16	(0x1 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_32	(0x2 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_64	(0x3 << 11)
++#define FTDMAC020_CCR_ABORT		    (1 << 15)
++#define FTDMAC020_CCR_BURST_1		(0x0 << 16)
++#define FTDMAC020_CCR_BURST_4		(0x1 << 16)
++#define FTDMAC020_CCR_BURST_8		(0x2 << 16)
++#define FTDMAC020_CCR_BURST_16		(0x3 << 16)
++#define FTDMAC020_CCR_BURST_32		(0x4 << 16)
++#define FTDMAC020_CCR_BURST_64		(0x5 << 16)
++#define FTDMAC020_CCR_BURST_128		(0x6 << 16)
++#define FTDMAC020_CCR_BURST_256		(0x7 << 16)
++#define FTDMAC020_CCR_PRIVILEGED	(1 << 19)
++#define FTDMAC020_CCR_BUFFERABLE	(1 << 20)
++#define FTDMAC020_CCR_CACHEABLE		(1 << 21)
++#define FTDMAC020_CCR_PRIO_0		(0x0 << 22)
++#define FTDMAC020_CCR_PRIO_1		(0x1 << 22)
++#define FTDMAC020_CCR_PRIO_2		(0x2 << 22)
++#define FTDMAC020_CCR_PRIO_3		(0x3 << 22)
++#define FTDMAC020_CCR_FIFOTH_1		(0x0 << 24)
++#define FTDMAC020_CCR_FIFOTH_2		(0x1 << 24)
++#define FTDMAC020_CCR_FIFOTH_4		(0x2 << 24)
++#define FTDMAC020_CCR_FIFOTH_8		(0x3 << 24)
++#define FTDMAC020_CCR_FIFOTH_16		(0x4 << 24)
++#define FTDMAC020_CCR_MASK_TC		(1 << 31)
++
++/*
++ * Channel configuration register
++ */
++#define FTDMAC020_CFG_MASK_TCI		(1 << 0)	/* mask tc interrupt */
++#define FTDMAC020_CFG_MASK_EI		(1 << 1)	/* mask error interrupt */
++#define FTDMAC020_CFG_MASK_AI		(1 << 2)	/* mask abort interrupt */
++#define FTDMAC020_CFG_SRC_HANDSHAKE(x)	(((x) & 0xf) << 3)
++#define FTDMAC020_CFG_SRC_HANDSHAKE_EN	(1 << 7)
++#define FTDMAC020_CFG_BUSY		(1 << 8)
++#define FTDMAC020_CFG_DST_HANDSHAKE(x)	(((x) & 0xf) << 9)
++#define FTDMAC020_CFG_DST_HANDSHAKE_EN	(1 << 13)
++#define FTDMAC020_CFG_LLP_CNT(cfg)	(((cfg) >> 16) & 0xf)
++
++/*
++ * Link list descriptor pointer
++ */
++#define FTDMAC020_LLP_M1		(1 << 0)
++#define FTDMAC020_LLP_ADDR(a)		((a) & ~0x3)
++
++/*
++ * Transfer size register
++ */
++#define FTDMAC020_CYC_MASK		0x3fffff
++
++/**
++ * Table 3-1. Address Map for Linked List Descriptor(Base Address: Cn_LLP[31:2])
++ *
++ * struct ftdmac020_lld - hardware link list descriptor.
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the next link list descriptor
++ * @ctrl: control field
++ * @cycle: transfer size
++ *
++ * should be word aligned.
++ */
++struct ftdmac020_lld {
++	dma_addr_t src;     /* SrcAddr */
++	dma_addr_t dst;     /* DstAddr */
++	dma_addr_t next;    /* LLP */
++	unsigned int ctrl;  /* Control */
++	unsigned int cycle; /* Total Size */
++};
++
++#define FTDMAC020_LLD_CTRL_DST_M1	(1 << 16)
++#define FTDMAC020_LLD_CTRL_SRC_M1	(1 << 17)
++#define FTDMAC020_LLD_CTRL_DST_INC	(0x0 << 18)
++#define FTDMAC020_LLD_CTRL_DST_DEC	(0x1 << 18)
++#define FTDMAC020_LLD_CTRL_DST_FIXED	(0x2 << 18)
++#define FTDMAC020_LLD_CTRL_SRC_INC	(0x0 << 20)
++#define FTDMAC020_LLD_CTRL_SRC_DEC	(0x1 << 20)
++#define FTDMAC020_LLD_CTRL_SRC_FIXED	(0x2 << 20)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_8	(0x0 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_16	(0x1 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_32	(0x2 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_64	(0x3 << 22)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_8	(0x0 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_16	(0x1 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_32	(0x2 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_64	(0x3 << 25)
++#define FTDMAC020_LLD_CTRL_MASK_TC	(1 << 28)
++#define FTDMAC020_LLD_CTRL_FIFOTH_1	(0x0 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_2	(0x1 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_4	(0x2 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_8	(0x3 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_16	(0x4 << 29)
++
++#define FTDMAC020_LLD_CYCLE_MASK	0x3fffff
++
++enum ftdmac020_channels {
++	FTDMAC020_CHANNEL_0 = (1 << 0),
++	FTDMAC020_CHANNEL_1 = (1 << 1),
++	FTDMAC020_CHANNEL_2 = (1 << 2),
++	FTDMAC020_CHANNEL_3 = (1 << 3),
++	FTDMAC020_CHANNEL_4 = (1 << 4),
++	FTDMAC020_CHANNEL_5 = (1 << 5),
++	FTDMAC020_CHANNEL_6 = (1 << 6),
++	FTDMAC020_CHANNEL_7 = (1 << 7),
++	FTDMAC020_CHANNEL_ALL = 0xff,
++};
++
++enum ftdmac020_burst {
++    FTDMAC020_BURST_SZ_1 = 0,
++    FTDMAC020_BURST_SZ_4,
++    FTDMAC020_BURST_SZ_8,
++    FTDMAC020_BURST_SZ_16,
++    FTDMAC020_BURST_SZ_32,
++    FTDMAC020_BURST_SZ_64,
++    FTDMAC020_BURST_SZ_128,
++    FTDMAC020_BURST_SZ_256
++};
++
++enum ftdmac020_ahbmaster {
++    FTDMA020_AHBMASTER_0 = 0,
++    FTDMA020_AHBMASTER_1
++};
++
++/**
++ * struct ftdmac020_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @id: specify which ftdmac020 device to use, -1 for wildcard
++ * @handshake: hardware handshake number, -1 to disable handshake mode
++ */
++struct ftdmac020_dma_slave {
++	struct dma_slave_config common;
++	int id;
++	int handshake;      /* handshake number, -1 means disable */
++	enum ftdmac020_burst     src_size;   /* source burst size selection */
++	enum ftdmac020_ahbmaster src_sel;  /* AHB Master selection */
++	enum ftdmac020_ahbmaster dst_sel;  /* AHB Master selection */
++};
++
++/**
++ * ftdmac020_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftdmac020_dma_slave
++ */
++bool ftdmac020_chan_filter(struct dma_chan *chan, void *data);
++
++/**
++ * ftdmac020_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac020_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac020_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id));
++
++#endif	/* __FTDMAC020_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/ftdmac030.h b/arch/arm/mach-GM-Duo/include/mach/ftdmac030.h
+new file mode 100644
+index 00000000..7d8f6451
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/ftdmac030.h
+@@ -0,0 +1,188 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftdmac030.h
++ *
++ *  Faraday FTDMAC030 DMA controller
++ *
++ *  Copyright (C) 2011 Faraday Technology
++ *  Copyright (C) 2011 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTDMAC030_H
++#define __FTDMAC030_H
++
++#include <linux/dmaengine.h>
++
++#define FTDMAC030_OFFSET_ISR		0x0
++#define FTDMAC030_OFFSET_TCISR		0x4
++#define FTDMAC030_OFFSET_TCICR		0x8
++#define FTDMAC030_OFFSET_EAISR		0xc
++#define FTDMAC030_OFFSET_EAICR		0x10
++#define FTDMAC030_OFFSET_TCRAW		0x14
++#define FTDMAC030_OFFSET_EARAW		0x18
++#define FTDMAC030_OFFSET_CH_ENABLED	0x1c
++#define FTDMAC030_OFFSET_SYNC		0x20
++#define FTDMAC030_OFFSET_LDM		0x24
++#define FTDMAC030_OFFSET_WDT		0x28
++#define FTDMAC030_OFFSET_GE		    0x2c
++#define FTDMAC030_OFFSET_PSE		0x30
++#define FTDMAC030_OFFSET_REVISION	0x34
++#define FTDMAC030_OFFSET_FEATURE	0x38
++#define FTDMAC030_OFFSET_LDMFFS0	0x3c
++#define FTDMAC030_OFFSET_LDMFFS1	0x40
++#define FTDMAC030_OFFSET_LDMFFS2	0x44
++#define FTDMAC030_OFFSET_LDMFFS3	0x48
++
++#define FTDMAC030_OFFSET_CTRL_CH(x)	(0x100 + (x) * 0x20)
++#define FTDMAC030_OFFSET_CFG_CH(x)	(0x104 + (x) * 0x20)
++#define FTDMAC030_OFFSET_SRC_CH(x)	(0x108 + (x) * 0x20)
++#define FTDMAC030_OFFSET_DST_CH(x)	(0x10c + (x) * 0x20)
++#define FTDMAC030_OFFSET_LLP_CH(x)	(0x110 + (x) * 0x20)
++#define FTDMAC030_OFFSET_CYC_CH(x)	(0x114 + (x) * 0x20)
++#define FTDMAC030_OFFSET_STRIDE_CH(x)	(0x118 + (x) * 0x20)
++
++/*
++ * Error/abort interrupt status/clear register
++ * Error/abort status register
++ */
++#define FTDMAC030_EA_ERR_CH(x)		(1 << (x))
++#define FTDMAC030_EA_WDT_CH(x)		(1 << ((x) + 8))
++#define FTDMAC030_EA_ABT_CH(x)		(1 << ((x) + 16))
++
++/*
++ * Control register
++ */
++#define FTDMAC030_CTRL_WE(x)		((1 << (x)) & 0xff)
++#define FTDMAC030_CTRL_WSYNC		(1 << 8)
++#define FTDMAC030_CTRL_SE(x)		(((x) & 0x7) << 9)
++#define FTDMAC030_CTRL_SE_ENABLE	(1 << 12)
++#define FTDMAC030_CTRL_WE_ENABLE	(1 << 13)
++#define FTDMAC030_CTRL_2D		(1 << 14)
++#define FTDMAC030_CTRL_EXP		(1 << 15)
++#define FTDMAC030_CTRL_ENABLE		(1 << 16)
++#define FTDMAC030_CTRL_WDT_ENABLE	(1 << 17)
++#define FTDMAC030_CTRL_DST_INC		(0x0 << 18)
++#define FTDMAC030_CTRL_DST_FIXED	(0x2 << 18)
++#define FTDMAC030_CTRL_SRC_INC		(0x0 << 20)
++#define FTDMAC030_CTRL_SRC_FIXED	(0x2 << 20)
++#define FTDMAC030_CTRL_DST_WIDTH_8	(0x0 << 22)
++#define FTDMAC030_CTRL_DST_WIDTH_16	(0x1 << 22)
++#define FTDMAC030_CTRL_DST_WIDTH_32	(0x2 << 22)
++#define FTDMAC030_CTRL_DST_WIDTH_64	(0x3 << 22)
++#define FTDMAC030_CTRL_SRC_WIDTH_8	(0x0 << 25)
++#define FTDMAC030_CTRL_SRC_WIDTH_16	(0x1 << 25)
++#define FTDMAC030_CTRL_SRC_WIDTH_32	(0x2 << 25)
++#define FTDMAC030_CTRL_SRC_WIDTH_64	(0x3 << 25)
++#define FTDMAC030_CTRL_MASK_TC		(1 << 28)
++#define FTDMAC030_CTRL_1BEAT		(0x0 << 29)
++#define FTDMAC030_CTRL_2BEATS		(0x1 << 29)
++#define FTDMAC030_CTRL_4BEATS		(0x2 << 29)
++#define FTDMAC030_CTRL_8BEATS		(0x3 << 29)
++#define FTDMAC030_CTRL_16BEATS		(0x4 << 29)
++#define FTDMAC030_CTRL_32BEATS		(0x5 << 29)
++#define FTDMAC030_CTRL_64BEATS		(0x6 << 29)
++#define FTDMAC030_CTRL_128BEATS		(0x7 << 29)
++
++/*
++ * Configuration register
++ */
++#define FTDMAC030_CFG_MASK_TCI		(1 << 0)	/* mask tc interrupt */
++#define FTDMAC030_CFG_MASK_EI		(1 << 1)	/* mask error interrupt */
++#define FTDMAC030_CFG_MASK_AI		(1 << 2)	/* mask abort interrupt */
++#define FTDMAC030_CFG_SRC_HANDSHAKE(x)	(((x) & 0xf) << 3)
++#define FTDMAC030_CFG_SRC_HANDSHAKE_EN	(1 << 7)
++#define FTDMAC030_CFG_DST_HANDSHAKE(x)	(((x) & 0xf) << 9)
++#define FTDMAC030_CFG_DST_HANDSHAKE_EN	(1 << 13)
++#define FTDMAC030_CFG_LLP_CNT(cfg)	(((cfg) >> 16) & 0xf)
++#define FTDMAC030_CFG_GW(x)		(((x) & 0xff) << 20)
++#define FTDMAC030_CFG_HIGH_PRIO		(1 << 28)
++
++/*
++ * Transfer size register
++ */
++#define FTDMAC030_CYC_MASK		0x3fffff
++#define FTDMAC030_CYC_TOTAL(x)		((x) & FTDMAC030_CYC_MASK)
++#define FTDMAC030_CYC_2D(x, y)		(((x) & 0xffff) | (((y) & 0xffff) << 16))
++
++/*
++ * Stride register
++ */
++#define FTDMAC030_STRIDE_SRC(x)		((x) & 0xffff)
++#define FTDMAC030_STRIDE_DST(x)		(((x) & 0xffff) << 16)
++
++/**
++ * struct ftdmac030_lld - hardware link list descriptor.
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the next link list descriptor
++ * @ctrl: control field
++ * @cycle: transfer size
++ * @stride: stride for 2D mode
++ *
++ * should be 32 or 64 bits aligned depends on AXI configuration
++ */
++struct ftdmac030_lld {
++	dma_addr_t src;
++	dma_addr_t dst;
++	dma_addr_t next;
++	unsigned int ctrl;
++	unsigned int cycle;
++	unsigned int stride;
++};
++
++enum ftdmac030_channels {
++	FTDMAC030_CHANNEL_0 = (1 << 0),
++	FTDMAC030_CHANNEL_1 = (1 << 1),
++	FTDMAC030_CHANNEL_2 = (1 << 2),
++	FTDMAC030_CHANNEL_3 = (1 << 3),
++	FTDMAC030_CHANNEL_4 = (1 << 4),
++	FTDMAC030_CHANNEL_5 = (1 << 5),
++	FTDMAC030_CHANNEL_6 = (1 << 6),
++	FTDMAC030_CHANNEL_7 = (1 << 7),
++	FTDMAC030_CHANNEL_ALL = 0xff,
++};
++
++/**
++ * struct ftdmac030_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @id: specify which ftdmac030 device to use, -1 for wildcard
++ * @channels: bitmap of usable DMA channels
++ * @handshake: hardware handshake number, -1 to disable handshake mode
++ */
++struct ftdmac030_dma_slave {
++	struct dma_slave_config common;
++	int id;
++	enum ftdmac030_channels channels;
++	int handshake;
++};
++
++/**
++ * ftdmac030_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftdmac030_dma_slave
++ */
++bool ftdmac030_chan_filter(struct dma_chan *chan, void *data);
++
++/**
++ * ftdmac030_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac030_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac030_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id));
++
++#endif	/* __FTDMAC030_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/ftintc010.h b/arch/arm/mach-GM-Duo/include/mach/ftintc010.h
+new file mode 100644
+index 00000000..0dcb320e
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/ftintc010.h
+@@ -0,0 +1,89 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/ftintc010.h
++ *
++ *  Faraday FTINTC010 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef __FTINTC010_H
++#define __FTINTC010_H
++
++#define FTINTC010_OFFSET_IRQSRC		0x00
++#define FTINTC010_OFFSET_IRQMASK	0x04
++#define FTINTC010_OFFSET_IRQCLEAR	0x08
++#define FTINTC010_OFFSET_IRQMODE	0x0c
++#define FTINTC010_OFFSET_IRQLEVEL	0x10
++#define FTINTC010_OFFSET_IRQSTATUS	0x14
++
++#define FTINTC010_OFFSET_FIQSRC		0x20
++#define FTINTC010_OFFSET_FIQMASK	0x24
++#define FTINTC010_OFFSET_FIQCLEAR	0x28
++#define FTINTC010_OFFSET_FIQMODE	0x2c
++#define FTINTC010_OFFSET_FIQLEVEL	0x30
++#define FTINTC010_OFFSET_FIQSTATUS	0x34
++
++#define FTINTC010_OFFSET_IRQSRCEX	0x60
++#define FTINTC010_OFFSET_IRQMASKEX	0x64
++#define FTINTC010_OFFSET_IRQCLEAREX	0x68
++#define FTINTC010_OFFSET_IRQMODEEX	0x6c
++#define FTINTC010_OFFSET_IRQLEVELEX	0x70
++#define FTINTC010_OFFSET_IRQSTATUSEX	0x74
++
++#define FTINTC010_OFFSET_FIQSRCEX		0x80
++#define FTINTC010_OFFSET_FIQMASKEX	    0x84
++#define FTINTC010_OFFSET_FIQCLEAREX	    0x88
++#define FTINTC010_OFFSET_FIQMODEEX	    0x8c
++#define FTINTC010_OFFSET_FIQLEVELEX	    0x90
++#define FTINTC010_OFFSET_FIQSTATUSEX	0x94
++
++#define FTINTC030_OFFSET_IRQPEND	0x14//IRQSTATUS
++#define FTINTC030_OFFSET_IRQPEND1	0x34
++
++#ifndef __ASSEMBLY__
++struct ftintc010_trigger_type {
++	unsigned int irqmode;
++	unsigned int irqlevel;
++	unsigned int fiqmode;
++	unsigned int fiqlevel;
++#ifdef CONFIG_FTINTC010EX
++	unsigned int irqmodeex;
++	unsigned int irqlevelex;
++	unsigned int fiqmodeex;
++	unsigned int fiqlevelex;
++#endif
++};
++
++#include <linux/irq.h>
++
++struct ftintc010_chip_data {
++	unsigned int irq_offset;
++	void __iomem *base;
++};
++
++void __init ftintc010_init(unsigned int ftintc010_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc010_trigger_type *trigger_type);
++/* reconfigure the irq type. Maybe the original is edge trigger, now change to level trigger 
++ * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
++ */
++int ftintc010_set_irq_type(unsigned int irq, unsigned int type);
++			   
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FTINTC010_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/ftintc030.h b/arch/arm/mach-GM-Duo/include/mach/ftintc030.h
+new file mode 100644
+index 00000000..b4c27632
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/ftintc030.h
+@@ -0,0 +1,87 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftintc030.h
++ *
++ *  Faraday FTINTC030 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef __FTINTC030_H
++#define __FTINTC030_H
++
++
++#define FTINTC030_OFFSET_IRQSRC		0x00
++#define FTINTC030_OFFSET_IRQENABLE  0x04
++#define FTINTC030_OFFSET_IRQCLEAR	0x08
++#define FTINTC030_OFFSET_IRQMODE	0x0c
++#define FTINTC030_OFFSET_IRQLEVEL	0x10
++#define FTINTC030_OFFSET_IRQPEND	0x14//IRQSTATUS
++#define FTINTC030_OFFSET_IRQPEND1	0x34
++
++
++#define FTINTC030_OFFSET_IRQCONFIG	0x200
++//#define FTINTC030_OFFSET_IRQTARGET	0x420
++
++#define FTINTC030_OFFSET_CPU_0_FIQ	0x420
++#define FTINTC030_OFFSET_CPU_0_IRQ	0x45C
++#define FTINTC030_OFFSET_CPU_1_FIQ	0x498
++#define FTINTC030_OFFSET_CPU_1_IRQ	0x4D4
++#define FTINTC030_OFFSET_CPU_2_FIQ	0x510
++#define FTINTC030_OFFSET_CPU_2_IRQ	0x54C
++#define FTINTC030_OFFSET_CPU_3_FIQ	0x588
++#define FTINTC030_OFFSET_CPU_3_IRQ	0x5C4
++
++#define FTINTC010_OFFSET_FIQCLEAREX	0x88
++
++#ifndef __ASSEMBLY__
++struct ftintc030_trigger_type {
++	unsigned int irqmode[15];
++	unsigned int irqlevel[15];
++	unsigned int fiqmode[15];
++	unsigned int fiqlevel[15];
++};
++
++/* IRQ */
++#define FTINTC030_TARGETIRQ_CPU0   0x1
++#define FTINTC030_TARGETIRQ_CPU1   0x2
++#define FTINTC030_TARGETIRQ_CPU2   0x4
++#define FTINTC030_TARGETIRQ_CPU3   0x8
++/* FIQ */
++#define FTINTC030_TARGETFIQ_CPU0   0x1
++#define FTINTC030_TARGETFIQ_CPU1   0x2
++#define FTINTC030_TARGETFIQ_CPU2   0x4
++#define FTINTC030_TARGETFIQ_CPU3   0x8
++
++void __init ftintc030_cascade_irq(unsigned int ftintc030_nr, unsigned int irq);
++
++void __init ftintc030_init(unsigned int ftintc030_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc030_trigger_type *trigger_type);
++
++/*
++ * Set a highlevel chained flow handler for a given IRQ.
++ * ftintc030_nr: INTC030 index
++ * irq: which irq number is the cascade irq
++ * handler: the handler function of this cascade irq
++ * handler_data: private data of the handler
++ */
++void ftintc030_setup_chain_irq(unsigned int ftintc030_nr, unsigned int irq, void *handler, void *handler_data);
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FTINTC030_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/ftpmu010.h b/arch/arm/mach-GM-Duo/include/mach/ftpmu010.h
+new file mode 100644
+index 00000000..ffa90812
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/ftpmu010.h
+@@ -0,0 +1,272 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/ftpmu010.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __FTPMU010_H
++#define __FTPMU010_H
++
++#include <mach/platform/pmu.h>
++
++#define PMU010_NAME "ftpmu010"
++#define NAME_SZ     20
++
++
++/*  MACROs for reading clock source
++ */
++#define PLL1_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL1)
++#define PLL2_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL2)
++#define PLL3_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL3)
++#define PLL4_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL4)
++#define PLL5_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL5)
++#define AXI_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_AXI)
++#define AHB_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_AHB)
++//#define APB_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_APB)
++#define APB0_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_APB0)
++#define APB1_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_APB1)
++#define APB2_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_APB2)
++#define CPU_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_CPU)
++
++typedef enum {
++    FTPMU_H264E_0 = 0x1,
++    FTPMU_H264D_0,
++    FTPMU_H264E_1,
++    FTPMU_H264D_1,
++    FTPMU_SCALER_0,
++    FTPMU_SCALER_1,
++    FTPMU_3DI_0,
++    FTPMU_3DI_1,
++    FTPMU_LCD_0,
++    FTPMU_LCD_1,
++    FTPMU_LCD_2,
++    FTPMU_CAP_0,
++    FTPMU_CAP_1,
++    FTPMU_CAP_2,
++    FTPMU_CAP_3,
++    FTPMU_ISP_0,
++    FTPMU_ISP_1,
++    FTPMU_AES,
++    FTPMU_MCP100_0,
++    FTPMU_NONE = 0xFFFFF,
++} ftpmu010_midx_t;
++
++typedef struct {
++    ftpmu010_midx_t midx;   /* module idx */
++    int             num;    /* number of clock gate */
++    struct {
++        unsigned int ofs;
++        unsigned int bit_val;    //specify the enable value
++        unsigned int bit_mask;   //specify gating clock bits
++    } reg[3];
++} ftpmu010_gate_clk_t;
++
++/* PMU init function
++ * Input parameters: virtual address of PMU
++ *  tbl: clock gating table for IPs
++ *  pmu_handler: the callback from pmu to reload/reconfigure pmu. NULL if unecessary
++ * Return: 0 for success, < 0 for fail
++ */
++int ftpmu010_init(void __iomem  *base, ftpmu010_gate_clk_t *tbl, void *pmu_handler);
++
++typedef enum
++{
++    ATTR_TYPE_NONE = 0,
++    ATTR_TYPE_PLL1,
++    ATTR_TYPE_PLL2,
++    ATTR_TYPE_PLL3,
++    ATTR_TYPE_PLL4,
++    ATTR_TYPE_PLL5,
++    ATTR_TYPE_AXI,
++    ATTR_TYPE_AHB,
++    ATTR_TYPE_APB,
++    ATTR_TYPE_APB0,
++    ATTR_TYPE_APB1,
++    ATTR_TYPE_APB2,
++    ATTR_TYPE_CPU,
++    ATTR_TYPE_PMUVER,
++    ATTR_TYPE_CHIPVER,  //format: xxxx_yyyy. xxxx: 8210, yyyy:IC revision
++    ATTR_TYPE_SYSCLK,
++    ATTR_TYPE_EPCNT,
++    ATTR_TYPE_CPUENUM,  //for: 0 for RC_FA726, 1: RC_FA626, 2: RC_fC7500......
++} ATTR_TYPE_T;
++
++/* cpu enumerator in whole system */
++typedef enum {
++    CPU_RC_FA726    = 0,
++    CPU_RC_FA626    = 1,
++    CPU_RC_FC7500   = 2,
++    CPU_EP0_FA726   = 3,
++    CPU_EP0_FA626   = 4,
++    CPU_EP0_FC7500  = 5,
++} attr_cpu_enum_t;
++
++typedef enum {
++    PMUVER_A = 0,
++    PMUVER_B,
++    PMUVER_C,
++    PMUVER_D,
++    PMUVER_UNKNOWN,
++} pmuver_t;
++
++typedef struct
++{
++    char          name[NAME_SZ+1];    /* hclk, .... */
++    ATTR_TYPE_T   attr_type;
++    unsigned int  value;
++} attrInfo_t;
++
++/* register attribute
++ */
++int ftpmu010_register_attr(attrInfo_t *attr);
++int ftpmu010_deregister_attr(attrInfo_t *attr);
++/* get attribute value
++ * return value: 0 for fail, > 0 for success
++ */
++unsigned int ftpmu010_get_attr(ATTR_TYPE_T attr);
++
++
++/*
++ * Structure for pinMux
++ */
++typedef struct
++{
++    unsigned int  reg_off;    /* register offset from PMU base */
++    unsigned int  bits_mask;  /* bits this module covers */
++    unsigned int  lock_bits;  /* bits this module locked */
++    unsigned int  init_val;   /* initial value */
++    unsigned int  init_mask;  /* initial mask */
++} pmuReg_t;
++
++typedef struct
++{
++    char        name[NAME_SZ+1];    /* module name length */
++    int         num;                /* number of register entries */
++    ATTR_TYPE_T clock_src;          /* which clock this module uses */
++    pmuReg_t    *pRegArray;         /* register array */
++} pmuRegInfo_t;
++
++/* register/de-register the register table
++ * return value:
++ *  give an unique fd if return value >= 0, otherwise < 0 if fail.
++ */
++int ftpmu010_register_reg(pmuRegInfo_t *info);
++int ftpmu010_deregister_reg(int fd);
++
++/* lock/unlock/replace the bits in lock_bits field
++ * return value:
++ *  0 for success, < 0 for fail
++ */
++int ftpmu010_add_lockbits(int fd, unsigned int reg_off, unsigned int lock_bits);
++int ftpmu010_del_lockbits(int fd, unsigned int reg_off, unsigned int unlock_bits);
++int ftpmu010_update_lockbits(int fd, unsigned int reg_off, unsigned int new_lock_bits);
++/* @int ftpmu010_bits_is_locked(int reg_off, unsigned int bits)
++ * @Purpose: This function is used to check if the bits are locked by any module or not.
++ * @Parameter:
++ *   reg_off: register offset
++ *   bits: the checked bits
++ * @Return:
++ *      If the any bit in bits is locked, then the returned value will be 0
++ *      otherwise, -1 is returned to indicates all bits are available.
++ *
++ */
++int ftpmu010_bits_is_locked(int fd, unsigned int reg_off, unsigned int bits);
++
++/* PMU register read/write
++ */
++unsigned int ftpmu010_read_reg(unsigned int reg_off);
++/* return value < 0 for fail */
++int ftpmu010_write_reg(int fd, unsigned int reg_off, unsigned int val, unsigned int mask);
++
++/* Purpose: calculate the divisor by input clock
++ * Input: fd, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor(int fd, unsigned int in_clock, int near);
++
++/* Purpose: calculate the divisor by input clock attribute
++ * Input: clock_src, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor2(ATTR_TYPE_T clock_src, unsigned int in_clock, int near);
++
++/* @Purpose: request the pmu PINs
++ * @Parameter:
++ *      fd: unique identifier
++ *      reg_off: register offset
++ *      req_bits: request registers
++ *      b_wait: 1 for blocking until the resource is available
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_request_pins(int fd, unsigned int reg_off, unsigned int req_bits, int b_wait);
++
++
++/* Purpose: release the pmu PINs
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_release_pins(int fd, unsigned int reg_off, unsigned int req_bits);
++
++/* Purpose: check if the PINs was requested by others except myself.
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: those pins occupied by others. zero indicates the pin are available.
++ */
++unsigned int ftpmu010_pins_is_requested(int fd, unsigned int reg_off, unsigned int req_bits);
++
++/*
++ * The following is used for specific functionality to PMU
++ */
++#define FUNC_TYPE_RELOAD_ATTR   0
++#define FUNC_TYPE_INTR_CLR      1
++#define FUNC_TYPE_INTR_FIRE     2
++
++/*
++ * The following function are used for module to send/clear interrupt.
++ * return: 0 for success, -1 for fail
++ */
++/* send interrupt from pmu */
++static inline int ftpmu010_trigger_intr(int irq)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_INTR_FIRE , irq, 0);
++}
++/* clear interupt in pmu */
++static inline int ftpmu010_clear_intr(int irq)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_INTR_CLR , irq, 0);
++}
++/* force the attribute refresh again */
++static inline int ftpmu010_reload_attr(ATTR_TYPE_T attr_type)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_RELOAD_ATTR , attr_type, 0);
++}
++
++#endif	/* __FTPMU010_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/ftpmu010_pcie.h b/arch/arm/mach-GM-Duo/include/mach/ftpmu010_pcie.h
+new file mode 100644
+index 00000000..32701324
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/ftpmu010_pcie.h
+@@ -0,0 +1,115 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/ftpmu010_pcie.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __FTPMU010_PCIE_H__
++#define __FTPMU010_PCIE_H__
++
++#include <mach/ftpmu010.h>
++
++#define GM8312_CHIP_ID  0x831210
++#define PCIE_NAME_SZ    20
++
++/*  MACROs for reading clock source
++ */
++#define PCIE_PLL1_CLK_IN    ftpmu010_pcie_get_attr(ATTR_TYPE_PCIE_PLL1)
++#define PCIE_AXI_CLK_IN     ftpmu010_pcie_get_attr(ATTR_TYPE_PCIE_AXI)
++#define PCIE_AHB_CLK_IN     ftpmu010_pcie_get_attr(ATTR_TYPE_PCIE_AHB)
++#define PCIE_APB_CLK_IN     ftpmu010_pcie_get_attr(ATTR_TYPE_PCIE_APB)
++
++typedef enum {
++    FTPMU_PCIE_SATA_0 = 0x1,
++    FTPMU_PCIE_NONE = 0xFFFFF,
++} ftpmu010_pcie_midx_t;
++
++typedef struct {
++    ftpmu010_pcie_midx_t midx;   /* module idx */
++    int             num;    /* number of clock gate */
++    struct {
++        unsigned int ofs;
++        unsigned int bit_val;    //specify the enable value
++        unsigned int bit_mask;   //specify gating clock bits
++    } reg[3];
++} ftpmu010_pcie_gate_clk_t;
++
++typedef enum
++{
++    ATTR_TYPE_PCIE_NONE = 0,
++    ATTR_TYPE_PCIE_PLL1,
++    ATTR_TYPE_PCIE_AXI,
++    ATTR_TYPE_PCIE_AHB,
++    ATTR_TYPE_PCIE_APB,
++    ATTR_TYPE_PCIE_PMUVER,
++} ATTR_PCIE_TYPE_T;
++
++typedef struct
++{
++    char                name[PCIE_NAME_SZ + 1];    /* hclk, .... */
++    ATTR_PCIE_TYPE_T    attr_type;
++    unsigned int        value;
++} attrPcieInfo_t;
++
++/* register attribute
++ */
++int ftpmu010_pcie_register_attr(attrPcieInfo_t *attr);
++int ftpmu010_pcie_deregister_attr(attrPcieInfo_t *attr);
++/* get attribute value
++ * return value: 0 for fail, > 0 for success
++ */
++unsigned int ftpmu010_pcie_get_attr(ATTR_PCIE_TYPE_T attr);
++
++/*
++ * Structure for pinMux
++ */
++typedef struct
++{
++    unsigned int  reg_off;    /* register offset from PMU base */
++    unsigned int  bits_mask;  /* bits this module covers */
++    unsigned int  lock_bits;  /* bits this module locked */
++    unsigned int  init_val;   /* initial value */
++    unsigned int  init_mask;  /* initial mask */
++} pmuPcieReg_t;
++
++typedef struct
++{
++    char                name[PCIE_NAME_SZ + 1];    /* module name length */
++    int                 num;                /* number of register entries */
++    ATTR_PCIE_TYPE_T    clock_src;          /* which clock this module uses */
++    pmuPcieReg_t        *pRegArray;         /* register array */
++} pmuPcieRegInfo_t;
++
++/* PMU init function
++ * Input parameters: virtual address of PMU
++ *  tbl: clock gating table for IPs
++ *  pmu_handler: the callback from pmu to reload/reconfigure pmu. NULL if unecessary
++ * Return: 0 for success, < 0 for fail
++ */
++int ftpmu010_pcie_init(void __iomem  *base, ftpmu010_pcie_gate_clk_t *tbl, void *pmu_handler);
++
++/* register/de-register the register table
++ * return value:
++ *  give an unique fd if return value >= 0, otherwise < 0 if fail.
++ */
++int ftpmu010_pcie_register_reg(pmuPcieRegInfo_t *info);
++int ftpmu010_pcie_deregister_reg(int fd);
++
++unsigned int ftpmu010_pcie_read_reg(unsigned int reg_off);
++int ftpmu010_pcie_write_reg(int fd, unsigned int reg_off, unsigned int val, unsigned int mask);
++
++#endif	/* __FTPMU010_PCIE_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/fttmr010.h b/arch/arm/mach-GM-Duo/include/mach/fttmr010.h
+new file mode 100644
+index 00000000..4f10f121
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/fttmr010.h
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (C) 2009 Po-Yu Chuang
++ * Copyright (C) 2009 Faraday Technology
++ *
++ * 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.
++ */
++
++/*
++ * Timer
++ */
++#ifndef __FTTMR010_H
++#define __FTTMR010_H
++
++#define FTTMR010_OFFSET_COUNTER		0x00
++#define FTTMR010_OFFSET_LOAD		0x04
++#define FTTMR010_OFFSET_MATCH1		0x08
++#define FTTMR010_OFFSET_MATCH2		0x0c
++#define FTTMR010_OFFSET_TIMER(x)	((x) * 0x10)
++#define FTTMR010_OFFSET_CR		0x30
++#define FTTMR010_OFFSET_INTR_STATE	0x34
++#define FTTMR010_OFFSET_INTR_MASK	0x38
++
++/*
++ * Timer Control Register
++ */
++#define FTTMR010_TM3_UPDOWN	(1 << 11)
++#define FTTMR010_TM2_UPDOWN	(1 << 10)
++#define FTTMR010_TM1_UPDOWN	(1 << 9)
++#define FTTMR010_TM3_OFENABLE	(1 << 8)
++#define FTTMR010_TM3_CLOCK	(1 << 7)
++#define FTTMR010_TM3_ENABLE	(1 << 6)
++#define FTTMR010_TM2_OFENABLE	(1 << 5)
++#define FTTMR010_TM2_CLOCK	(1 << 4)
++#define FTTMR010_TM2_ENABLE	(1 << 3)
++#define FTTMR010_TM1_OFENABLE	(1 << 2)
++#define FTTMR010_TM1_CLOCK	(1 << 1)
++#define FTTMR010_TM1_ENABLE	(1 << 0)
++
++/*
++ * Timer Interrupt State & Mask Registers
++ */
++#define FTTMR010_TM3_OVERFLOW	(1 << 8)
++#define FTTMR010_TM3_MATCH2	(1 << 7)
++#define FTTMR010_TM3_MATCH1	(1 << 6)
++#define FTTMR010_TM2_OVERFLOW	(1 << 5)
++#define FTTMR010_TM2_MATCH2	(1 << 4)
++#define FTTMR010_TM2_MATCH1	(1 << 3)
++#define FTTMR010_TM1_OVERFLOW	(1 << 2)
++#define FTTMR010_TM1_MATCH2	(1 << 1)
++#define FTTMR010_TM1_MATCH1	(1 << 0)
++
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++
++struct fttmr010_clockevent {
++	struct clock_event_device	clockevent;
++	struct irqaction		irqaction;
++	void __iomem			*base;
++	unsigned int			id;	/* one of 3 counters */
++	unsigned int			reload;
++	unsigned int			freq;
++};
++
++struct fttmr010_clocksource {
++	struct clocksource	clocksource;
++	void __iomem		*base;
++	unsigned int		id;	/* one of 3 counters */
++	unsigned int		freq;
++};
++
++void __init fttmr010_clockevent_init(struct fttmr010_clockevent *fttmr010);
++void __init fttmr010_clocksource_init(struct fttmr010_clocksource *fttmr010);
++
++#endif	/* __FTTMR010_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/gm_jiffies.h b/arch/arm/mach-GM-Duo/include/mach/gm_jiffies.h
+new file mode 100644
+index 00000000..66d4196b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/gm_jiffies.h
+@@ -0,0 +1,27 @@
++#ifndef __GM_JIFFIES_H__
++#define __GM_JIFFIES_H__
++
++#define gm_jiffies      get_gm_jiffies()
++#define gm_jiffies_u64  get_gm_jiffies_u64()
++
++/* @unsigned long get_gm_jiffies(void)
++ * @Purpose: This function provides jiffies with 1ms granularity. This value will count up to 0xFFFFFFFF
++ *           and warp around again.
++ * @Parameter:
++ *   None
++ * @Return:
++ *      0 means the timer is not active. Othwise return non-zero value.
++ */
++unsigned long get_gm_jiffies(void);
++
++/* @u64 get_gm_jiffies_u64(void)
++ * @Purpose: This function provides jiffies with 1ms granularity. This value will count up to 0xFFFFFFFFFFFFFFFF
++ *           and warp around again.
++ * @Parameter:
++ *   None
++ * @Return:
++ *      0 means the timer is not active. Othwise return non-zero value.
++ */
++u64 get_gm_jiffies_u64(void);
++
++#endif /* __GM_JIFFIES_H__ */
+\ No newline at end of file
+diff --git a/arch/arm/mach-GM-Duo/include/mach/hardware.h b/arch/arm/mach-GM-Duo/include/mach/hardware.h
+new file mode 100644
+index 00000000..d9f6c7ba
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/hardware.h
+@@ -0,0 +1,38 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/hardware.h
++ *
++ *  This file contains the hardware definitions of the Faraday boards.
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_H
++#define __ASM_ARCH_HARDWARE_H
++
++#ifndef PCIBIOS_MIN_IO
++/* the mini io address is 0x6000,that is IO will allocate from 0-0x6000 offset*/
++#define PCIBIOS_MIN_IO	0x0
++#endif
++
++#ifndef PCIBIOS_MIN_MEM
++/* the mini MEM address is 0x100000,that is MEM will allocate from 0-0x100000 offset*/
++#define PCIBIOS_MIN_MEM	0x0
++#endif
++
++#define pcibios_assign_all_busses()	1
++
++#endif /* __ASM_ARCH_HARDWARE_H */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/io.h b/arch/arm/mach-GM-Duo/include/mach/io.h
+new file mode 100644
+index 00000000..fa708459
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/io.h
+@@ -0,0 +1,18 @@
++/* arch/arm/mach-GM-Duo/include/mach/io.h
++ *
++ * Copyright 2008 Simtec Electronics
++ *	Ben Dooks <ben-linux@fluff.org>
++ *
++ * Default IO routines for S3C64XX based
++ */
++
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++/* No current ISA/PCI bus support. */
++#define __io(a)		((void __iomem *)(a))//__typesafe_io(a)
++#define __mem_pci(a)	(a)
++
++#define IO_SPACE_LIMIT (0xFFFFFFFF)
++
++#endif
+diff --git a/arch/arm/mach-GM-Duo/include/mach/irqs.h b/arch/arm/mach-GM-Duo/include/mach/irqs.h
+new file mode 100644
+index 00000000..bf7fd327
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/irqs.h
+@@ -0,0 +1,34 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/irqs.h
++ *
++ *  Faraday Platform Independent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 09/16/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__
++
++/* Include platform *dependent* IRQ definitions */
++#include <mach/platform/irqs.h>
++
++#endif /* __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__ */
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/memory.h b/arch/arm/mach-GM-Duo/include/mach/memory.h
+new file mode 100644
+index 00000000..d5a4a6ee
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/memory.h
+@@ -0,0 +1,48 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/memory.h
++ *  
++ *  Faraday Platform Independent Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ *  Harry Hsu 04/06/2010 add "isolate high memory" function
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__
++
++#include <asm/sizes.h>
++#include <mach/platform/memory.h>
++#include <mach/platform/platform_io.h>
++
++#define MEM_SIZE        SZ_256M
++#define END_MEM		    (CPU_MEM_PA_LIMIT + 1)
++
++#define CONSISTENT_DMA_SIZE  (12 << 20)	/* 12M NISH_20121015 */
++
++#ifndef __ASSEMBLY__
++extern unsigned long fmem_virt_to_phys(unsigned int vaddr);
++extern unsigned int fmem_phys_to_virt(unsigned long phys);
++
++#define __virt_to_phys(x)	fmem_virt_to_phys((unsigned int)(x))  //((x) - PAGE_OFFSET + PHYS_OFFSET)
++#define __phys_to_virt(x)	fmem_phys_to_virt((unsigned long)(x))  //((x) - PHYS_OFFSET + PAGE_OFFSET)
++#endif /* __ASSEMBLY__ */
++
++#endif /* __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/board.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/board.h
+new file mode 100644
+index 00000000..9e4871ba
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/board.h
+@@ -0,0 +1,132 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/board.h
++ *
++ *  GM board Independent Specification
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ *  ChangeLog
++ *
++ *   Harry  2012/3/6 03:15 created.
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM8210"
++#define BOOT_PARAMETER_PA_OFFSET  0x100
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0x99000000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE    0x98300000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        9
++
++#define UART_FTUART010_2_PA_BASE    0x98500000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        20
++
++#define UART_FTUART010_3_PA_BASE    0x98800000
++#define UART_FTUART010_3_VA_BASE    (UART_FTUART010_2_VA_BASE + UART_FTUART010_2_VA_SIZE)
++#define UART_FTUART010_3_VA_SIZE    SZ_4K
++#define UART_FTUART010_3_IRQ        21
++
++#define UART_FTUART010_4_PA_BASE    0x98900000
++#define UART_FTUART010_4_VA_BASE    (UART_FTUART010_3_VA_BASE + UART_FTUART010_3_VA_SIZE)
++#define UART_FTUART010_4_VA_SIZE    SZ_4K
++#define UART_FTUART010_4_IRQ        22
++
++#define UART_FTUART010_5_PA_BASE    0x82600000
++#define UART_FTUART010_5_VA_BASE    (UART_FTUART010_4_VA_BASE + UART_FTUART010_4_VA_SIZE)
++#define UART_FTUART010_5_VA_SIZE    SZ_4K
++#define UART_FTUART010_5_IRQ        25
++
++/* TIMER */
++#define TIMER_FTTMR010_PA_BASE	    0x99100000
++#define TIMER_FTTMR010_VA_BASE	    (UART_FTUART010_5_VA_BASE + UART_FTUART010_5_VA_SIZE)
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         14
++#define TIMER_FTTMR010_IRQ1         14
++#define TIMER_FTTMR010_IRQ2         14
++
++/* INTC030 */
++#define INTC_FTINTC030_PA_BASE      0x96000000
++#define INTC_FTINTC030_VA_BASE      (TIMER_FTTMR010_VA_BASE + TIMER_FTTMR010_VA_SIZE)
++#define INTC_FTINTC030_VA_SIZE	    SZ_4K
++
++/* PCI_PMU */
++#define PCIPMU_FTPMU010_PA_BASE     0xA2700000
++#define PCIPMU_FTPMU010_VA_BASE     (INTC_FTINTC030_VA_BASE + INTC_FTINTC030_VA_SIZE)
++#define PCIPMU_FTPMU010_VA_SIZE     SZ_4K
++
++/* INTC010 */
++#define INTC_FTINTC010_PA_BASE      0xA2800000
++#define INTC_FTINTC010_VA_BASE      (PCIPMU_FTPMU010_VA_BASE + PCIPMU_FTPMU010_VA_SIZE)
++#define INTC_FTINTC010_VA_SIZE	    SZ_4K
++
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++
++#define BOARD_BUS_LOCK_SUPPORT      1
++
++typedef enum {
++    BUS_LOCK_I2C = 0,
++    BUS_LOCK_NAND,
++    BUS_LOCK_SPINOR,
++} bus_lock_t;
++
++void board_bus_lock_init(bus_lock_t bus);
++void board_bus_lock(bus_lock_t bus);
++void board_bus_unlock(bus_lock_t bus);
++/* return value:
++ *  -1 for fail which means the bus was locked by others
++ *  0 for grab the lock success
++ */
++int board_bus_trylock(bus_lock_t bus);
++
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/gpio.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/gpio.h
+new file mode 100644
+index 00000000..c26a9e86
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8126_GPIO_H__
++#define __GM8126_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		3
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8126_GPIO_H__
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/irqs.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/irqs.h
+new file mode 100644
+index 00000000..45887a1b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/irqs.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/irqs.h
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Justin Shih  10/06/2012  Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/memory.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/memory.h
+new file mode 100644
+index 00000000..f8a76bab
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/memory.h
+@@ -0,0 +1,64 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/memory.h
++ *  
++ *  GM Platform Dependent Memory Configuration
++ *  
++ * 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
++ *  
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define PHYS_OFFSET     CPU_MEM_PA_BASE//0x0
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management. 
++ *
++ * Users can adjust the memory size based on the real memory size requirement.  
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     0x1000000
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement. 
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE. 
++ * The memory boundary is 16M alginment 
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/platform_io.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/platform_io.h
+new file mode 100644
+index 00000000..690464ad
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/platform_io.h
+@@ -0,0 +1,922 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/platform_io.h
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++#define PLATFORM_FIQ_BASE       0
++#define PLATFORM_IRQ_TOTALCOUNT		96/* interrupt controller supports 96 interrupts */
++#define PLATFORM_GM8312_IRQ_TOTALCOUNT 	32
++#define PLATFORM_GM8312_IRQ_BASE      	PLATFORM_IRQ_TOTALCOUNT
++#define PLATFORM_INTERRUPTS     (PLATFORM_IRQ_TOTALCOUNT + PLATFORM_GM8312_IRQ_TOTALCOUNT)
++#define CPU_MEM_PA_BASE         0x01000000     /* the memory physical start address(DDR) */
++
++/*
++ * Component counts
++ */
++
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	2
++#define GPIO_FTGPIO010_COUNT	2
++/* I2C */
++#define I2C_COUNT	6
++#define I2C_FTI2C010_COUNT	6
++/* SSP */
++#define SSP_COUNT	6
++#define SSP_FTSSP010_COUNT	6
++/* SPI020 */
++#define SPI_COUNT	1
++#define SPI_FTSPI020_COUNT	1
++/* SDC */
++#define SDC_COUNT	1
++#define SDC_FTSDC021_COUNT	1
++/* NAND */
++#define NAND_COUNT	1
++#define NAND_FTNAND023_COUNT	1
++/* NANDDP */
++#define NANDDP_COUNT	1
++#define NANDDP_FTNAND023_COUNT	1
++/* LCD */
++#define LCD_COUNT	3
++#define LCD_FTLCDC200_COUNT	3
++/* SMC */
++#define SMC_COUNT	1
++#define SMC_FTSMC010_COUNT	1
++/* 2D GRAPHIC */
++#define GRA_COUNT	1
++#define GRA_FT2DGRA_COUNT	1
++/* MAC */
++#define MAC_COUNT	2
++#define MAC_FTGMAC100_COUNT	2
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* CAP */
++#define CAP_COUNT	1
++#define CAP_FTCAP300_COUNT	2
++/* DI3D */
++#define DI3D_COUNT	2
++#define DI3D_FTDI3D_COUNT	2
++/* H264E */
++#define H264E_COUNT	2
++#define H264E_FTMCP280_COUNT	2
++/* H264D */
++#define H264D_COUNT	2
++#define H264D_FTMCP300_COUNT	2
++/* MCP */
++#define MCP_COUNT	1
++#define MCP_FTMCP100_COUNT	1
++/* IR_DET */
++#define IR_DET_COUNT	1
++#define IR_DET_FTIRDET_COUNT	1
++/* KPD */
++#define KPD_COUNT	1
++#define KPD_FTKPD_COUNT	1
++/* PCIE */
++#define PCIE_COUNT	2
++#define PCIE_FTPCI100_COUNT	2
++/* SATA */
++#define SATA_COUNT	4
++#define SATA_FTSATA100_COUNT	4
++/* OTG */
++#define OTG_COUNT	3
++#define USB_FOTG2XX_COUNT	3
++/* TVE */
++#define TVE_COUNT	1
++#define TVE_FTTVE100_COUNT	1
++/* HDMI */
++#define HDMI_COUNT	1
++#define HDMI_FTHDMI_COUNT	1
++/* AHBC */
++#define AHBC_COUNT	1
++#define AHBC_FTAHBC020_COUNT	1
++/* APBB */
++#define APBB_COUNT	3
++#define APBB_FTAPBB020_COUNT	3
++/* DMAC */
++#define DMAC_COUNT	2
++#define DMAC_FTDMAC020_COUNT	2
++/* XDMAC */
++#define XDMAC_COUNT	1
++#define XDMAC_FTDMAC030_COUNT	1
++/* I2S_PCIE */
++#define I2S_PCIE_COUNT	2
++#define I2S_PCIE_FTSSP010_COUNT	2
++/* I2C_PCIE */
++#define I2C_PCIE_COUNT	4
++#define I2C_PCIE_FTSSP010_COUNT	4
++/* SCAL */
++#define SCAL_COUNT  2
++#define SCAL_FTSCAL300_COUNT    2
++
++/*
++ * Interrrupt numbers
++ */
++/* DDR IRQ */
++#define DDRC_IRQ_COUNT  2
++#define DDRC0_IRQ       26
++#define DDRC1_IRQ       27
++
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	16
++#define WDT_FTWDT010_0_IRQ	16
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	1
++#define GPIO_FTGPIO010_IRQ	13
++#define GPIO_FTGPIO010_0_IRQ	13
++#define GPIO_FTGPIO010_1_IRQ	63
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	18
++#define I2C_FTI2C010_0_IRQ	18
++#define I2C_FTI2C010_1_IRQ	53
++#define I2C_FTI2C010_2_IRQ	50
++#define I2C_FTI2C010_3_IRQ	51
++#define I2C_FTI2C010_4_IRQ	52
++#define I2C_FTI2C010_5_IRQ	43
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	6
++#define SSP_FTSSP010_0_IRQ	6
++#define SSP_FTSSP010_1_IRQ	11
++#define SSP_FTSSP010_2_IRQ	7
++#define SSP_FTSSP010_3_IRQ	54
++#define SSP_FTSSP010_4_IRQ	74
++#define SSP_FTSSP010_5_IRQ	75
++
++/* SSP for PCIE */
++#define SSP_FTSSP010_6_IRQ  I2S_PCIE_FTSSP010_0_IRQ
++#define SSP_FTSSP010_7_IRQ	I2S_PCIE_FTSSP010_1_IRQ
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	92
++#define SPI_FTSPI020_0_IRQ	92
++
++/* SDC */
++#define SDC_FTSDC021_IRQ_COUNT	1
++#define SDC_FTSDC021_IRQ	15
++#define SDC_FTSDC021_0_IRQ	15
++
++/* NAND */
++#define NAND_FTNAND023_IRQ_COUNT	1
++#define NAND_FTNAND023_IRQ	23
++#define NAND_FTNAND023_0_IRQ	23
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	24
++#define LCD_FTLCDC200_0_IRQ	24
++#define LCD_FTLCDC200_1_IRQ	45
++#define LCD_FTLCDC200_2_IRQ	46
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_IRQ_COUNT	1
++#define GRA_FT2DGRA_IRQ	4
++#define GRA_FT2DGRA_0_IRQ	4
++
++/* MAC */
++#define MAC_FTGMAC100_IRQ_COUNT	1
++#define MAC_FTGMAC100_IRQ	3
++#define MAC_FTGMAC100_0_IRQ	3
++#define MAC_FTGMAC100_1_IRQ	33
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	19
++#define AES_FTAES020_0_IRQ	19
++
++/* CAP */
++#define CAP_FTCAP300_IRQ_COUNT	1
++#define CAP_FTCAP300_IRQ	32
++#define CAP_FTCAP300_0_IRQ	32
++
++/* DI3D */
++#define DI3D_FTDI3D_IRQ_COUNT	1
++#define DI3D_FTDI3D_IRQ	41
++#define DI3D_FTDI3D_0_IRQ	41
++#define DI3D_FTDI3D_1_IRQ	42
++
++/* H264E */
++#define H264E_FTMCP280_IRQ_COUNT	1
++#define H264E_FTMCP280_IRQ	29
++#define H264E_FTMCP280_0_IRQ	29
++#define H264E_FTMCP280_1_IRQ	28
++
++/* H264D */
++#define H264D_FTMCP300_IRQ_COUNT	1
++#define H264D_FTMCP300_IRQ	30
++#define H264D_FTMCP300_0_IRQ	30
++#define H264D_FTMCP300_1_IRQ	40
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	1
++#define MCP_FTMCP100_IRQ	31
++#define MCP_FTMCP100_0_IRQ	31
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_IRQ_COUNT	1
++#define XDMAC_FTDMAC030_IRQ		34
++#define XDMAC_FTDMAC030_0_IRQ		34
++#define XDMAC_FTDMAC030_0_0_IRQ         61
++#define XDMAC_FTDMAC030_0_1_IRQ         62
++
++/* IR_DET */
++#define IR_DET_FTIRDET_IRQ_COUNT	1
++#define IR_DET_FTIRDET_IRQ	48
++#define IR_DET_FTIRDET_0_IRQ	48
++
++/* KPD */
++#define KPD_FTKPD_IRQ_COUNT	1
++#define KPD_FTKPD_IRQ	49
++#define KPD_FTKPD_0_IRQ	49
++
++/* PCIE */
++#define PCIE_FTPCI100_IRQ_COUNT	1
++#define PCIE_FTPCI100_IRQ	17
++#define PCIE_FTPCI100_0_IRQ	17
++
++/* EXT_INT */
++#define EXT_INT_IRQ_COUNT	1
++#define EXT_INT_IRQ	55
++#define EXT_INT_0_IRQ	55
++
++/* SATA */
++#define SATA_FTSATA100_IRQ_COUNT	1
++#define SATA_FTSATA100_IRQ	(PLATFORM_GM8312_IRQ_BASE + 1)
++#define SATA_FTSATA100_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 1)
++#define SATA_FTSATA100_1_IRQ	(PLATFORM_GM8312_IRQ_BASE + 2)
++#define SATA_FTSATA100_2_IRQ	(PLATFORM_GM8312_IRQ_BASE + 3)
++#define SATA_FTSATA100_3_IRQ	(PLATFORM_GM8312_IRQ_BASE + 4)
++
++/* OTG */
++#define USB_FOTG2XX_IRQ_COUNT	3
++#define USB_FOTG2XX_IRQ		(PLATFORM_GM8312_IRQ_BASE + 5)
++#define USB_FOTG2XX_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 5)
++#define USB_FOTG2XX_1_IRQ	(PLATFORM_GM8312_IRQ_BASE + 6)
++#define USB_FOTG2XX_2_IRQ	(PLATFORM_GM8312_IRQ_BASE + 7)
++
++/* HDMI */
++#define HDMI_FTHDMI_IRQ_COUNT	1
++#define HDMI_FTHDMI_IRQ		(PLATFORM_GM8312_IRQ_BASE + 8)
++#define HDMI_FTHDMI_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 8)
++
++/* DMAC */
++#define DMAC_FTDMAC020_IRQ_COUNT	2
++#define DMAC_FTDMAC020_IRQ		1
++#define DMAC_FTDMAC020_0_IRQ		1
++#define DMAC_FTDMAC020_1_IRQ		(PLATFORM_GM8312_IRQ_BASE + 16)
++
++/* APBB */
++#define APBB_FTAPBB020_IRQ_COUNT	3
++#define APBB_FTAPBB020_IRQ		2
++#define APBB_FTAPBB020_0_IRQ		2
++#define APBB_FTAPBB020_1_IRQ		5
++#define APBB_FTAPBB020_2_IRQ		60
++
++/* I2S_PCIE */
++#define I2S_PCIE_FTSSP010_IRQ_COUNT	2
++#define I2S_PCIE_FTSSP010_IRQ	(PLATFORM_GM8312_IRQ_BASE + 17)
++#define I2S_PCIE_FTSSP010_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 17)
++#define I2S_PCIE_FTSSP010_1_IRQ	(PLATFORM_GM8312_IRQ_BASE + 18)
++
++
++
++
++/* I2C_PCIE */
++#define I2C_PCIE_FTI2C010_IRQ_COUNT	1
++#define I2C_PCIE_FTI2C010_IRQ	(PLATFORM_GM8312_IRQ_BASE + 9)
++#define I2C_PCIE_FTI2C010_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 9)
++#define I2C_PCIE_FTI2C010_1_IRQ	(PLATFORM_GM8312_IRQ_BASE + 10)
++#define I2C_PCIE_FTI2C010_2_IRQ	(PLATFORM_GM8312_IRQ_BASE + 11)
++#define I2C_PCIE_FTI2C010_3_IRQ	(PLATFORM_GM8312_IRQ_BASE + 12)
++
++/* SCAL */
++#define SCAL_FTSCAL300_IRQ_COUNT    1
++#define SCAL_FTSCAL300_IRQ  12
++#define SCAL_FTSCAL300_0_IRQ    12
++#define SCAL_FTSCAL300_1_IRQ    44
++
++/*
++ * Interrupts among FA726, FA626 and FC7500
++ */
++#define CPU_INT_BASE        76
++#define CPU_INT_0           76  /* cpu_comm */
++#define CPU_INT_1           77  /* cpu_comm */
++#define CPU_INT_2           78  /* dma channel6 intr */
++#define CPU_INT_3           79  /* dma channel7 intr */
++#define CPU_INT_4           80  /* dma channel5 intr */
++#define CPU_INT_5           81  /* SPI020 intr */
++#define CPU_INT_6           82  /* dma channel4 intr */
++#define CPU_INT_7           83  /* available */
++#define CPU_INT_8           84  /* available */
++#define CPU_INT_9           85  /* available */
++#define CPU_INT_10          86  /* available */
++#define CPU_INT_11          87  /* available */
++#define CPU_INT_12          88  /* available */
++#define CPU_INT_13          89  /* available */
++#define CPU_INT_14          90  /* audio_comm, 626 <-> 7500 */
++#define CPU_INT_15          91  /* audio_comm, 626 <-> 7500 */
++
++/*
++ * The following definitions define the interrupts used by modules
++ */
++#define CPU_COMMRX_IRQ          CPU_INT_0
++#define CPU_COMMTX_IRQ          CPU_INT_1
++
++#define AUDIO_COMMRX_IRQ        CPU_INT_14
++#define AUDIO_COMMTX_IRQ        CPU_INT_15
++
++/*
++ * Base addresses
++ */
++/* DDRC */
++#define DDRC_PA_COUNT           2
++#define DDRC_0_PA_BASE          0x99300000
++#define DDRC_0_PA_LIMIT         0x99300FFF
++#define DDRC_0_PA_SIZE          0x00001000
++#define DDRC_1_PA_BASE          0x99700000
++#define DDRC_1_PA_LIMIT         0x99700FFF
++#define DDRC_1_PA_SIZE          0x00001000
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x99200000
++#define WDT_FTWDT010_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x99200000
++#define WDT_FTWDT010_0_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	1
++#define GPIO_FTGPIO010_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0x98E00000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0x98E00FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0x99600000
++#define I2C_FTI2C010_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0x99600000
++#define I2C_FTI2C010_0_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_FTI2C010_1_PA_BASE	0x99800000
++#define I2C_FTI2C010_1_PA_LIMIT	0x99800FFF
++#define I2C_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_FTI2C010_2_PA_BASE	0x99900000
++#define I2C_FTI2C010_2_PA_LIMIT	0x99900FFF
++#define I2C_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_FTI2C010_3_PA_BASE	0x99A00000
++#define I2C_FTI2C010_3_PA_LIMIT	0x99A00FFF
++#define I2C_FTI2C010_3_PA_SIZE	0x00001000
++#define I2C_FTI2C010_4_PA_BASE	0x99B00000
++#define I2C_FTI2C010_4_PA_LIMIT	0x99B00FFF
++#define I2C_FTI2C010_4_PA_SIZE	0x00001000
++#define I2C_FTI2C010_5_PA_BASE	0x98c00000
++#define I2C_FTI2C010_5_PA_LIMIT	0x98c00FFF
++#define I2C_FTI2C010_5_PA_SIZE	0x00001000
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0x82000000
++#define SSP_FTSSP010_PA_LIMIT	0x82000FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0x82000000
++#define SSP_FTSSP010_0_PA_LIMIT	0x82000FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0x82100000
++#define SSP_FTSSP010_1_PA_LIMIT	0x82100FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++#define SSP_FTSSP010_2_PA_BASE	0x82200000
++#define SSP_FTSSP010_2_PA_LIMIT	0x82200FFF
++#define SSP_FTSSP010_2_PA_SIZE	0x00001000
++#define SSP_FTSSP010_3_PA_BASE	0x82300000
++#define SSP_FTSSP010_3_PA_LIMIT	0x82300FFF
++#define SSP_FTSSP010_3_PA_SIZE	0x00001000
++#define SSP_FTSSP010_4_PA_BASE	0x82400000
++#define SSP_FTSSP010_4_PA_LIMIT	0x82400FFF
++#define SSP_FTSSP010_4_PA_SIZE	0x00001000
++#define SSP_FTSSP010_5_PA_BASE	0x82500000
++#define SSP_FTSSP010_5_PA_LIMIT	0x82500FFF
++#define SSP_FTSSP010_5_PA_SIZE	0x00001000
++
++/* PCIE */
++#define SSP_FTSSP010_6_PA_BASE  I2S_PCIE_FTSSP010_0_PA_BASE
++#define SSP_FTSSP010_6_PA_LIMIT I2S_PCIE_FTSSP010_0_PA_LIMIT
++#define SSP_FTSSP010_6_PA_SIZE  I2S_PCIE_FTSSP010_0_PA_SIZE
++
++#define SSP_FTSSP010_7_PA_BASE  I2S_PCIE_FTSSP010_1_PA_BASE
++#define SSP_FTSSP010_7_PA_LIMIT I2S_PCIE_FTSSP010_1_PA_LIMIT
++#define SSP_FTSSP010_7_PA_SIZE  I2S_PCIE_FTSSP010_1_PA_SIZE
++
++/* SPI */
++#define SPI_FTSPI020_PA_COUNT	1
++#define SPI_FTSPI020_PA_BASE	0x80300000
++#define SPI_FTSPI020_PA_LIMIT	0x80300FFF
++#define SPI_FTSPI020_PA_SIZE	0x00001000
++#define SPI_FTSPI020_0_PA_BASE	0x80300000
++#define SPI_FTSPI020_0_PA_LIMIT	0x80300FFF
++#define SPI_FTSPI020_0_PA_SIZE	0x00001000
++
++/* SDC */
++#define SDC_FTSDC021_PA_COUNT	1
++#define SDC_FTSDC021_PA_BASE	0x92800000
++#define SDC_FTSDC021_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_PA_SIZE	0x00001000
++#define SDC_FTSDC021_0_PA_BASE	0x92800000
++#define SDC_FTSDC021_0_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_0_PA_SIZE	0x00001000
++
++/* NAND */
++#define NAND_FTNAND023_PA_COUNT	1
++#define NAND_FTNAND023_PA_BASE	0x80000000
++#define NAND_FTNAND023_PA_LIMIT	0x800FFFFF
++#define NAND_FTNAND023_PA_SIZE	0x00100000
++#define NAND_FTNAND023_0_PA_BASE	0x80000000
++#define NAND_FTNAND023_0_PA_LIMIT	0x800FFFFF
++#define NAND_FTNAND023_0_PA_SIZE	0x00100000
++
++/* NANDDP */
++#define NANDDP_FTNAND023_PA_COUNT	1
++#define NANDDP_FTNAND023_PA_BASE	0x80100000
++#define NANDDP_FTNAND023_PA_LIMIT	0x801FFFFF
++#define NANDDP_FTNAND023_PA_SIZE	0x00100000
++#define NANDDP_FTNAND023_0_PA_BASE	0x80100000
++#define NANDDP_FTNAND023_0_PA_LIMIT	0x801FFFFF
++#define NANDDP_FTNAND023_0_PA_SIZE	0x00100000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	1
++#define LCD_FTLCDC200_PA_BASE	0x9A800000
++#define LCD_FTLCDC200_PA_LIMIT	0x9A80CFFF
++#define LCD_FTLCDC200_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	0x9A800000
++#define LCD_FTLCDC200_0_PA_LIMIT	0x9A80CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_1_PA_BASE	0x9B200000
++#define LCD_FTLCDC200_1_PA_LIMIT	0x9B20CFFF
++#define LCD_FTLCDC200_1_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_2_PA_BASE	0x9B800000
++#define LCD_FTLCDC200_2_PA_LIMIT	0x9B80CFFF
++#define LCD_FTLCDC200_2_PA_SIZE	0x0000D000
++
++/* Graphic Plance Encoder */
++#define GRAPHIC_ENC_PA_COUNT    1
++#define GRAPHIC_ENC_PA_BASE	    0x9B300000
++#define GRAPHIC_ENC_PA_LIMIT	0x9B300FFF
++#define GRAPHIC_ENC_PA_SIZE	    0x00001000
++#define GRAPHIC_ENC_0_PA_BASE	0x9B300000
++#define GRAPHIC_ENC_0_PA_LIMIT	0x9B300FFF
++#define GRAPHIC_ENC_0_PA_SIZE	0x00001000
++
++/* Graphic Plance Decoder */
++#define GRAPHIC_DEC_PA_COUNT	3
++#define GRAPHIC_DEC_PA_BASE	    0x9B400000
++#define GRAPHIC_DEC_PA_LIMIT	0x9B400FFF
++#define GRAPHIC_DEC_PA_SIZE	    0x00001000
++#define GRAPHIC_DEC_0_PA_BASE	0x9B400000
++#define GRAPHIC_DEC_0_PA_LIMIT	0x9B400FFF
++#define GRAPHIC_DEC_0_PA_SIZE	0x00001000
++#define GRAPHIC_DEC_1_PA_BASE	0x9B500000
++#define GRAPHIC_DEC_1_PA_LIMIT	0x9B500FFF
++#define GRAPHIC_DEC_1_PA_SIZE	0x00001000
++#define GRAPHIC_DEC_2_PA_BASE	0x9B600000
++#define GRAPHIC_DEC_2_PA_LIMIT	0x9B600FFF
++#define GRAPHIC_DEC_2_PA_SIZE	0x00001000
++
++/* SMC */
++#define SMC_FTSMC010_PA_COUNT	1
++#define SMC_FTSMC010_PA_BASE	0x92100000
++#define SMC_FTSMC010_PA_LIMIT	0x92100FFF
++#define SMC_FTSMC010_PA_SIZE	0x00001000
++#define SMC_FTSMC010_0_PA_BASE	0x92100000
++#define SMC_FTSMC010_0_PA_LIMIT	0x92100FFF
++#define SMC_FTSMC010_0_PA_SIZE	0x00001000
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_PA_COUNT	1
++#define GRA_FT2DGRA_PA_BASE	0x92200000
++#define GRA_FT2DGRA_PA_LIMIT	0x92200FFF
++#define GRA_FT2DGRA_PA_SIZE	0x00001000
++#define GRA_FT2DGRA_0_PA_BASE	0x92200000
++#define GRA_FT2DGRA_0_PA_LIMIT	0x92200FFF
++#define GRA_FT2DGRA_0_PA_SIZE	0x00001000
++
++/* MAC */
++#define MAC_FTGMAC100_PA_COUNT	1
++#define MAC_FTGMAC100_PA_BASE	0x92500000
++#define MAC_FTGMAC100_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_0_PA_BASE	0x92500000
++#define MAC_FTGMAC100_0_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_0_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_1_PA_BASE	0x92300000
++#define MAC_FTGMAC100_1_PA_LIMIT	0x92300FFF
++#define MAC_FTGMAC100_1_PA_SIZE	0x00001000
++
++/* DMAC */
++#define DMAC_FTDMAC020_PA_COUNT		2
++#define DMAC_FTDMAC020_PA_BASE		0x92600000
++#define DMAC_FTDMAC020_PA_LIMIT		0x92600FFF
++#define DMAC_FTDMAC020_PA_SIZE		0x00001000
++#define DMAC_FTDMAC020_0_PA_BASE	0x92600000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0x92600FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++#define DMAC_FTDMAC020_1_PA_BASE	0xA1A00000
++#define DMAC_FTDMAC020_1_PA_LIMIT	0xA1A00FFF
++#define DMAC_FTDMAC020_1_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0x92700000
++#define AES_FTAES020_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0x92700000
++#define AES_FTAES020_0_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* CAP */
++#define CAP_FTCAP300_PA_COUNT	1
++#define CAP_FTCAP300_PA_BASE	0x96100000
++#define CAP_FTCAP300_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_PA_SIZE	0x00001000
++#define CAP_FTCAP300_0_PA_BASE	0x96100000
++#define CAP_FTCAP300_0_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_0_PA_SIZE	0x00001000
++
++/* AHBC */
++#define AHBC_FTAHBC020_PA_COUNT		1
++#define AHBC_FTAHBC020_PA_BASE		0x92A00000
++#define AHBC_FTAHBC020_PA_LIMIT		0x92A00FFF
++#define AHBC_FTAHBC020_PA_SIZE		0x00001000
++#define AHBC_FTAHBC020_0_PA_BASE	0x92A00000
++#define AHBC_FTAHBC020_0_PA_LIMIT	0x92A00FFF
++#define AHBC_FTAHBC020_0_PA_SIZE	0x00001000
++
++/* APBB */
++#define APBB_FTAPBB020_PA_COUNT		3
++#define APBB_FTAPBB020_PA_BASE		0x98100000
++#define APBB_FTAPBB020_PA_LIMIT		0x98100FFF
++#define APBB_FTAPBB020_PA_SIZE		0x00001000
++#define APBB_FTAPBB020_0_PA_BASE	0x98100000
++#define APBB_FTAPBB020_0_PA_LIMIT	0x98100FFF
++#define APBB_FTAPBB020_0_PA_SIZE	0x00001000
++#define APBB_FTAPBB020_1_PA_BASE	0x9A000000
++#define APBB_FTAPBB020_1_PA_LIMIT	0x9A000FFF
++#define APBB_FTAPBB020_1_PA_SIZE	0x00001000
++#define APBB_FTAPBB020_2_PA_BASE	0x92C00000
++#define APBB_FTAPBB020_2_PA_LIMIT	0x92C00FFF
++#define APBB_FTAPBB020_2_PA_SIZE	0x00001000
++
++/* DI3D */
++#define DI3D_FTDI3D_PA_COUNT	2
++#define DI3D_FTDI3D_PA_BASE	    0x9B100000
++#define DI3D_FTDI3D_PA_LIMIT	0x9B100FFF
++#define DI3D_FTDI3D_PA_SIZE	    0x00001000
++#define DI3D_FTDI3D_0_PA_BASE	0x9B100000
++#define DI3D_FTDI3D_0_PA_LIMIT	0x9B100FFF
++#define DI3D_FTDI3D_0_PA_SIZE	0x00001000
++
++#define DI3D_FTDI3D_1_PA_BASE   0x9BA00000
++#define DI3D_FTDI3D_1_PA_LIMIT  0x9BA00FFF
++#define DI3D_FTDI3D_1_PA_SIZE   0x00001000
++
++/* H264E */
++#define H264E_FTMCP280_PA_COUNT	1
++#define H264E_FTMCP280_PA_BASE	0x90000000
++#define H264E_FTMCP280_PA_LIMIT	0x90000FFF
++#define H264E_FTMCP280_PA_SIZE	0x00001000
++#define H264E_FTMCP280_0_PA_BASE	0x90000000
++#define H264E_FTMCP280_0_PA_LIMIT	0x90000FFF
++#define H264E_FTMCP280_0_PA_SIZE	0x00001000
++#define H264E_FTMCP280_1_PA_BASE	0x90200000
++#define H264E_FTMCP280_1_PA_LIMIT	0x90200FFF
++#define H264E_FTMCP280_1_PA_SIZE	0x00001000
++
++/* H264D */
++#define H264D_FTMCP300_PA_COUNT	1
++#define H264D_FTMCP300_PA_BASE	0x94200000
++#define H264D_FTMCP300_PA_LIMIT	0x942FFFFF
++#define H264D_FTMCP300_PA_SIZE	0x00100000
++#define H264D_FTMCP300_0_PA_BASE	0x94200000
++#define H264D_FTMCP300_0_PA_LIMIT	0x942FFFFF
++#define H264D_FTMCP300_0_PA_SIZE	0x00100000
++#define H264D_FTMCP300_1_PA_BASE	0x94000000
++#define H264D_FTMCP300_1_PA_LIMIT	0x940FFFFF
++#define H264D_FTMCP300_1_PA_SIZE	0x00100000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0x92000000
++#define MCP_FTMCP100_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_0_PA_BASE	0x92000000
++#define MCP_FTMCP100_0_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++
++/* IR_DET */
++#define IR_DET_FTIRDET_PA_COUNT	1
++#define IR_DET_FTIRDET_PA_BASE	0x99C00000
++#define IR_DET_FTIRDET_PA_LIMIT	0x99C00FFF
++#define IR_DET_FTIRDET_PA_SIZE	0x00001000
++#define IR_DET_FTIRDET_0_PA_BASE	0x99C00000
++#define IR_DET_FTIRDET_0_PA_LIMIT	0x99C00FFF
++#define IR_DET_FTIRDET_0_PA_SIZE	0x00001000
++
++/* KPD */
++#define KPD_FTKPD_PA_COUNT	1
++#define KPD_FTKPD_PA_BASE	0x99D00000
++#define KPD_FTKPD_PA_LIMIT	0x99D00FFF
++#define KPD_FTKPD_PA_SIZE	0x00001000
++#define KPD_FTKPD_0_PA_BASE	0x99D00000
++#define KPD_FTKPD_0_PA_LIMIT	0x99D00FFF
++#define KPD_FTKPD_0_PA_SIZE	0x00001000
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_PA_COUNT	1
++#define XDMAC_FTDMAC030_PA_BASE		0x9A100000
++#define XDMAC_FTDMAC030_PA_LIMIT	0x9A100FFF
++#define XDMAC_FTDMAC030_PA_SIZE		0x00001000
++#define XDMAC_FTDMAC030_0_PA_BASE	0x9A100000
++#define XDMAC_FTDMAC030_0_PA_LIMIT	0x9A100FFF
++#define XDMAC_FTDMAC030_0_PA_SIZE	0x00001000
++
++/* 8310 PCIE */
++#define PCIE_PLDA_PA_COUNT      1
++#define PCIE_PLDA_PA_BASE       0x99E00000
++#define PCIE_PLDA_PA_LIMIT      0x99E01FFF
++#define PCIE_PLDA_PA_SIZE       0x00002000
++#define PCIE_PLDA_0_PA_BASE     0x99E00000
++#define PCIE_PLDA_0_PA_LIMIT    0x99E01FFF
++#define PCIE_PLDA_0_PA_SIZE     0x00002000
++
++/* 8312 PCIE */
++#define PCIE_PCIE_PLDA_PA_COUNT   1
++#define PCIE_PCIE_PLDA_PA_BASE    0xA3700000
++#define PCIE_PCIE_PLDA_PA_LIMIT   0xA3700FFF
++#define PCIE_PCIE_PLDA_PA_SIZE    0x00001000
++#define PCIE_PCIE_PLDA_0_PA_BASE  0xA3700000
++#define PCIE_PCIE_PLDA_0_PA_LIMIT 0xA3700FFF
++#define PCIE_PCIE_PLDA_0_PA_SIZE  0x00001000
++#define PCIE_PCIE_PLDA_1_PA_BASE  0xA3800000
++#define PCIE_PCIE_PLDA_1_PA_LIMIT 0xA3800FFF
++#define PCIE_PCIE_PLDA_1_PA_SIZE  0x00001000
++
++/* SATA */
++#define SATA_FTSATA100_PA_COUNT	    4
++#define SATA_FTSATA100_PA_BASE      0xA1100000
++#define SATA_FTSATA100_PA_LIMIT     0xA1100FFF
++#define SATA_FTSATA100_PA_SIZE      0x00001000
++#define SATA_FTSATA100_0_PA_BASE    0xA1100000
++#define SATA_FTSATA100_0_PA_LIMIT   0xA1100FFF
++#define SATA_FTSATA100_0_PA_SIZE    0x00001000
++#define SATA_FTSATA100_1_PA_BASE    0xA1200000
++#define SATA_FTSATA100_1_PA_LIMIT   0xA1200FFF
++#define SATA_FTSATA100_1_PA_SIZE    0x00001000
++#define SATA_FTSATA100_2_PA_BASE    0xA1300000
++#define SATA_FTSATA100_2_PA_LIMIT   0xA1300FFF
++#define SATA_FTSATA100_2_PA_SIZE    0x00001000
++#define SATA_FTSATA100_3_PA_BASE    0xA1400000
++#define SATA_FTSATA100_3_PA_LIMIT   0xA1400FFF
++#define SATA_FTSATA100_3_PA_SIZE    0x00001000
++
++/* SATA H2X */
++#define H2X_FTH2X030_SATA_PA_COUNT      4
++#define H2X_FTH2X030_SATA_PA_BASE       0xA2900000
++#define H2X_FTH2X030_SATA_PA_LIMIT      0xA2900FFF
++#define H2X_FTH2X030_SATA_PA_SIZE       0x00001000
++#define H2X_FTH2X030_SATA_0_PA_BASE     0xA2900000
++#define H2X_FTH2X030_SATA_0_PA_LIMIT    0xA2900FFF
++#define H2X_FTH2X030_SATA_0_PA_SIZE     0x00001000
++#define H2X_FTH2X030_SATA_1_PA_BASE     0xA2A00000
++#define H2X_FTH2X030_SATA_1_PA_LIMIT    0xA2A00FFF
++#define H2X_FTH2X030_SATA_1_PA_SIZE     0x00001000
++#define H2X_FTH2X030_SATA_2_PA_BASE     0xA2B00000
++#define H2X_FTH2X030_SATA_2_PA_LIMIT    0xA2B00FFF
++#define H2X_FTH2X030_SATA_2_PA_SIZE     0x00001000
++#define H2X_FTH2X030_SATA_3_PA_BASE     0xA2C00000
++#define H2X_FTH2X030_SATA_3_PA_LIMIT    0xA2C00FFF
++#define H2X_FTH2X030_SATA_3_PA_SIZE     0x00001000
++
++/* OTG */
++#define USB_FOTG2XX_PA_COUNT	3
++#define USB_FOTG2XX_PA_BASE	0xA1500000
++#define USB_FOTG2XX_PA_LIMIT	0xA1500FFF
++#define USB_FOTG2XX_PA_SIZE	0x00001000
++#define USB_FOTG2XX_0_PA_BASE	0xA1500000
++#define USB_FOTG2XX_0_PA_LIMIT	0xA1500FFF
++#define USB_FOTG2XX_0_PA_SIZE	0x00001000
++#define USB_FOTG2XX_1_PA_BASE	0xA1600000
++#define USB_FOTG2XX_1_PA_LIMIT	0xA1600FFF
++#define USB_FOTG2XX_1_PA_SIZE	0x00001000
++#define USB_FOTG2XX_2_PA_BASE	0xA1700000
++#define USB_FOTG2XX_2_PA_LIMIT	0xA1700FFF
++#define USB_FOTG2XX_2_PA_SIZE	0x00001000
++/* OTG H2X0 */
++#define H2X0_FOTG2XX_PA_BASE	0xA2D00000
++#define H2X0_FOTG2XX_PA_SIZE	0x00001000
++/* OTG H2X1 */
++#define H2X1_FOTG2XX_PA_BASE	0xA2E00000
++#define H2X1_FOTG2XX_PA_SIZE	0x00001000
++/* OTG H2X2 */
++#define H2X2_FOTG2XX_PA_BASE	0xA2F00000
++#define H2X2_FOTG2XX_PA_SIZE	0x00001000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT	1
++#define TVE_FTTVE100_PA_BASE	0xA1800000
++#define TVE_FTTVE100_PA_LIMIT	0xA1800FFF
++#define TVE_FTTVE100_PA_SIZE	0x00001000
++#define TVE_FTTVE100_0_PA_BASE	0xA1800000
++#define TVE_FTTVE100_0_PA_LIMIT	0xA1800FFF
++#define TVE_FTTVE100_0_PA_SIZE	0x00001000
++
++/* HDMI */
++#define HDMI_FTHDMI_PA_COUNT	1
++#define HDMI_FTHDMI_PA_BASE	0xA1900000
++#define HDMI_FTHDMI_PA_LIMIT	0xA1900FFF
++#define HDMI_FTHDMI_PA_SIZE	0x00001000
++#define HDMI_FTHDMI_0_PA_BASE	0xA1900000
++#define HDMI_FTHDMI_0_PA_LIMIT	0xA1900FFF
++#define HDMI_FTHDMI_0_PA_SIZE	0x00001000
++
++#define HDMI_FTHDCPMEM_PA_BASE  0xA1B00000
++#define HDMI_FTHDCPMEM_PA_LIMIT 0xA1B001FF
++#define HDMI_FTHDCPMEM_PA_SIZE  0x00000200
++
++/* I2S_PCIE */
++#define I2S_PCIE_FTSSP010_PA_COUNT	2
++#define I2S_PCIE_FTSSP010_PA_BASE	0xA3100000
++#define I2S_PCIE_FTSSP010_PA_LIMIT	0xA3100FFF
++#define I2S_PCIE_FTSSP010_PA_SIZE	0x00001000
++#define I2S_PCIE_FTSSP010_0_PA_BASE	0xA3100000
++#define I2S_PCIE_FTSSP010_0_PA_LIMIT	0xA3100FFF
++#define I2S_PCIE_FTSSP010_0_PA_SIZE	0x00001000
++#define I2S_PCIE_FTSSP010_1_PA_BASE	0xA3200000
++#define I2S_PCIE_FTSSP010_1_PA_LIMIT	0xA3200FFF
++#define I2S_PCIE_FTSSP010_1_PA_SIZE	0x00001000
++
++/* I2C_PCIE */
++#define I2C_PCIE_FTI2C010_PA_COUNT	4
++#define I2C_PCIE_FTI2C010_PA_BASE	0xA3300000
++#define I2C_PCIE_FTI2C010_PA_LIMIT	0xA3300FFF
++#define I2C_PCIE_FTI2C010_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_0_PA_BASE	0xA3300000
++#define I2C_PCIE_FTI2C010_0_PA_LIMIT	0xA3300FFF
++#define I2C_PCIE_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_1_PA_BASE	0xA3400000
++#define I2C_PCIE_FTI2C010_1_PA_LIMIT	0xA3400FFF
++#define I2C_PCIE_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_2_PA_BASE	0xA3500000
++#define I2C_PCIE_FTI2C010_2_PA_LIMIT	0xA3500FFF
++#define I2C_PCIE_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_3_PA_BASE	0xA3600000
++#define I2C_PCIE_FTI2C010_3_PA_LIMIT	0xA3600FFF
++#define I2C_PCIE_FTI2C010_3_PA_SIZE	0x00001000
++
++/* SCAL */
++#define SCAL_FTSCAL300_PA_COUNT 1
++#define SCAL_FTSCAL300_PA_BASE  0x96200000
++#define SCAL_FTSCAL300_PA_LIMIT 0x96247FFF
++#define SCAL_FTSCAL300_PA_SIZE  0x00048000
++#define SCAL_FTSCAL300_0_PA_BASE    0x96200000
++#define SCAL_FTSCAL300_0_PA_LIMIT   0x96247FFF
++#define SCAL_FTSCAL300_0_PA_SIZE    0x00048000
++#define SCAL_FTSCAL300_1_PA_BASE    0x96300000
++#define SCAL_FTSCAL300_1_PA_LIMIT   0x96347FFF
++#define SCAL_FTSCAL300_1_PA_SIZE    0x00048000
++
++/* IOLINK */
++#define IOLINK_TX_PA_COUNT          3
++#define IOLINK_TX_0_PA_BASE         0x9BB00000
++#define IOLINK_TX_0_PA_SIZE         0x1000
++#define IOLINK_TX_1_PA_BASE         0x9BC00000
++#define IOLINK_TX_1_PA_SIZE         0x1000
++#define IOLINK_TX_2_PA_BASE         0x9BD00000
++#define IOLINK_TX_2_PA_SIZE         0x1000
++
++/* H2XBrg_7 */
++#define PCIE_H2XBRG_7_PA_BASE       0xA3000000
++#define PCI3_H2SBRG_7_PA_SIZE       0x1000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++#define PLATFORM_IRQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL1	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL1	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL3	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL3	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL4	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL4	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL5	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL5	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL6	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL6	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL7	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL7	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL8	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL8	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE9	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL9	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE9	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL9	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE10	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL10	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE10	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL10	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE11	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL11	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE11	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL11	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE12	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL12	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE12	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL12	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE13	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL13	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE13	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL13	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE14	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL14	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE14	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL14	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE15	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL15	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE15	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL15	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODEEX2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVELEX2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODEEX2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVELEX2	0xFFFFFFFF
++
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/pmu.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/pmu.h
+new file mode 100644
+index 00000000..1a9fb19d
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/pmu.h
+@@ -0,0 +1,33 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++#define GM8210_TEST_CHIP_ID 0x821010
++
++unsigned int pmu_get_apb_clk(void);
++unsigned int pmu_get_apb0_clk(void);
++unsigned int pmu_get_apb1_clk(void);
++unsigned int pmu_get_apb2_clk(void);
++int platform_check_flash_type(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/pmu_pcie.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/pmu_pcie.h
+new file mode 100644
+index 00000000..39f135eb
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/pmu_pcie.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/pmu_pcie.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_PCIE_H__
++#define __PMU_PCIE_H__
++
++#define GM8312_TEST_CHIP_ID 0x831200
++
++unsigned int pmu_pcie_get_apb_clk(void);
++unsigned int pmu_pcie_get_ahb_clk(void);
++unsigned int pmu_pcie_get_axi_clk(void);
++void pmu_pcie_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_PCIE_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/serial.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/serial.h
+new file mode 100644
+index 00000000..47aee6eb
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/serial.h
+@@ -0,0 +1,96 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 4 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created.
++ */
++
++//#define UART_CLKSRC_OSCH//issue
++
++#ifdef UART_CLKSRC_OSCH
++#define CONFIG_UART_CLK			12288000//12000000
++#else
++#define CONFIG_UART_CLK			25000000//(30000000/16)
++#endif
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#ifdef CONFIG_SERIAL_UART1_IP
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++#else
++#define EXTENDED_UART_1 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART2_IP
++#define EXTENDED_UART_2 \
++     { 0, BASE_BAUD, UART_FTUART010_2_VA_BASE, UART_FTUART010_2_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS2 */
++#else
++#define EXTENDED_UART_2 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART3_IP
++#define EXTENDED_UART_3 \
++     { 0, BASE_BAUD, UART_FTUART010_3_VA_BASE, UART_FTUART010_3_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS3 */
++#else
++#define EXTENDED_UART_3 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART4_IP
++#define EXTENDED_UART_4 \
++     { 0, BASE_BAUD, UART_FTUART010_4_VA_BASE, UART_FTUART010_4_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS4 */
++#else
++#define EXTENDED_UART_4 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART5_IP
++#define EXTENDED_UART_5 \
++     { 0, BASE_BAUD, UART_FTUART010_5_VA_BASE, UART_FTUART010_5_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS5 */
++#else
++#define EXTENDED_UART_5 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART6_IP
++#define EXTENDED_UART_6 \
++     { 0, BASE_BAUD, UART_FTUART010_6_VA_BASE, UART_FTUART010_6_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS6 */
++#else
++#define EXTENDED_UART_6 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1            \
++        EXTENDED_UART_2            \
++        EXTENDED_UART_3            \
++        EXTENDED_UART_4            \
++        EXTENDED_UART_5            \
++        EXTENDED_UART_6
++
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/system.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/system.h
+new file mode 100644
+index 00000000..ca2dee55
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/system.h
+@@ -0,0 +1,76 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/system.h
++ *
++ *  Faraday Platform Dependent System Definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++static inline void arch_reset(char mode, const char *cmd)
++{
++#define BIT13 (0x1<<13)
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++    pmuReg_t regRSTArray[] = {
++    	/* reg_off,bit_masks,lock_bits,init_val,init_mask */
++	{0xB8, BIT13, BIT13, 0, BIT13},
++    };
++    pmuRegInfo_t rst_clk_info = {
++    	"rst_clk",
++	ARRAY_SIZE(regRSTArray),
++	ATTR_TYPE_NONE,
++	regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<13)), (PMU_FTPMU010_VA_BASE + 0xB8));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C)); //reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));//load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08)); /*Magic number*/
++    writeb(0x03, (wdt_va_base + 0x0C)); /*Enable WDT */
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/vmalloc.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/vmalloc.h
+new file mode 100644
+index 00000000..b86c26fe
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-M/vmalloc.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/vmalloc.h
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/board.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/board.h
+new file mode 100644
+index 00000000..11286806
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/board.h
+@@ -0,0 +1,112 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/board.h
++ *
++ *  GM board Independent Specification
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ *  ChangeLog
++ *
++ *   Harry  2012/3/6 03:15 created.
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM210"
++#define BOOT_PARAMETER_PA_OFFSET  0x100
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0x99000000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE    0x98400000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        10
++
++/* TIMER */
++#define TIMER_FTTMR010_PA_BASE	    0x98D00000
++#define TIMER_FTTMR010_VA_BASE	    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         73
++#define TIMER_FTTMR010_IRQ1         73
++#define TIMER_FTTMR010_IRQ2         73
++
++/* INTC030 */
++#define INTC_FTINTC030_PA_BASE      0x96000000
++#define INTC_FTINTC030_VA_BASE      (TIMER_FTTMR010_VA_BASE + TIMER_FTTMR010_VA_SIZE)
++#define INTC_FTINTC030_VA_SIZE	    SZ_4K
++
++/* PCI_PMU */
++#define PCIPMU_FTPMU010_PA_BASE     0xA2700000
++#define PCIPMU_FTPMU010_VA_BASE     (INTC_FTINTC030_VA_BASE + INTC_FTINTC030_VA_SIZE)
++#define PCIPMU_FTPMU010_VA_SIZE     SZ_4K
++
++/* INTC010 */
++#define INTC_FTINTC010_PA_BASE      0xA2800000
++#define INTC_FTINTC010_VA_BASE      (PCIPMU_FTPMU010_VA_BASE + PCIPMU_FTPMU010_VA_SIZE)
++#define INTC_FTINTC010_VA_SIZE	    SZ_4K
++
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++
++#define BOARD_BUS_LOCK_SUPPORT      1
++
++typedef enum {
++    BUS_LOCK_I2C = 0,
++    BUS_LOCK_NAND,
++    BUS_LOCK_SPINOR,
++} bus_lock_t;
++
++void board_bus_lock_init(bus_lock_t bus);
++void board_bus_lock(bus_lock_t bus);
++void board_bus_unlock(bus_lock_t bus);
++/* return value:
++ *  -1 for fail which means the bus was locked by others
++ *  0 for grab the lock success
++ */
++int board_bus_trylock(bus_lock_t bus);
++
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/gpio.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/gpio.h
+new file mode 100644
+index 00000000..c26a9e86
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8126_GPIO_H__
++#define __GM8126_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		3
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8126_GPIO_H__
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/irqs.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/irqs.h
+new file mode 100644
+index 00000000..45887a1b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/irqs.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/irqs.h
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Justin Shih  10/06/2012  Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/memory.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/memory.h
+new file mode 100644
+index 00000000..988e97b3
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/memory.h
+@@ -0,0 +1,64 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/memory.h
++ *  
++ *  GM Platform Dependent Memory Configuration
++ *  
++ * 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
++ *  
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define PHYS_OFFSET     CPU_MEM_PA_BASE
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management. 
++ *
++ * Users can adjust the memory size based on the real memory size requirement.  
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     (50 << 20)
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement. 
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE. 
++ * The memory boundary is 16M alginment 
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/platform_io.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/platform_io.h
+new file mode 100644
+index 00000000..1ae5399b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/platform_io.h
+@@ -0,0 +1,729 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/platform_io.h
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++#define PLATFORM_FIQ_BASE       0
++#define PLATFORM_IRQ_TOTALCOUNT		96/* interrupt controller supports 96 interrupts */
++#define PLATFORM_GM8312_IRQ_TOTALCOUNT 	32
++#define PLATFORM_GM8312_IRQ_BASE      	PLATFORM_IRQ_TOTALCOUNT
++#define PLATFORM_INTERRUPTS     (PLATFORM_IRQ_TOTALCOUNT + PLATFORM_GM8312_IRQ_TOTALCOUNT)
++#define CPU_MEM_PA_BASE         0x10000000     /* the memory physical start address(DDR) */
++
++/*
++ * Component counts
++ */
++
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	2
++#define GPIO_FTGPIO010_COUNT	2
++/* I2C */
++#define I2C_COUNT	6
++#define I2C_FTI2C010_COUNT	6
++/* LCD */
++#define LCD_COUNT	3
++#define LCD_FTLCDC200_COUNT	3
++/* 2D GRAPHIC */
++#define GRA_COUNT	1
++#define GRA_FT2DGRA_COUNT	1
++/* MAC */
++#define MAC_COUNT	2
++#define MAC_FTGMAC100_COUNT	2
++/* DMAC */
++#define DMAC_COUNT	2
++#define DMAC_FTDMAC020_COUNT	2
++/* XDMAC */
++#define XDMAC_COUNT	1
++#define XDMAC_FTDMAC030_COUNT	1
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* CAP */
++#define CAP_COUNT	1
++#define CAP_FTCAP300_COUNT	2
++/* DI3D */
++#define DI3D_COUNT	2
++#define DI3D_FTDI3D_COUNT	2
++/* H264E */
++#define H264E_COUNT	2
++#define H264E_FTMCP280_COUNT	2
++/* H264D */
++#define H264D_COUNT	2
++#define H264D_FTMCP300_COUNT	2
++/* MCP */
++#define MCP_COUNT	1
++#define MCP_FTMCP100_COUNT	1
++/* PCIE */
++#define PCIE_COUNT	2
++#define PCIE_FTPCI100_COUNT	2
++/* SCAL */
++#define SCAL_COUNT	2
++#define SCAL_FTSCAL300_COUNT	2
++/* DMAC_PCIE */
++#define DMAC_PCIE_COUNT	1
++#define DMAC_PCIE_FTDMAC020_COUNT	1
++/* I2C_PCIE */
++#define I2C_PCIE_COUNT	4
++#define I2C_PCIE_FTSSP010_COUNT	4
++
++/*
++ * Interrrupt numbers
++ */
++/* DDR IRQ */
++#define DDRC_IRQ_COUNT  2
++#define DDRC0_IRQ       26
++#define DDRC1_IRQ       27
++
++
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	16
++#define WDT_FTWDT010_0_IRQ	16
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	2
++#define GPIO_FTGPIO010_IRQ	    13
++#define GPIO_FTGPIO010_0_IRQ	13
++#define GPIO_FTGPIO010_1_IRQ	63
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	18
++#define I2C_FTI2C010_0_IRQ	18
++#define I2C_FTI2C010_1_IRQ	53
++#define I2C_FTI2C010_2_IRQ	50
++#define I2C_FTI2C010_3_IRQ	51
++#define I2C_FTI2C010_4_IRQ	52
++#define I2C_FTI2C010_5_IRQ	43
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	92
++#define SPI_FTSPI020_0_IRQ	92
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	24
++#define LCD_FTLCDC200_0_IRQ	24
++#define LCD_FTLCDC200_1_IRQ	45
++#define LCD_FTLCDC200_2_IRQ	46
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_IRQ_COUNT	1
++#define GRA_FT2DGRA_IRQ	4
++#define GRA_FT2DGRA_0_IRQ	4
++
++/* MAC */
++#define MAC_FTGMAC100_IRQ_COUNT	1
++#define MAC_FTGMAC100_IRQ	3
++#define MAC_FTGMAC100_0_IRQ	3
++#define MAC_FTGMAC100_1_IRQ	33
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_IRQ_COUNT	1
++#define XDMAC_FTDMAC030_IRQ		34
++#define XDMAC_FTDMAC030_0_IRQ		34
++#define XDMAC_FTDMAC030_0_0_IRQ         61
++#define XDMAC_FTDMAC030_0_1_IRQ         62
++
++/* DMAC */
++#define DMAC_FTDMAC020_IRQ_COUNT	2
++#define DMAC_FTDMAC020_IRQ		1
++#define DMAC_FTDMAC020_0_IRQ		1
++#define DMAC_FTDMAC020_1_IRQ		(PLATFORM_GM8312_IRQ_BASE + 16)
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	19
++#define AES_FTAES020_0_IRQ	19
++
++/* CAP */
++#define CAP_FTCAP300_IRQ_COUNT	1
++#define CAP_FTCAP300_IRQ	32
++#define CAP_FTCAP300_0_IRQ	32
++
++/* DI3D */
++#define DI3D_FTDI3D_IRQ_COUNT	2
++#define DI3D_FTDI3D_IRQ	41
++#define DI3D_FTDI3D_0_IRQ	41
++#define DI3D_FTDI3D_1_IRQ	42
++
++/* H264E */
++#define H264E_FTMCP280_IRQ_COUNT	1
++#define H264E_FTMCP280_IRQ	29
++#define H264E_FTMCP280_0_IRQ	29
++#define H264E_FTMCP280_1_IRQ	28
++
++/* H264D */
++#define H264D_FTMCP300_IRQ_COUNT	1
++#define H264D_FTMCP300_IRQ	30
++#define H264D_FTMCP300_0_IRQ	30
++#define H264D_FTMCP300_1_IRQ	40
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	1
++#define MCP_FTMCP100_IRQ	31
++#define MCP_FTMCP100_0_IRQ	31
++
++/* PCIE */
++#define PCIE_FTPCI100_IRQ_COUNT	1
++#define PCIE_FTPCI100_IRQ	17
++#define PCIE_FTPCI100_0_IRQ	17
++
++/* EXT_INT */
++#define EXT_INT_IRQ_COUNT	1
++#define EXT_INT_IRQ	55
++#define EXT_INT_0_IRQ	55
++
++/* SCAL */
++#define SCAL_FTSCAL300_IRQ_COUNT	1
++#define SCAL_FTSCAL300_IRQ	12
++#define SCAL_FTSCAL300_0_IRQ	12
++#define SCAL_FTSCAL300_1_IRQ	44
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	6
++#define SSP_FTSSP010_0_IRQ	6
++#define SSP_FTSSP010_1_IRQ	11
++#define SSP_FTSSP010_2_IRQ	7
++#define SSP_FTSSP010_3_IRQ	54
++#define SSP_FTSSP010_4_IRQ	74
++#define SSP_FTSSP010_5_IRQ	75
++
++/* SSP for PCIE */
++#define SSP_FTSSP010_6_IRQ  (PLATFORM_INTERRUPTS + 17)
++#define SSP_FTSSP010_7_IRQ	(PLATFORM_INTERRUPTS + 18)
++
++/* HDMI */
++#define HDMI_FTHDMI_IRQ_COUNT   1
++#define HDMI_FTHDMI_IRQ     (PLATFORM_GM8312_IRQ_BASE + 8)
++#define HDMI_FTHDMI_0_IRQ   (PLATFORM_GM8312_IRQ_BASE + 8)
++
++/* I2C_PCIE */
++#define I2C_PCIE_FTI2C010_IRQ_COUNT	1
++#define I2C_PCIE_FTI2C010_IRQ	(PLATFORM_INTERRUPTS + 9)
++#define I2C_PCIE_FTI2C010_0_IRQ	(PLATFORM_INTERRUPTS + 9)
++#define I2C_PCIE_FTI2C010_1_IRQ	(PLATFORM_INTERRUPTS + 10)
++#define I2C_PCIE_FTI2C010_2_IRQ	(PLATFORM_INTERRUPTS + 11)
++#define I2C_PCIE_FTI2C010_3_IRQ	(PLATFORM_INTERRUPTS + 12)
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	92
++#define SPI_FTSPI020_0_IRQ	92
++
++/* NAND */
++#define NAND_FTNAND023_IRQ_COUNT	1
++#define NAND_FTNAND023_IRQ	    23
++#define NAND_FTNAND023_0_IRQ	23
++
++/*
++ * Interrupts among FA726, FA626 and FC7500
++ */
++#define CPU_INT_BASE        76
++#define CPU_INT_0           76  /* cpu_comm */
++#define CPU_INT_1           77  /* cpu_comm */
++#define CPU_INT_2           78  /* dma channel6 intr */
++#define CPU_INT_3           79  /* dma channel7 intr */
++#define CPU_INT_4           80  /* dma channel5 intr  */
++#define CPU_INT_5           81  /* SPI020 intr */
++#define CPU_INT_6           82  /* dma channel4 intr */
++#define CPU_INT_7           83  /* available */
++#define CPU_INT_8           84  /* available */
++#define CPU_INT_9           85  /* available */
++#define CPU_INT_10          86  /* available */
++#define CPU_INT_11          87  /* available */
++#define CPU_INT_12          88  /* available */
++#define CPU_INT_13          89  /* available */
++#define CPU_INT_14          90  /* audio_comm, 626 <-> 7500 */
++#define CPU_INT_15          91  /* audio_comm, 626 <-> 7500 */
++
++/*
++ * The following definitions define the interrupts used by modules
++ */
++#define CPU_COMMRX_IRQ          CPU_INT_1
++#define CPU_COMMTX_IRQ          CPU_INT_0
++
++#define AUDIO_COMMRX_IRQ        CPU_INT_15
++#define AUDIO_COMMTX_IRQ        CPU_INT_14
++
++/*
++ * Base addresses
++ */
++/* DDRC */
++#define DDRC_PA_COUNT           2
++#define DDRC_0_PA_BASE          0x99300000
++#define DDRC_0_PA_LIMIT         0x99300FFF
++#define DDRC_0_PA_SIZE          0x00001000
++#define DDRC_1_PA_BASE          0x99700000
++#define DDRC_1_PA_LIMIT         0x99700FFF
++#define DDRC_1_PA_SIZE          0x00001000
++
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x99200000
++#define WDT_FTWDT010_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x99200000
++#define WDT_FTWDT010_0_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/* GPIO */
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	2
++#define GPIO_FTGPIO010_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0x98E00000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0x98E00FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0x99600000
++#define I2C_FTI2C010_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0x99600000
++#define I2C_FTI2C010_0_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_FTI2C010_1_PA_BASE	0x99800000
++#define I2C_FTI2C010_1_PA_LIMIT	0x99800FFF
++#define I2C_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_FTI2C010_2_PA_BASE	0x99900000
++#define I2C_FTI2C010_2_PA_LIMIT	0x99900FFF
++#define I2C_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_FTI2C010_3_PA_BASE	0x99A00000
++#define I2C_FTI2C010_3_PA_LIMIT	0x99A00FFF
++#define I2C_FTI2C010_3_PA_SIZE	0x00001000
++#define I2C_FTI2C010_4_PA_BASE	0x99B00000
++#define I2C_FTI2C010_4_PA_LIMIT	0x99B00FFF
++#define I2C_FTI2C010_4_PA_SIZE	0x00001000
++#define I2C_FTI2C010_5_PA_BASE	0x98c00000
++#define I2C_FTI2C010_5_PA_LIMIT	0x98c00FFF
++#define I2C_FTI2C010_5_PA_SIZE	0x00001000
++
++/* SPI */
++#define SPI_FTSPI020_PA_COUNT	1
++#define SPI_FTSPI020_PA_BASE	0x80300000
++#define SPI_FTSPI020_PA_LIMIT	0x80300FFF
++#define SPI_FTSPI020_PA_SIZE	0x00001000
++#define SPI_FTSPI020_0_PA_BASE	0x80300000
++#define SPI_FTSPI020_0_PA_LIMIT	0x80300FFF
++#define SPI_FTSPI020_0_PA_SIZE	0x00001000
++
++/* NAND */
++#define NAND_FTNAND023_PA_COUNT	1
++#define NAND_FTNAND023_PA_BASE	0x80000000
++#define NAND_FTNAND023_PA_LIMIT	0x800FFFFF
++#define NAND_FTNAND023_PA_SIZE	0x00100000
++#define NAND_FTNAND023_0_PA_BASE	0x80000000
++#define NAND_FTNAND023_0_PA_LIMIT	0x800FFFFF
++#define NAND_FTNAND023_0_PA_SIZE	0x00100000
++
++/* NANDDP */
++#define NANDDP_FTNAND023_PA_COUNT	1
++#define NANDDP_FTNAND023_PA_BASE	0x80100000
++#define NANDDP_FTNAND023_PA_LIMIT	0x801FFFFF
++#define NANDDP_FTNAND023_PA_SIZE	0x00100000
++#define NANDDP_FTNAND023_0_PA_BASE	0x80100000
++#define NANDDP_FTNAND023_0_PA_LIMIT	0x801FFFFF
++#define NANDDP_FTNAND023_0_PA_SIZE	0x00100000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	1
++#define LCD_FTLCDC200_PA_BASE	0x9A800000
++#define LCD_FTLCDC200_PA_LIMIT	0x9A80CFFF
++#define LCD_FTLCDC200_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	0x9A800000
++#define LCD_FTLCDC200_0_PA_LIMIT	0x9A80CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_1_PA_BASE	0x9B200000
++#define LCD_FTLCDC200_1_PA_LIMIT	0x9B20CFFF
++#define LCD_FTLCDC200_1_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_2_PA_BASE	0x9B800000
++#define LCD_FTLCDC200_2_PA_LIMIT	0x9B80CFFF
++#define LCD_FTLCDC200_2_PA_SIZE	0x0000D000
++
++/* Graphic Plance Encoder */
++#define GRAPHIC_ENC_PA_COUNT    1
++#define GRAPHIC_ENC_PA_BASE	    0x9B300000
++#define GRAPHIC_ENC_PA_LIMIT	0x9B300FFF
++#define GRAPHIC_ENC_PA_SIZE	    0x00001000
++#define GRAPHIC_ENC_0_PA_BASE	0x9B300000
++#define GRAPHIC_ENC_0_PA_LIMIT	0x9B300FFF
++#define GRAPHIC_ENC_0_PA_SIZE	0x00001000
++
++/* Graphic Plance Decoder */
++#define GRAPHIC_DEC_PA_COUNT	3
++#define GRAPHIC_DEC_PA_BASE	    0x9B400000
++#define GRAPHIC_DEC_PA_LIMIT	0x9B400FFF
++#define GRAPHIC_DEC_PA_SIZE	    0x00001000
++#define GRAPHIC_DEC_0_PA_BASE	0x9B400000
++#define GRAPHIC_DEC_0_PA_LIMIT	0x9B400FFF
++#define GRAPHIC_DEC_0_PA_SIZE	0x00001000
++#define GRAPHIC_DEC_1_PA_BASE	0x9B500000
++#define GRAPHIC_DEC_1_PA_LIMIT	0x9B500FFF
++#define GRAPHIC_DEC_1_PA_SIZE	0x00001000
++#define GRAPHIC_DEC_2_PA_BASE	0x9B600000
++#define GRAPHIC_DEC_2_PA_LIMIT	0x9B600FFF
++#define GRAPHIC_DEC_2_PA_SIZE	0x00001000
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_PA_COUNT	1
++#define GRA_FT2DGRA_PA_BASE	0x92200000
++#define GRA_FT2DGRA_PA_LIMIT	0x92200FFF
++#define GRA_FT2DGRA_PA_SIZE	0x00001000
++#define GRA_FT2DGRA_0_PA_BASE	0x92200000
++#define GRA_FT2DGRA_0_PA_LIMIT	0x92200FFF
++#define GRA_FT2DGRA_0_PA_SIZE	0x00001000
++
++/* MAC */
++#define MAC_FTGMAC100_PA_COUNT	1
++#define MAC_FTGMAC100_PA_BASE	0x92500000
++#define MAC_FTGMAC100_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_0_PA_BASE	0x92500000
++#define MAC_FTGMAC100_0_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_0_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_1_PA_BASE	0x92300000
++#define MAC_FTGMAC100_1_PA_LIMIT	0x92300FFF
++#define MAC_FTGMAC100_1_PA_SIZE	0x00001000
++
++/* DMAC */
++#define DMAC_FTDMAC020_PA_COUNT		2
++#define DMAC_FTDMAC020_PA_BASE		0x92600000
++#define DMAC_FTDMAC020_PA_LIMIT		0x92600FFF
++#define DMAC_FTDMAC020_PA_SIZE		0x00001000
++#define DMAC_FTDMAC020_0_PA_BASE	0x92600000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0x92600FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++#define DMAC_FTDMAC020_1_PA_BASE	0xA1A00000
++#define DMAC_FTDMAC020_1_PA_LIMIT	0xA1A00FFF
++#define DMAC_FTDMAC020_1_PA_SIZE	0x00001000
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_PA_COUNT	1
++#define XDMAC_FTDMAC030_PA_BASE		0x9A100000
++#define XDMAC_FTDMAC030_PA_LIMIT	0x9A100FFF
++#define XDMAC_FTDMAC030_PA_SIZE		0x00001000
++#define XDMAC_FTDMAC030_0_PA_BASE	0x9A100000
++#define XDMAC_FTDMAC030_0_PA_LIMIT	0x9A100FFF
++#define XDMAC_FTDMAC030_0_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0x92700000
++#define AES_FTAES020_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0x92700000
++#define AES_FTAES020_0_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* CAP */
++#define CAP_FTCAP300_PA_COUNT	1
++#define CAP_FTCAP300_PA_BASE	0x96100000
++#define CAP_FTCAP300_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_PA_SIZE	0x00001000
++#define CAP_FTCAP300_0_PA_BASE	0x96100000
++#define CAP_FTCAP300_0_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_0_PA_SIZE	0x00001000
++
++/* DI3D */
++#define DI3D_FTDI3D_PA_COUNT	2
++#define DI3D_FTDI3D_PA_BASE	    0x9B100000
++#define DI3D_FTDI3D_PA_LIMIT	0x9B100FFF
++#define DI3D_FTDI3D_PA_SIZE	    0x00001000
++#define DI3D_FTDI3D_0_PA_BASE	0x9B100000
++#define DI3D_FTDI3D_0_PA_LIMIT	0x9B100FFF
++#define DI3D_FTDI3D_0_PA_SIZE	0x00001000
++
++#define DI3D_FTDI3D_1_PA_BASE   0x9BA00000
++#define DI3D_FTDI3D_1_PA_LIMIT  0x9BA00FFF
++#define DI3D_FTDI3D_1_PA_SIZE   0x00001000
++
++
++/* H264E */
++#define H264E_FTMCP280_PA_COUNT	1
++#define H264E_FTMCP280_PA_BASE	0x90000000
++#define H264E_FTMCP280_PA_LIMIT	0x90000FFF
++#define H264E_FTMCP280_PA_SIZE	0x00001000
++#define H264E_FTMCP280_0_PA_BASE	0x90000000
++#define H264E_FTMCP280_0_PA_LIMIT	0x90000FFF
++#define H264E_FTMCP280_0_PA_SIZE	0x00001000
++#define H264E_FTMCP280_1_PA_BASE	0x90200000
++#define H264E_FTMCP280_1_PA_LIMIT	0x90200FFF
++#define H264E_FTMCP280_1_PA_SIZE	0x00001000
++
++/* H264D */
++#define H264D_FTMCP300_PA_COUNT	1
++#define H264D_FTMCP300_PA_BASE	0x94200000
++#define H264D_FTMCP300_PA_LIMIT	0x942FFFFF
++#define H264D_FTMCP300_PA_SIZE	0x00100000
++#define H264D_FTMCP300_0_PA_BASE	0x94200000
++#define H264D_FTMCP300_0_PA_LIMIT	0x942FFFFF
++#define H264D_FTMCP300_0_PA_SIZE	0x00100000
++#define H264D_FTMCP300_1_PA_BASE	0x94000000
++#define H264D_FTMCP300_1_PA_LIMIT	0x940FFFFF
++#define H264D_FTMCP300_1_PA_SIZE	0x00100000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0x92000000
++#define MCP_FTMCP100_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_0_PA_BASE	0x92000000
++#define MCP_FTMCP100_0_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++
++/* PCIE */
++#define PCIE_FTPCI100_PA_COUNT	1
++#define PCIE_FTPCI100_PA_BASE	0xA3700000
++#define PCIE_FTPCI100_PA_LIMIT	0xA3700FFF
++#define PCIE_FTPCI100_PA_SIZE	0x00001000
++#define PCIE_FTPCI100_0_PA_BASE	0xA3700000
++#define PCIE_FTPCI100_0_PA_LIMIT	0xA3700FFF
++#define PCIE_FTPCI100_0_PA_SIZE	0x00001000
++#define PCIE_FTPCI100_1_PA_BASE	0xA3800000
++#define PCIE_FTPCI100_1_PA_LIMIT	0xA3800FFF
++#define PCIE_FTPCI100_1_PA_SIZE	0x00001000
++
++/* SCAL */
++#define SCAL_FTSCAL300_PA_COUNT	1
++#define SCAL_FTSCAL300_PA_BASE	0x96200000
++#define SCAL_FTSCAL300_PA_LIMIT	0x96247FFF
++#define SCAL_FTSCAL300_PA_SIZE	0x00048000
++#define SCAL_FTSCAL300_0_PA_BASE	0x96200000
++#define SCAL_FTSCAL300_0_PA_LIMIT	0x96247FFF
++#define SCAL_FTSCAL300_0_PA_SIZE	0x00048000
++#define SCAL_FTSCAL300_1_PA_BASE	0x96300000
++#define SCAL_FTSCAL300_1_PA_LIMIT	0x96347FFF
++#define SCAL_FTSCAL300_1_PA_SIZE	0x00048000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT   1
++#define TVE_FTTVE100_PA_BASE    0xA1800000
++#define TVE_FTTVE100_PA_LIMIT   0xA1800FFF
++#define TVE_FTTVE100_PA_SIZE    0x00001000
++#define TVE_FTTVE100_0_PA_BASE  0xA1800000
++#define TVE_FTTVE100_0_PA_LIMIT 0xA1800FFF
++#define TVE_FTTVE100_0_PA_SIZE  0x00001000
++
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0x82000000
++#define SSP_FTSSP010_PA_LIMIT	0x82000FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0x82000000
++#define SSP_FTSSP010_0_PA_LIMIT	0x82000FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0x82100000
++#define SSP_FTSSP010_1_PA_LIMIT	0x82100FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++#define SSP_FTSSP010_2_PA_BASE	0x82200000
++#define SSP_FTSSP010_2_PA_LIMIT	0x82200FFF
++#define SSP_FTSSP010_2_PA_SIZE	0x00001000
++#define SSP_FTSSP010_3_PA_BASE	0x82300000
++#define SSP_FTSSP010_3_PA_LIMIT	0x82300FFF
++#define SSP_FTSSP010_3_PA_SIZE	0x00001000
++#define SSP_FTSSP010_4_PA_BASE	0x82400000
++#define SSP_FTSSP010_4_PA_LIMIT	0x82400FFF
++#define SSP_FTSSP010_4_PA_SIZE	0x00001000
++#define SSP_FTSSP010_5_PA_BASE	0x82500000
++#define SSP_FTSSP010_5_PA_LIMIT	0x82500FFF
++#define SSP_FTSSP010_5_PA_SIZE	0x00001000
++
++/* PCIE */
++#define SSP_FTSSP010_6_PA_BASE  I2S_PCIE_FTSSP010_0_PA_BASE
++#define SSP_FTSSP010_6_PA_LIMIT I2S_PCIE_FTSSP010_0_PA_LIMIT
++#define SSP_FTSSP010_6_PA_SIZE  I2S_PCIE_FTSSP010_0_PA_SIZE
++
++#define SSP_FTSSP010_7_PA_BASE  I2S_PCIE_FTSSP010_1_PA_BASE
++#define SSP_FTSSP010_7_PA_LIMIT I2S_PCIE_FTSSP010_1_PA_LIMIT
++#define SSP_FTSSP010_7_PA_SIZE  I2S_PCIE_FTSSP010_1_PA_SIZE
++
++/* HDMI */
++#define HDMI_FTHDMI_PA_COUNT    1
++#define HDMI_FTHDMI_PA_BASE 0xA1900000
++#define HDMI_FTHDMI_PA_LIMIT    0xA1900FFF
++#define HDMI_FTHDMI_PA_SIZE 0x00001000
++#define HDMI_FTHDMI_0_PA_BASE   0xA1900000
++#define HDMI_FTHDMI_0_PA_LIMIT  0xA1900FFF
++#define HDMI_FTHDMI_0_PA_SIZE   0x00001000
++
++#define HDMI_FTHDCPMEM_PA_BASE  0xA1B00000
++#define HDMI_FTHDCPMEM_PA_LIMIT 0xA1B001FF
++#define HDMI_FTHDCPMEM_PA_SIZE  0x00000200
++
++/* DMAC_PCIE */
++#define DMAC_PCIE_FTDMAC020_PA_COUNT	1
++#define DMAC_PCIE_FTDMAC020_PA_BASE	0xA1A00000
++#define DMAC_PCIE_FTDMAC020_PA_LIMIT	0xA1A00FFF
++#define DMAC_PCIE_FTDMAC020_PA_SIZE	0x00001000
++#define DMAC_PCIE_FTDMAC020_0_PA_BASE	0xA1A00000
++#define DMAC_PCIE_FTDMAC020_0_PA_LIMIT	0xA1A00FFF
++#define DMAC_PCIE_FTDMAC020_0_PA_SIZE	0x00001000
++
++/* I2C_PCIE */
++#define I2C_PCIE_FTI2C010_PA_COUNT	1
++#define I2C_PCIE_FTI2C010_PA_BASE	0xA3300000
++#define I2C_PCIE_FTI2C010_PA_LIMIT	0xA3300FFF
++#define I2C_PCIE_FTI2C010_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_0_PA_BASE	0xA3300000
++#define I2C_PCIE_FTI2C010_0_PA_LIMIT	0xA3300FFF
++#define I2C_PCIE_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_1_PA_BASE	0xA3400000
++#define I2C_PCIE_FTI2C010_1_PA_LIMIT	0xA3400FFF
++#define I2C_PCIE_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_2_PA_BASE	0xA3500000
++#define I2C_PCIE_FTI2C010_2_PA_LIMIT	0xA3500FFF
++#define I2C_PCIE_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_3_PA_BASE	0xA3600000
++#define I2C_PCIE_FTI2C010_3_PA_LIMIT	0xA3600FFF
++#define I2C_PCIE_FTI2C010_3_PA_SIZE	0x00001000
++
++/* I2S_PCIE */
++#define I2S_PCIE_FTSSP010_PA_COUNT	1
++#define I2S_PCIE_FTSSP010_PA_BASE	0xA3100000
++#define I2S_PCIE_FTSSP010_PA_LIMIT	0xA31FFFFF
++#define I2S_PCIE_FTSSP010_PA_SIZE	0x00100000
++#define I2S_PCIE_FTSSP010_0_PA_BASE	0xA3100000
++#define I2S_PCIE_FTSSP010_0_PA_LIMIT	0xA31FFFFF
++#define I2S_PCIE_FTSSP010_0_PA_SIZE	0x00100000
++#define I2S_PCIE_FTSSP010_1_PA_BASE	0xA3200000
++#define I2S_PCIE_FTSSP010_1_PA_LIMIT	0xA32FFFFF
++#define I2S_PCIE_FTSSP010_1_PA_SIZE	0x00100000
++
++/* IOLINK */
++#define IOLINK_TX_PA_COUNT          3
++#define IOLINK_TX_0_PA_BASE         0x9BB00000
++#define IOLINK_TX_0_PA_SIZE         0x1000
++#define IOLINK_TX_1_PA_BASE         0x9BC00000
++#define IOLINK_TX_1_PA_SIZE         0x1000
++#define IOLINK_TX_2_PA_BASE         0x9BD00000
++#define IOLINK_TX_2_PA_SIZE         0x1000
++
++/* 8310 PCIE */
++#define PCIE_PLDA_PA_COUNT      1
++#define PCIE_PLDA_PA_BASE       0x99E00000
++#define PCIE_PLDA_PA_LIMIT      0x99E01FFF
++#define PCIE_PLDA_PA_SIZE       0x00002000
++#define PCIE_PLDA_0_PA_BASE     0x99E00000
++#define PCIE_PLDA_0_PA_LIMIT    0x99E01FFF
++#define PCIE_PLDA_0_PA_SIZE     0x00002000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++#define PLATFORM_IRQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL1	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL1	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL3	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL3	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL4	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL4	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL5	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL5	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL6	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL6	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL7	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL7	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL8	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL8	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE9	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL9	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE9	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL9	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE10	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL10	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE10	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL10	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE11	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL11	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE11	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL11	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE12	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL12	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE12	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL12	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE13	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL13	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE13	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL13	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE14	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL14	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE14	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL14	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE15	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL15	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE15	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL15	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODEEX2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVELEX2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODEEX2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVELEX2	0xFFFFFFFF
++
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/pmu.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/pmu.h
+new file mode 100644
+index 00000000..1a9fb19d
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/pmu.h
+@@ -0,0 +1,33 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++#define GM8210_TEST_CHIP_ID 0x821010
++
++unsigned int pmu_get_apb_clk(void);
++unsigned int pmu_get_apb0_clk(void);
++unsigned int pmu_get_apb1_clk(void);
++unsigned int pmu_get_apb2_clk(void);
++int platform_check_flash_type(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/pmu_pcie.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/pmu_pcie.h
+new file mode 100644
+index 00000000..39f135eb
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/pmu_pcie.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/pmu_pcie.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_PCIE_H__
++#define __PMU_PCIE_H__
++
++#define GM8312_TEST_CHIP_ID 0x831200
++
++unsigned int pmu_pcie_get_apb_clk(void);
++unsigned int pmu_pcie_get_ahb_clk(void);
++unsigned int pmu_pcie_get_axi_clk(void);
++void pmu_pcie_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_PCIE_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/serial.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/serial.h
+new file mode 100644
+index 00000000..46b9d82b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/serial.h
+@@ -0,0 +1,49 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 4 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created.
++ */
++
++//#define UART_CLKSRC_OSCH//issue
++
++#ifdef UART_CLKSRC_OSCH
++#define CONFIG_UART_CLK			12288000//12000000
++#else
++#define CONFIG_UART_CLK			25000000//(30000000/16)
++#endif
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#ifdef UART_FTUART010_1_VA_BASE
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++#else
++#define EXTENDED_UART_1
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/system.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/system.h
+new file mode 100644
+index 00000000..ca2dee55
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/system.h
+@@ -0,0 +1,76 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/system.h
++ *
++ *  Faraday Platform Dependent System Definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++static inline void arch_reset(char mode, const char *cmd)
++{
++#define BIT13 (0x1<<13)
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++    pmuReg_t regRSTArray[] = {
++    	/* reg_off,bit_masks,lock_bits,init_val,init_mask */
++	{0xB8, BIT13, BIT13, 0, BIT13},
++    };
++    pmuRegInfo_t rst_clk_info = {
++    	"rst_clk",
++	ARRAY_SIZE(regRSTArray),
++	ATTR_TYPE_NONE,
++	regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<13)), (PMU_FTPMU010_VA_BASE + 0xB8));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C)); //reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));//load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08)); /*Magic number*/
++    writeb(0x03, (wdt_va_base + 0x0C)); /*Enable WDT */
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/vmalloc.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/vmalloc.h
+new file mode 100644
+index 00000000..b86c26fe
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210-S/vmalloc.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/vmalloc.h
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/board.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/board.h
+new file mode 100644
+index 00000000..f9e1e8b7
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/board.h
+@@ -0,0 +1,148 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/board.h
++ *
++ *  GM board Independent Specification
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ *  ChangeLog
++ *
++ *   Harry  2012/3/6 03:15 created.
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM8210"
++#define BOOT_PARAMETER_PA_OFFSET  0x100
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0x99000000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE    0x98300000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        9
++
++#define UART_FTUART010_1_PA_BASE    0x98400000
++#define UART_FTUART010_1_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_1_VA_SIZE    SZ_4K
++#define UART_FTUART010_1_IRQ        10
++
++#define UART_FTUART010_2_PA_BASE    0x98500000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_1_VA_BASE + UART_FTUART010_1_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        20
++
++#define UART_FTUART010_3_PA_BASE    0x98800000
++#define UART_FTUART010_3_VA_BASE    (UART_FTUART010_2_VA_BASE + UART_FTUART010_2_VA_SIZE)
++#define UART_FTUART010_3_VA_SIZE    SZ_4K
++#define UART_FTUART010_3_IRQ        21
++
++#define UART_FTUART010_4_PA_BASE    0x98900000
++#define UART_FTUART010_4_VA_BASE    (UART_FTUART010_3_VA_BASE + UART_FTUART010_3_VA_SIZE)
++#define UART_FTUART010_4_VA_SIZE    SZ_4K
++#define UART_FTUART010_4_IRQ        22
++
++#define UART_FTUART010_5_PA_BASE    0x82600000
++#define UART_FTUART010_5_VA_BASE    (UART_FTUART010_4_VA_BASE + UART_FTUART010_4_VA_SIZE)
++#define UART_FTUART010_5_VA_SIZE    SZ_4K
++#define UART_FTUART010_5_IRQ        25
++
++/* TIMER */
++#define TIMER_FTTMR010_0_PA_BASE	    0x99100000
++#define TIMER_FTTMR010_0_VA_BASE	    (UART_FTUART010_5_VA_BASE + UART_FTUART010_5_VA_SIZE)
++#define TIMER_FTTMR010_0_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_0_IRQ_COUNT    3
++#define TIMER_FTTMR010_0_IRQ0         14
++#define TIMER_FTTMR010_0_IRQ1         14
++#define TIMER_FTTMR010_0_IRQ2         14
++
++#define TIMER_FTTMR010_2_PA_BASE	    0x98D00000
++#define TIMER_FTTMR010_2_VA_BASE	    (TIMER_FTTMR010_0_VA_BASE + TIMER_FTTMR010_0_VA_SIZE)
++#define TIMER_FTTMR010_2_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_2_IRQ_COUNT    3
++#define TIMER_FTTMR010_2_IRQ0         73
++#define TIMER_FTTMR010_2_IRQ1         73
++#define TIMER_FTTMR010_2_IRQ2         73
++
++/* INTC030 */
++#define INTC_FTINTC030_PA_BASE      0x96000000
++#define INTC_FTINTC030_VA_BASE      (TIMER_FTTMR010_2_VA_BASE + TIMER_FTTMR010_2_VA_SIZE)
++#define INTC_FTINTC030_VA_SIZE	    SZ_4K
++
++/* PCI_PMU */
++#define PCIPMU_FTPMU010_PA_BASE     0xC2700000
++#define PCIPMU_FTPMU010_VA_BASE     (INTC_FTINTC030_VA_BASE + INTC_FTINTC030_VA_SIZE)
++#define PCIPMU_FTPMU010_VA_SIZE     SZ_4K
++
++/* INTC010 */
++#define INTC_FTINTC010_PA_BASE      0xC2800000
++#define INTC_FTINTC010_VA_BASE      (PCIPMU_FTPMU010_VA_BASE + PCIPMU_FTPMU010_VA_SIZE)
++#define INTC_FTINTC010_VA_SIZE	    SZ_4K
++
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++
++#define BOARD_BUS_LOCK_SUPPORT      1
++
++typedef enum {
++    BUS_LOCK_I2C = 0,
++    BUS_LOCK_I2C1,
++    BUS_LOCK_I2C2,
++    BUS_LOCK_I2C3,
++    BUS_LOCK_I2C4,
++    BUS_LOCK_I2C5,
++} bus_lock_t;
++
++void board_bus_lock_init(bus_lock_t bus);
++void board_bus_lock(bus_lock_t bus);
++void board_bus_unlock(bus_lock_t bus);
++/* return value:
++ *  -1 for fail which means the bus was locked by others
++ *  0 for grab the lock success
++ */
++int board_bus_trylock(bus_lock_t bus);
++
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/gpio.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/gpio.h
+new file mode 100644
+index 00000000..c26a9e86
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8126_GPIO_H__
++#define __GM8126_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		3
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8126_GPIO_H__
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/irqs.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/irqs.h
+new file mode 100644
+index 00000000..45887a1b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/irqs.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/irqs.h
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Justin Shih  10/06/2012  Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/memory.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/memory.h
+new file mode 100644
+index 00000000..45627821
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/memory.h
+@@ -0,0 +1,68 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/memory.h
++ *
++ *  GM Platform Dependent Memory Configuration
++ *
++ * 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
++ *
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define FA726_PHYS_OFFSET   0x1000000
++#define FA626_PHYS_OFFSET   0x10000000
++
++extern unsigned long phys_offset;
++#define PHYS_OFFSET     phys_offset	//CPU_MEM_PA_BASE//0x0
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management.
++ *
++ * Users can adjust the memory size based on the real memory size requirement.
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     0x1000000 // fa626 = (50 << 20)
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement.
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE.
++ * The memory boundary is 16M alginment
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/platform_io.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/platform_io.h
+new file mode 100644
+index 00000000..554c49a5
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/platform_io.h
+@@ -0,0 +1,904 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/platform_io.h
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++#define PLATFORM_FIQ_BASE       0
++#define PLATFORM_IRQ_TOTALCOUNT		96/* interrupt controller supports 96 interrupts */
++#define PLATFORM_GM8312_IRQ_TOTALCOUNT 	32
++#define PLATFORM_GM8312_IRQ_BASE      	PLATFORM_IRQ_TOTALCOUNT
++#define PLATFORM_INTERRUPTS     (PLATFORM_IRQ_TOTALCOUNT + PLATFORM_GM8312_IRQ_TOTALCOUNT)
++
++/*
++ * Component counts
++ */
++
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	2
++#define GPIO_FTGPIO010_COUNT	2
++/* I2C */
++#define I2C_COUNT	6
++#define I2C_FTI2C010_COUNT	6
++/* SSP */
++#define SSP_COUNT	6
++#define SSP_FTSSP010_COUNT	6
++/* SPI020 */
++#define SPI_COUNT	1
++#define SPI_FTSPI020_COUNT	1
++/* SDC */
++#define SDC_COUNT	1
++#define SDC_FTSDC021_COUNT	1
++/* NAND */
++#define NAND_COUNT	1
++#define NAND_FTNAND023_COUNT	1
++/* NANDDP */
++#define NANDDP_COUNT	1
++#define NANDDP_FTNAND023_COUNT	1
++/* LCD */
++#define LCD_COUNT	3
++#define LCD_FTLCDC200_COUNT	3
++/* SMC */
++#define SMC_COUNT	1
++#define SMC_FTSMC010_COUNT	1
++/* 2D GRAPHIC */
++#define GRA_COUNT	1
++#define GRA_FT2DGRA_COUNT	1
++/* MAC */
++#define MAC_COUNT	2
++#define MAC_FTGMAC100_COUNT	2
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* CAP */
++#define CAP_COUNT	1
++#define CAP_FTCAP300_COUNT	2
++/* DI3D */
++#define DI3D_COUNT	2
++#define DI3D_FTDI3D_COUNT	2
++/* H264E */
++#define H264E_COUNT	2
++#define H264E_FTMCP280_COUNT	2
++/* H264D */
++#define H264D_COUNT	2
++#define H264D_FTMCP300_COUNT	2
++/* MCP */
++#define MCP_COUNT	1
++#define MCP_FTMCP100_COUNT	1
++/* IR_DET */
++#define IR_DET_COUNT	1
++#define IR_DET_FTIRDET_COUNT	1
++/* KPD */
++#define KPD_COUNT	1
++#define KPD_FTKPD_COUNT	1
++/* PCIE */
++#define PCIE_COUNT	2
++#define PCIE_FTPCI100_COUNT	2
++/* SATA */
++#define SATA_COUNT	4
++#define SATA_FTSATA100_COUNT	4
++/* OTG */
++#define OTG_COUNT	3
++#define USB_FOTG2XX_COUNT	3
++/* TVE */
++#define TVE_COUNT	1
++#define TVE_FTTVE100_COUNT	1
++/* HDMI */
++#define HDMI_COUNT	1
++#define HDMI_FTHDMI_COUNT	1
++/* AHBC */
++#define AHBC_COUNT	1
++#define AHBC_FTAHBC020_COUNT	1
++/* APBB */
++#define APBB_COUNT	3
++#define APBB_FTAPBB020_COUNT	3
++/* DMAC */
++#define DMAC_COUNT	2
++#define DMAC_FTDMAC020_COUNT	2
++/* XDMAC */
++#define XDMAC_COUNT	1
++#define XDMAC_FTDMAC030_COUNT	1
++/* I2S_PCIE */
++#define I2S_PCIE_COUNT	2
++#define I2S_PCIE_FTSSP010_COUNT	2
++/* I2C_PCIE */
++#define I2C_PCIE_COUNT	4
++#define I2C_PCIE_FTSSP010_COUNT	4
++/* SCAL */
++#define SCAL_COUNT  2
++#define SCAL_FTSCAL300_COUNT    2
++/* DMAC_PCIE */
++#define DMAC_PCIE_COUNT	1
++#define DMAC_PCIE_FTDMAC020_COUNT	1
++
++/*
++ * Interrrupt numbers
++ */
++/* DDR IRQ */
++#define DDRC_IRQ_COUNT  2
++#define DDRC0_IRQ       26
++#define DDRC1_IRQ       27
++
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	16
++#define WDT_FTWDT010_0_IRQ	16
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	1
++#define GPIO_FTGPIO010_IRQ	13
++#define GPIO_FTGPIO010_0_IRQ	13
++#define GPIO_FTGPIO010_1_IRQ	63
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	18
++#define I2C_FTI2C010_0_IRQ	18
++#define I2C_FTI2C010_1_IRQ	53
++#define I2C_FTI2C010_2_IRQ	50
++#define I2C_FTI2C010_3_IRQ	51
++#define I2C_FTI2C010_4_IRQ	52
++#define I2C_FTI2C010_5_IRQ	43
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	6
++#define SSP_FTSSP010_0_IRQ	6
++#define SSP_FTSSP010_1_IRQ	11
++#define SSP_FTSSP010_2_IRQ	7
++#define SSP_FTSSP010_3_IRQ	54
++#define SSP_FTSSP010_4_IRQ	74
++#define SSP_FTSSP010_5_IRQ	75
++
++/* SSP for PCIE */
++#define SSP_FTSSP010_6_IRQ  I2S_PCIE_FTSSP010_0_IRQ
++#define SSP_FTSSP010_7_IRQ	I2S_PCIE_FTSSP010_1_IRQ
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	92
++#define SPI_FTSPI020_0_IRQ	92
++
++/* SDC */
++#define SDC_FTSDC021_IRQ_COUNT	1
++#define SDC_FTSDC021_IRQ	15
++#define SDC_FTSDC021_0_IRQ	15
++
++/* NAND */
++#define NAND_FTNAND023_IRQ_COUNT	1
++#define NAND_FTNAND023_IRQ	23
++#define NAND_FTNAND023_0_IRQ	23
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	24
++#define LCD_FTLCDC200_0_IRQ	24
++#define LCD_FTLCDC200_1_IRQ	45
++#define LCD_FTLCDC200_2_IRQ	46
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_IRQ_COUNT	1
++#define GRA_FT2DGRA_IRQ	4
++#define GRA_FT2DGRA_0_IRQ	4
++
++/* MAC */
++#define MAC_FTGMAC100_IRQ_COUNT	1
++#define MAC_FTGMAC100_IRQ	3
++#define MAC_FTGMAC100_0_IRQ	3
++#define MAC_FTGMAC100_1_IRQ	33
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	19
++#define AES_FTAES020_0_IRQ	19
++
++/* CAP */
++#define CAP_FTCAP300_IRQ_COUNT	1
++#define CAP_FTCAP300_IRQ	32
++#define CAP_FTCAP300_0_IRQ	32
++
++/* DI3D */
++#define DI3D_FTDI3D_IRQ_COUNT	1
++#define DI3D_FTDI3D_IRQ	41
++#define DI3D_FTDI3D_0_IRQ	41
++#define DI3D_FTDI3D_1_IRQ	42
++
++/* H264E */
++#define H264E_FTMCP280_IRQ_COUNT	1
++#define H264E_FTMCP280_IRQ	29
++#define H264E_FTMCP280_0_IRQ	29
++#define H264E_FTMCP280_1_IRQ	28
++
++/* H264D */
++#define H264D_FTMCP300_IRQ_COUNT	1
++#define H264D_FTMCP300_IRQ	30
++#define H264D_FTMCP300_0_IRQ	30
++#define H264D_FTMCP300_1_IRQ	40
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	1
++#define MCP_FTMCP100_IRQ	31
++#define MCP_FTMCP100_0_IRQ	31
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_IRQ_COUNT	1
++#define XDMAC_FTDMAC030_IRQ		34
++#define XDMAC_FTDMAC030_0_IRQ		34
++#define XDMAC_FTDMAC030_0_0_IRQ         61
++#define XDMAC_FTDMAC030_0_1_IRQ         62
++
++/* IR_DET */
++#define IR_DET_FTIRDET_IRQ_COUNT	1
++#define IR_DET_FTIRDET_IRQ	48
++#define IR_DET_FTIRDET_0_IRQ	48
++
++/* KPD */
++#define KPD_FTKPD_IRQ_COUNT	1
++#define KPD_FTKPD_IRQ	49
++#define KPD_FTKPD_0_IRQ	49
++
++/* PCIE */
++#define PCIE_FTPCI100_IRQ_COUNT	1
++#define PCIE_FTPCI100_IRQ	17
++#define PCIE_FTPCI100_0_IRQ	17
++
++/* EXT_INT */
++#define EXT_INT_IRQ_COUNT	1
++#define EXT_INT_IRQ	55
++#define EXT_INT_0_IRQ	55
++
++/* SATA */
++#define SATA_FTSATA100_IRQ_COUNT	1
++#define SATA_FTSATA100_IRQ	(PLATFORM_GM8312_IRQ_BASE + 1)
++#define SATA_FTSATA100_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 1)
++#define SATA_FTSATA100_1_IRQ	(PLATFORM_GM8312_IRQ_BASE + 2)
++#define SATA_FTSATA100_2_IRQ	(PLATFORM_GM8312_IRQ_BASE + 3)
++#define SATA_FTSATA100_3_IRQ	(PLATFORM_GM8312_IRQ_BASE + 4)
++
++/* OTG */
++#define USB_FOTG2XX_IRQ_COUNT	3
++#define USB_FOTG2XX_IRQ		(PLATFORM_GM8312_IRQ_BASE + 5)
++#define USB_FOTG2XX_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 5)
++#define USB_FOTG2XX_1_IRQ	(PLATFORM_GM8312_IRQ_BASE + 6)
++#define USB_FOTG2XX_2_IRQ	(PLATFORM_GM8312_IRQ_BASE + 7)
++
++/* HDMI */
++#define HDMI_FTHDMI_IRQ_COUNT	1
++#define HDMI_FTHDMI_IRQ		(PLATFORM_GM8312_IRQ_BASE + 8)
++#define HDMI_FTHDMI_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 8)
++
++/* DMAC */
++#define DMAC_FTDMAC020_IRQ_COUNT	2
++#define DMAC_FTDMAC020_IRQ		1
++#define DMAC_FTDMAC020_0_IRQ		1
++#define DMAC_FTDMAC020_1_IRQ		(PLATFORM_GM8312_IRQ_BASE + 16)
++
++/* APBB */
++#define APBB_FTAPBB020_IRQ_COUNT	3
++#define APBB_FTAPBB020_IRQ		2
++#define APBB_FTAPBB020_0_IRQ		2
++#define APBB_FTAPBB020_1_IRQ		5
++#define APBB_FTAPBB020_2_IRQ		60
++
++/* I2S_PCIE */
++#define I2S_PCIE_FTSSP010_IRQ_COUNT	2
++#define I2S_PCIE_FTSSP010_IRQ	(PLATFORM_GM8312_IRQ_BASE + 17)
++#define I2S_PCIE_FTSSP010_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 17)
++#define I2S_PCIE_FTSSP010_1_IRQ	(PLATFORM_GM8312_IRQ_BASE + 18)
++
++/* SCAL */
++#define SCAL_FTSCAL300_IRQ_COUNT    1
++#define SCAL_FTSCAL300_IRQ  12
++#define SCAL_FTSCAL300_0_IRQ    12
++#define SCAL_FTSCAL300_1_IRQ    44
++
++/*
++ * Interrupts among FA726, FA626 and FC7500
++ */
++#define CPU_INT_BASE        76
++#define CPU_INT_0           76  /* cpu_comm */
++#define CPU_INT_1           77  /* cpu_comm */
++#define CPU_INT_2           78  /* dma channel6 intr */
++#define CPU_INT_3           79  /* dma channel7 intr */
++#define CPU_INT_4           80  /* dma channel5 intr */
++#define CPU_INT_5           81  /* cpu_comm */
++#define CPU_INT_6           82  /* dma channel4 intr */
++#define CPU_INT_7           83  /* cpu_comm */
++#define CPU_INT_8           84  /* cpu_comm */
++#define CPU_INT_9           85  /* cpu_comm */
++#define CPU_INT_10          86  /* SATA */
++#define CPU_INT_11          87  /* SATA */
++#define CPU_INT_12          88  /* SATA */
++#define CPU_INT_13          89  /* SATA */
++#define CPU_INT_14          90  /* audio_comm, 626 <-> 7500 */
++#define CPU_INT_15          91  /* audio_comm, 626 <-> 7500 */
++
++/*
++ * Base addresses
++ */
++/* DDRC */
++#define DDRC_PA_COUNT           2
++#define DDRC_0_PA_BASE          0x99300000
++#define DDRC_0_PA_LIMIT         0x99300FFF
++#define DDRC_0_PA_SIZE          0x00001000
++#define DDRC_1_PA_BASE          0x99700000
++#define DDRC_1_PA_LIMIT         0x99700FFF
++#define DDRC_1_PA_SIZE          0x00001000
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x99200000
++#define WDT_FTWDT010_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x99200000
++#define WDT_FTWDT010_0_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	1
++#define GPIO_FTGPIO010_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0x98E00000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0x98E00FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0x99600000
++#define I2C_FTI2C010_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0x99600000
++#define I2C_FTI2C010_0_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_FTI2C010_1_PA_BASE	0x99800000
++#define I2C_FTI2C010_1_PA_LIMIT	0x99800FFF
++#define I2C_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_FTI2C010_2_PA_BASE	0x99900000
++#define I2C_FTI2C010_2_PA_LIMIT	0x99900FFF
++#define I2C_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_FTI2C010_3_PA_BASE	0x99A00000
++#define I2C_FTI2C010_3_PA_LIMIT	0x99A00FFF
++#define I2C_FTI2C010_3_PA_SIZE	0x00001000
++#define I2C_FTI2C010_4_PA_BASE	0x99B00000
++#define I2C_FTI2C010_4_PA_LIMIT	0x99B00FFF
++#define I2C_FTI2C010_4_PA_SIZE	0x00001000
++#define I2C_FTI2C010_5_PA_BASE	0x98c00000
++#define I2C_FTI2C010_5_PA_LIMIT	0x98c00FFF
++#define I2C_FTI2C010_5_PA_SIZE	0x00001000
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0x82000000
++#define SSP_FTSSP010_PA_LIMIT	0x82000FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0x82000000
++#define SSP_FTSSP010_0_PA_LIMIT	0x82000FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0x82100000
++#define SSP_FTSSP010_1_PA_LIMIT	0x82100FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++#define SSP_FTSSP010_2_PA_BASE	0x82200000
++#define SSP_FTSSP010_2_PA_LIMIT	0x82200FFF
++#define SSP_FTSSP010_2_PA_SIZE	0x00001000
++#define SSP_FTSSP010_3_PA_BASE	0x82300000
++#define SSP_FTSSP010_3_PA_LIMIT	0x82300FFF
++#define SSP_FTSSP010_3_PA_SIZE	0x00001000
++#define SSP_FTSSP010_4_PA_BASE	0x82400000
++#define SSP_FTSSP010_4_PA_LIMIT	0x82400FFF
++#define SSP_FTSSP010_4_PA_SIZE	0x00001000
++#define SSP_FTSSP010_5_PA_BASE	0x82500000
++#define SSP_FTSSP010_5_PA_LIMIT	0x82500FFF
++#define SSP_FTSSP010_5_PA_SIZE	0x00001000
++
++/* PCIE */
++#define SSP_FTSSP010_6_PA_BASE  I2S_PCIE_FTSSP010_0_PA_BASE
++#define SSP_FTSSP010_6_PA_LIMIT I2S_PCIE_FTSSP010_0_PA_LIMIT
++#define SSP_FTSSP010_6_PA_SIZE  I2S_PCIE_FTSSP010_0_PA_SIZE
++
++#define SSP_FTSSP010_7_PA_BASE  I2S_PCIE_FTSSP010_1_PA_BASE
++#define SSP_FTSSP010_7_PA_LIMIT I2S_PCIE_FTSSP010_1_PA_LIMIT
++#define SSP_FTSSP010_7_PA_SIZE  I2S_PCIE_FTSSP010_1_PA_SIZE
++
++/* SPI */
++#define SPI_FTSPI020_PA_COUNT	1
++#define SPI_FTSPI020_PA_BASE	0x80300000
++#define SPI_FTSPI020_PA_LIMIT	0x80300FFF
++#define SPI_FTSPI020_PA_SIZE	0x00001000
++#define SPI_FTSPI020_0_PA_BASE	0x80300000
++#define SPI_FTSPI020_0_PA_LIMIT	0x80300FFF
++#define SPI_FTSPI020_0_PA_SIZE	0x00001000
++
++/* SDC */
++#define SDC_FTSDC021_PA_COUNT	1
++#define SDC_FTSDC021_PA_BASE	0x92800000
++#define SDC_FTSDC021_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_PA_SIZE	0x00001000
++#define SDC_FTSDC021_0_PA_BASE	0x92800000
++#define SDC_FTSDC021_0_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_0_PA_SIZE	0x00001000
++
++/* NAND */
++#define NAND_FTNAND023_PA_COUNT	1
++#define NAND_FTNAND023_PA_BASE	0x80000000
++#define NAND_FTNAND023_PA_LIMIT	0x800FFFFF
++#define NAND_FTNAND023_PA_SIZE	0x00100000
++#define NAND_FTNAND023_0_PA_BASE	0x80000000
++#define NAND_FTNAND023_0_PA_LIMIT	0x800FFFFF
++#define NAND_FTNAND023_0_PA_SIZE	0x00100000
++
++/* NANDDP */
++#define NANDDP_FTNAND023_PA_COUNT	1
++#define NANDDP_FTNAND023_PA_BASE	0x80100000
++#define NANDDP_FTNAND023_PA_LIMIT	0x801FFFFF
++#define NANDDP_FTNAND023_PA_SIZE	0x00100000
++#define NANDDP_FTNAND023_0_PA_BASE	0x80100000
++#define NANDDP_FTNAND023_0_PA_LIMIT	0x801FFFFF
++#define NANDDP_FTNAND023_0_PA_SIZE	0x00100000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	1
++#define LCD_FTLCDC200_PA_BASE	0x9A800000
++#define LCD_FTLCDC200_PA_LIMIT	0x9A80CFFF
++#define LCD_FTLCDC200_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	0x9A800000
++#define LCD_FTLCDC200_0_PA_LIMIT	0x9A80CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_1_PA_BASE	0x9B200000
++#define LCD_FTLCDC200_1_PA_LIMIT	0x9B20CFFF
++#define LCD_FTLCDC200_1_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_2_PA_BASE	0x9B800000
++#define LCD_FTLCDC200_2_PA_LIMIT	0x9B80CFFF
++#define LCD_FTLCDC200_2_PA_SIZE	0x0000D000
++
++/* Graphic Plance Encoder */
++#define GRAPHIC_ENC_PA_COUNT    1
++#define GRAPHIC_ENC_PA_BASE	    0x9B300000
++#define GRAPHIC_ENC_PA_LIMIT	0x9B300FFF
++#define GRAPHIC_ENC_PA_SIZE	    0x00001000
++#define GRAPHIC_ENC_0_PA_BASE	0x9B300000
++#define GRAPHIC_ENC_0_PA_LIMIT	0x9B300FFF
++#define GRAPHIC_ENC_0_PA_SIZE	0x00001000
++
++/* Graphic Plance Decoder */
++#define GRAPHIC_DEC_PA_COUNT	3
++#define GRAPHIC_DEC_PA_BASE	    0x9B400000
++#define GRAPHIC_DEC_PA_LIMIT	0x9B400FFF
++#define GRAPHIC_DEC_PA_SIZE	    0x00001000
++#define GRAPHIC_DEC_0_PA_BASE	0x9B400000
++#define GRAPHIC_DEC_0_PA_LIMIT	0x9B400FFF
++#define GRAPHIC_DEC_0_PA_SIZE	0x00001000
++#define GRAPHIC_DEC_1_PA_BASE	0x9B500000
++#define GRAPHIC_DEC_1_PA_LIMIT	0x9B500FFF
++#define GRAPHIC_DEC_1_PA_SIZE	0x00001000
++#define GRAPHIC_DEC_2_PA_BASE	0x9B600000
++#define GRAPHIC_DEC_2_PA_LIMIT	0x9B600FFF
++#define GRAPHIC_DEC_2_PA_SIZE	0x00001000
++
++/* SMC */
++#define SMC_FTSMC010_PA_COUNT	1
++#define SMC_FTSMC010_PA_BASE	0x92100000
++#define SMC_FTSMC010_PA_LIMIT	0x92100FFF
++#define SMC_FTSMC010_PA_SIZE	0x00001000
++#define SMC_FTSMC010_0_PA_BASE	0x92100000
++#define SMC_FTSMC010_0_PA_LIMIT	0x92100FFF
++#define SMC_FTSMC010_0_PA_SIZE	0x00001000
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_PA_COUNT	1
++#define GRA_FT2DGRA_PA_BASE	0x92200000
++#define GRA_FT2DGRA_PA_LIMIT	0x92200FFF
++#define GRA_FT2DGRA_PA_SIZE	0x00001000
++#define GRA_FT2DGRA_0_PA_BASE	0x92200000
++#define GRA_FT2DGRA_0_PA_LIMIT	0x92200FFF
++#define GRA_FT2DGRA_0_PA_SIZE	0x00001000
++
++/* MAC */
++#define MAC_FTGMAC100_PA_COUNT	1
++#define MAC_FTGMAC100_PA_BASE	0x92500000
++#define MAC_FTGMAC100_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_0_PA_BASE	0x92500000
++#define MAC_FTGMAC100_0_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_0_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_1_PA_BASE	0x92300000
++#define MAC_FTGMAC100_1_PA_LIMIT	0x92300FFF
++#define MAC_FTGMAC100_1_PA_SIZE	0x00001000
++
++/* DMAC */
++#define DMAC_FTDMAC020_PA_COUNT		2
++#define DMAC_FTDMAC020_PA_BASE		0x92600000
++#define DMAC_FTDMAC020_PA_LIMIT		0x92600FFF
++#define DMAC_FTDMAC020_PA_SIZE		0x00001000
++#define DMAC_FTDMAC020_0_PA_BASE	0x92600000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0x92600FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++#define DMAC_FTDMAC020_1_PA_BASE	0xC1A00000
++#define DMAC_FTDMAC020_1_PA_LIMIT	0xC1A00FFF
++#define DMAC_FTDMAC020_1_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0x92700000
++#define AES_FTAES020_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0x92700000
++#define AES_FTAES020_0_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* CAP */
++#define CAP_FTCAP300_PA_COUNT	1
++#define CAP_FTCAP300_PA_BASE	0x96100000
++#define CAP_FTCAP300_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_PA_SIZE	0x00001000
++#define CAP_FTCAP300_0_PA_BASE	0x96100000
++#define CAP_FTCAP300_0_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_0_PA_SIZE	0x00001000
++
++/* AHBC */
++#define AHBC_FTAHBC020_PA_COUNT		1
++#define AHBC_FTAHBC020_PA_BASE		0x92A00000
++#define AHBC_FTAHBC020_PA_LIMIT		0x92A00FFF
++#define AHBC_FTAHBC020_PA_SIZE		0x00001000
++#define AHBC_FTAHBC020_0_PA_BASE	0x92A00000
++#define AHBC_FTAHBC020_0_PA_LIMIT	0x92A00FFF
++#define AHBC_FTAHBC020_0_PA_SIZE	0x00001000
++
++/* APBB */
++#define APBB_FTAPBB020_PA_COUNT		3
++#define APBB_FTAPBB020_PA_BASE		0x98100000
++#define APBB_FTAPBB020_PA_LIMIT		0x98100FFF
++#define APBB_FTAPBB020_PA_SIZE		0x00001000
++#define APBB_FTAPBB020_0_PA_BASE	0x98100000
++#define APBB_FTAPBB020_0_PA_LIMIT	0x98100FFF
++#define APBB_FTAPBB020_0_PA_SIZE	0x00001000
++#define APBB_FTAPBB020_1_PA_BASE	0x9A000000
++#define APBB_FTAPBB020_1_PA_LIMIT	0x9A000FFF
++#define APBB_FTAPBB020_1_PA_SIZE	0x00001000
++#define APBB_FTAPBB020_2_PA_BASE	0x92C00000
++#define APBB_FTAPBB020_2_PA_LIMIT	0x92C00FFF
++#define APBB_FTAPBB020_2_PA_SIZE	0x00001000
++
++/* DI3D */
++#define DI3D_FTDI3D_PA_COUNT	2
++#define DI3D_FTDI3D_PA_BASE	    0x9B100000
++#define DI3D_FTDI3D_PA_LIMIT	0x9B100FFF
++#define DI3D_FTDI3D_PA_SIZE	    0x00001000
++#define DI3D_FTDI3D_0_PA_BASE	0x9B100000
++#define DI3D_FTDI3D_0_PA_LIMIT	0x9B100FFF
++#define DI3D_FTDI3D_0_PA_SIZE	0x00001000
++
++#define DI3D_FTDI3D_1_PA_BASE   0x9BA00000
++#define DI3D_FTDI3D_1_PA_LIMIT  0x9BA00FFF
++#define DI3D_FTDI3D_1_PA_SIZE   0x00001000
++
++/* H264E */
++#define H264E_FTMCP280_PA_COUNT	1
++#define H264E_FTMCP280_PA_BASE	0x90000000
++#define H264E_FTMCP280_PA_LIMIT	0x90000FFF
++#define H264E_FTMCP280_PA_SIZE	0x00001000
++#define H264E_FTMCP280_0_PA_BASE	0x90000000
++#define H264E_FTMCP280_0_PA_LIMIT	0x90000FFF
++#define H264E_FTMCP280_0_PA_SIZE	0x00001000
++#define H264E_FTMCP280_1_PA_BASE	0x90200000
++#define H264E_FTMCP280_1_PA_LIMIT	0x90200FFF
++#define H264E_FTMCP280_1_PA_SIZE	0x00001000
++
++/* H264D */
++#define H264D_FTMCP300_PA_COUNT	1
++#define H264D_FTMCP300_PA_BASE	0x94200000
++#define H264D_FTMCP300_PA_LIMIT	0x942FFFFF
++#define H264D_FTMCP300_PA_SIZE	0x00100000
++#define H264D_FTMCP300_0_PA_BASE	0x94200000
++#define H264D_FTMCP300_0_PA_LIMIT	0x942FFFFF
++#define H264D_FTMCP300_0_PA_SIZE	0x00100000
++#define H264D_FTMCP300_1_PA_BASE	0x94000000
++#define H264D_FTMCP300_1_PA_LIMIT	0x940FFFFF
++#define H264D_FTMCP300_1_PA_SIZE	0x00100000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0x92000000
++#define MCP_FTMCP100_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_0_PA_BASE	0x92000000
++#define MCP_FTMCP100_0_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++
++/* IR_DET */
++#define IR_DET_FTIRDET_PA_COUNT	1
++#define IR_DET_FTIRDET_PA_BASE	0x99C00000
++#define IR_DET_FTIRDET_PA_LIMIT	0x99C00FFF
++#define IR_DET_FTIRDET_PA_SIZE	0x00001000
++#define IR_DET_FTIRDET_0_PA_BASE	0x99C00000
++#define IR_DET_FTIRDET_0_PA_LIMIT	0x99C00FFF
++#define IR_DET_FTIRDET_0_PA_SIZE	0x00001000
++
++/* KPD */
++#define KPD_FTKPD_PA_COUNT	1
++#define KPD_FTKPD_PA_BASE	0x99D00000
++#define KPD_FTKPD_PA_LIMIT	0x99D00FFF
++#define KPD_FTKPD_PA_SIZE	0x00001000
++#define KPD_FTKPD_0_PA_BASE	0x99D00000
++#define KPD_FTKPD_0_PA_LIMIT	0x99D00FFF
++#define KPD_FTKPD_0_PA_SIZE	0x00001000
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_PA_COUNT	1
++#define XDMAC_FTDMAC030_PA_BASE		0x9A100000
++#define XDMAC_FTDMAC030_PA_LIMIT	0x9A100FFF
++#define XDMAC_FTDMAC030_PA_SIZE		0x00001000
++#define XDMAC_FTDMAC030_0_PA_BASE	0x9A100000
++#define XDMAC_FTDMAC030_0_PA_LIMIT	0x9A100FFF
++#define XDMAC_FTDMAC030_0_PA_SIZE	0x00001000
++
++/* 8310 PCIE */
++#define PCIE_PLDA_PA_COUNT      1
++#define PCIE_PLDA_PA_BASE       0x99E00000
++#define PCIE_PLDA_PA_LIMIT      0x99E01FFF
++#define PCIE_PLDA_PA_SIZE       0x00002000
++#define PCIE_PLDA_0_PA_BASE     0x99E00000
++#define PCIE_PLDA_0_PA_LIMIT    0x99E01FFF
++#define PCIE_PLDA_0_PA_SIZE     0x00002000
++
++/* 8312 PCIE */
++#define PCIE_PCIE_PLDA_PA_COUNT   1
++#define PCIE_PCIE_PLDA_PA_BASE    0xC3700000
++#define PCIE_PCIE_PLDA_PA_LIMIT   0xC3700FFF
++#define PCIE_PCIE_PLDA_PA_SIZE    0x00001000
++#define PCIE_PCIE_PLDA_0_PA_BASE  0xC3700000
++#define PCIE_PCIE_PLDA_0_PA_LIMIT 0xC3700FFF
++#define PCIE_PCIE_PLDA_0_PA_SIZE  0x00001000
++#define PCIE_PCIE_PLDA_1_PA_BASE  0xC3800000
++#define PCIE_PCIE_PLDA_1_PA_LIMIT 0xC3800FFF
++#define PCIE_PCIE_PLDA_1_PA_SIZE  0x00001000
++
++/* SATA */
++#define SATA_FTSATA100_PA_COUNT	    4
++#define SATA_FTSATA100_PA_BASE      0xC1100000
++#define SATA_FTSATA100_PA_LIMIT     0xC1100FFF
++#define SATA_FTSATA100_PA_SIZE      0x00001000
++#define SATA_FTSATA100_0_PA_BASE    0xC1100000
++#define SATA_FTSATA100_0_PA_LIMIT   0xC1100FFF
++#define SATA_FTSATA100_0_PA_SIZE    0x00001000
++#define SATA_FTSATA100_1_PA_BASE    0xC1200000
++#define SATA_FTSATA100_1_PA_LIMIT   0xC1200FFF
++#define SATA_FTSATA100_1_PA_SIZE    0x00001000
++#define SATA_FTSATA100_2_PA_BASE    0xC1300000
++#define SATA_FTSATA100_2_PA_LIMIT   0xC1300FFF
++#define SATA_FTSATA100_2_PA_SIZE    0x00001000
++#define SATA_FTSATA100_3_PA_BASE    0xC1400000
++#define SATA_FTSATA100_3_PA_LIMIT   0xC1400FFF
++#define SATA_FTSATA100_3_PA_SIZE    0x00001000
++
++/* SATA H2X */
++#define H2X_FTH2X030_SATA_PA_COUNT      4
++#define H2X_FTH2X030_SATA_PA_BASE       0xC2900000
++#define H2X_FTH2X030_SATA_PA_LIMIT      0xC2900FFF
++#define H2X_FTH2X030_SATA_PA_SIZE       0x00001000
++#define H2X_FTH2X030_SATA_0_PA_BASE     0xC2900000
++#define H2X_FTH2X030_SATA_0_PA_LIMIT    0xC2900FFF
++#define H2X_FTH2X030_SATA_0_PA_SIZE     0x00001000
++#define H2X_FTH2X030_SATA_1_PA_BASE     0xC2A00000
++#define H2X_FTH2X030_SATA_1_PA_LIMIT    0xC2A00FFF
++#define H2X_FTH2X030_SATA_1_PA_SIZE     0x00001000
++#define H2X_FTH2X030_SATA_2_PA_BASE     0xC2B00000
++#define H2X_FTH2X030_SATA_2_PA_LIMIT    0xC2B00FFF
++#define H2X_FTH2X030_SATA_2_PA_SIZE     0x00001000
++#define H2X_FTH2X030_SATA_3_PA_BASE     0xC2C00000
++#define H2X_FTH2X030_SATA_3_PA_LIMIT    0xC2C00FFF
++#define H2X_FTH2X030_SATA_3_PA_SIZE     0x00001000
++
++/* OTG */
++#define USB_FOTG2XX_PA_COUNT	3
++#define USB_FOTG2XX_PA_BASE	0xC1500000
++#define USB_FOTG2XX_PA_LIMIT	0xC1500FFF
++#define USB_FOTG2XX_PA_SIZE	0x00001000
++#define USB_FOTG2XX_0_PA_BASE	0xC1500000
++#define USB_FOTG2XX_0_PA_LIMIT	0xC1500FFF
++#define USB_FOTG2XX_0_PA_SIZE	0x00001000
++#define USB_FOTG2XX_1_PA_BASE	0xC1600000
++#define USB_FOTG2XX_1_PA_LIMIT	0xC1600FFF
++#define USB_FOTG2XX_1_PA_SIZE	0x00001000
++#define USB_FOTG2XX_2_PA_BASE	0xC1700000
++#define USB_FOTG2XX_2_PA_LIMIT	0xC1700FFF
++#define USB_FOTG2XX_2_PA_SIZE	0x00001000
++/* OTG H2X0 */
++#define H2X0_FOTG2XX_PA_BASE	0xC2D00000
++#define H2X0_FOTG2XX_PA_SIZE	0x00001000
++/* OTG H2X1 */
++#define H2X1_FOTG2XX_PA_BASE	0xC2E00000
++#define H2X1_FOTG2XX_PA_SIZE	0x00001000
++/* OTG H2X2 */
++#define H2X2_FOTG2XX_PA_BASE	0xC2F00000
++#define H2X2_FOTG2XX_PA_SIZE	0x00001000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT	1
++#define TVE_FTTVE100_PA_BASE	0xC1800000
++#define TVE_FTTVE100_PA_LIMIT	0xC1800FFF
++#define TVE_FTTVE100_PA_SIZE	0x00001000
++#define TVE_FTTVE100_0_PA_BASE	0xC1800000
++#define TVE_FTTVE100_0_PA_LIMIT	0xC1800FFF
++#define TVE_FTTVE100_0_PA_SIZE	0x00001000
++
++/* HDMI */
++#define HDMI_FTHDMI_PA_COUNT	1
++#define HDMI_FTHDMI_PA_BASE	0xC1900000
++#define HDMI_FTHDMI_PA_LIMIT	0xC1900FFF
++#define HDMI_FTHDMI_PA_SIZE	0x00001000
++#define HDMI_FTHDMI_0_PA_BASE	0xC1900000
++#define HDMI_FTHDMI_0_PA_LIMIT	0xC1900FFF
++#define HDMI_FTHDMI_0_PA_SIZE	0x00001000
++
++#define HDMI_FTHDCPMEM_PA_BASE  0xC1B00000
++#define HDMI_FTHDCPMEM_PA_LIMIT 0xC1B001FF
++#define HDMI_FTHDCPMEM_PA_SIZE  0x00000200
++
++/* I2S_PCIE */
++#define I2S_PCIE_FTSSP010_PA_COUNT	2
++#define I2S_PCIE_FTSSP010_PA_BASE	0xC3100000
++#define I2S_PCIE_FTSSP010_PA_LIMIT	0xC3100FFF
++#define I2S_PCIE_FTSSP010_PA_SIZE	0x00001000
++#define I2S_PCIE_FTSSP010_0_PA_BASE	0xC3100000
++#define I2S_PCIE_FTSSP010_0_PA_LIMIT	0xC3100FFF
++#define I2S_PCIE_FTSSP010_0_PA_SIZE	0x00001000
++#define I2S_PCIE_FTSSP010_1_PA_BASE	0xC3200000
++#define I2S_PCIE_FTSSP010_1_PA_LIMIT	0xC3200FFF
++#define I2S_PCIE_FTSSP010_1_PA_SIZE	0x00001000
++
++/* I2C_PCIE */
++#define I2C_PCIE_FTI2C010_PA_COUNT	4
++#define I2C_PCIE_FTI2C010_PA_BASE	0xC3300000
++#define I2C_PCIE_FTI2C010_PA_LIMIT	0xC3300FFF
++#define I2C_PCIE_FTI2C010_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_0_PA_BASE	0xC3300000
++#define I2C_PCIE_FTI2C010_0_PA_LIMIT	0xC3300FFF
++#define I2C_PCIE_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_1_PA_BASE	0xC3400000
++#define I2C_PCIE_FTI2C010_1_PA_LIMIT	0xC3400FFF
++#define I2C_PCIE_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_2_PA_BASE	0xC3500000
++#define I2C_PCIE_FTI2C010_2_PA_LIMIT	0xC3500FFF
++#define I2C_PCIE_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_PCIE_FTI2C010_3_PA_BASE	0xC3600000
++#define I2C_PCIE_FTI2C010_3_PA_LIMIT	0xC3600FFF
++#define I2C_PCIE_FTI2C010_3_PA_SIZE	0x00001000
++
++/* SCAL */
++#define SCAL_FTSCAL300_PA_COUNT 1
++#define SCAL_FTSCAL300_PA_BASE  0x96200000
++#define SCAL_FTSCAL300_PA_LIMIT 0x96247FFF
++#define SCAL_FTSCAL300_PA_SIZE  0x00048000
++#define SCAL_FTSCAL300_0_PA_BASE    0x96200000
++#define SCAL_FTSCAL300_0_PA_LIMIT   0x96247FFF
++#define SCAL_FTSCAL300_0_PA_SIZE    0x00048000
++#define SCAL_FTSCAL300_1_PA_BASE    0x96300000
++#define SCAL_FTSCAL300_1_PA_LIMIT   0x96347FFF
++#define SCAL_FTSCAL300_1_PA_SIZE    0x00048000
++
++/* IOLINK */
++#define IOLINK_TX_PA_COUNT          3
++#define IOLINK_TX_0_PA_BASE         0x9BB00000
++#define IOLINK_TX_0_PA_SIZE         0x1000
++#define IOLINK_TX_1_PA_BASE         0x9BC00000
++#define IOLINK_TX_1_PA_SIZE         0x1000
++#define IOLINK_TX_2_PA_BASE         0x9BD00000
++#define IOLINK_TX_2_PA_SIZE         0x1000
++
++/* H2XBrg_7 */
++#define PCIE_H2XBRG_7_PA_BASE       0xC3000000
++#define PCI3_H2SBRG_7_PA_SIZE       0x1000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++#define PLATFORM_IRQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL1	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL1	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL3	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL3	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL4	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL4	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL5	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL5	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL6	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL6	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL7	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL7	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL8	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL8	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE9	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL9	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE9	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL9	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE10	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL10	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE10	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL10	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE11	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL11	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE11	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL11	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE12	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL12	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE12	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL12	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE13	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL13	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE13	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL13	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE14	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL14	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE14	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL14	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE15	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL15	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE15	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL15	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODEEX2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVELEX2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODEEX2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVELEX2	0xFFFFFFFF
++
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/pmu.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/pmu.h
+new file mode 100644
+index 00000000..1a9fb19d
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/pmu.h
+@@ -0,0 +1,33 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++#define GM8210_TEST_CHIP_ID 0x821010
++
++unsigned int pmu_get_apb_clk(void);
++unsigned int pmu_get_apb0_clk(void);
++unsigned int pmu_get_apb1_clk(void);
++unsigned int pmu_get_apb2_clk(void);
++int platform_check_flash_type(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/pmu_pcie.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/pmu_pcie.h
+new file mode 100644
+index 00000000..39f135eb
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/pmu_pcie.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/pmu_pcie.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_PCIE_H__
++#define __PMU_PCIE_H__
++
++#define GM8312_TEST_CHIP_ID 0x831200
++
++unsigned int pmu_pcie_get_apb_clk(void);
++unsigned int pmu_pcie_get_ahb_clk(void);
++unsigned int pmu_pcie_get_axi_clk(void);
++void pmu_pcie_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_PCIE_H__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/serial.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/serial.h
+new file mode 100644
+index 00000000..68b447a9
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/serial.h
+@@ -0,0 +1,80 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 6 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created.
++ */
++
++//#define UART_CLKSRC_OSCH//issue
++
++#ifdef UART_CLKSRC_OSCH
++#define CONFIG_UART_CLK			12288000//12000000
++#else
++#define CONFIG_UART_CLK			25000000//(30000000/16)
++#endif
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++
++#ifdef CONFIG_SERIAL_UART2_IP
++#define EXTENDED_UART_2 \
++     { 0, BASE_BAUD, UART_FTUART010_2_VA_BASE, UART_FTUART010_2_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS2 */
++#else
++#define EXTENDED_UART_2 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART3_IP
++#define EXTENDED_UART_3 \
++     { 0, BASE_BAUD, UART_FTUART010_3_VA_BASE, UART_FTUART010_3_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS3 */
++#else
++#define EXTENDED_UART_3 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART4_IP
++#define EXTENDED_UART_4 \
++     { 0, BASE_BAUD, UART_FTUART010_4_VA_BASE, UART_FTUART010_4_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS4 */
++#else
++#define EXTENDED_UART_4 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART5_IP
++#define EXTENDED_UART_5 \
++     { 0, BASE_BAUD, UART_FTUART010_5_VA_BASE, UART_FTUART010_5_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS5 */
++#else
++#define EXTENDED_UART_5 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1            \
++        EXTENDED_UART_2            \
++        EXTENDED_UART_3            \
++        EXTENDED_UART_4            \
++        EXTENDED_UART_5
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/system.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/system.h
+new file mode 100644
+index 00000000..ca2dee55
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/system.h
+@@ -0,0 +1,76 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/system.h
++ *
++ *  Faraday Platform Dependent System Definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++static inline void arch_reset(char mode, const char *cmd)
++{
++#define BIT13 (0x1<<13)
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++    pmuReg_t regRSTArray[] = {
++    	/* reg_off,bit_masks,lock_bits,init_val,init_mask */
++	{0xB8, BIT13, BIT13, 0, BIT13},
++    };
++    pmuRegInfo_t rst_clk_info = {
++    	"rst_clk",
++	ARRAY_SIZE(regRSTArray),
++	ATTR_TYPE_NONE,
++	regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<13)), (PMU_FTPMU010_VA_BASE + 0xB8));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C)); //reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));//load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08)); /*Magic number*/
++    writeb(0x03, (wdt_va_base + 0x0C)); /*Enable WDT */
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/vmalloc.h b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/vmalloc.h
+new file mode 100644
+index 00000000..b86c26fe
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/platform-GM8210/vmalloc.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/platform/vmalloc.h
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Justin Shih  10/06/2012  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM-Duo/include/mach/serial.h b/arch/arm/mach-GM-Duo/include/mach/serial.h
+new file mode 100644
+index 00000000..64608862
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/serial.h
+@@ -0,0 +1,64 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/serial.h
++ *  
++ *  Platform Independent UART Console Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * Note
++ *
++ *  The first UART (FTUART010) in the system is used as the console.
++ * 
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ */
++
++#ifndef __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__
++#define __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__
++
++#ifndef __ASSEMBLY__
++
++#include <mach/platform/board.h>
++#include <linux/serial.h>
++/* Include platform *dependent* UART console configuration */
++#include <mach/platform/serial.h>
++
++#ifndef STD_COM_FLAGS
++#define STD_COM_FLAGS  (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
++#endif
++
++#ifndef PLATFORM_MORE_SERIAL_PORTS
++#define PLATFORM_MORE_SERIAL_PORTS
++#endif
++
++#ifndef SERIAL_PORT_DFNS
++     /* UART CLK        PORT                 IRQ                 FLAGS          hub6 io_type iomem_base reg_shift*/
++#define SERIAL_PORT_DFNS	\
++     { 0, BASE_BAUD, UART_FTUART010_0_VA_BASE, UART_FTUART010_0_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS0 */ \
++     PLATFORM_MORE_SERIAL_PORTS
++#endif
++
++/*
++ * We use a 18.432MHz clock rather than typical 1.8432 MHz clock for UART.
++ */
++#define BASE_BAUD       (CONFIG_UART_CLK / 16)
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__ */
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/system.h b/arch/arm/mach-GM-Duo/include/mach/system.h
+new file mode 100644
+index 00000000..f4daf5f6
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/system.h
+@@ -0,0 +1,49 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/system.h
++ *  
++ *  Faraday Platform Independent System Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__
++
++/* Include platform *dependent* system definitions */
++#include <mach/platform/system.h>
++
++#include <asm/proc-fns.h>
++#ifndef arch_idle
++static inline void arch_idle(void)
++{
++	cpu_do_idle();
++}
++#endif
++
++#ifndef arch_reset
++extern inline void arch_reset(char mode, const char *cmd)
++{
++	/* NOP */
++}
++#endif
++
++#endif /* __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__ */
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/timex.h b/arch/arm/mach-GM-Duo/include/mach/timex.h
+new file mode 100644
+index 00000000..d3ff0c18
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/timex.h
+@@ -0,0 +1,33 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/timex.h
++ *  
++ *  Faraday Platform Independent Clock Tick Rate Definition
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ */
++
++#ifndef __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__
++#define __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__
++
++#define CLOCK_TICK_RATE	CONFIG_CLOCK_TICK_RATE
++
++#endif /* __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__ */
++
+diff --git a/arch/arm/mach-GM-Duo/include/mach/uncompress.h b/arch/arm/mach-GM-Duo/include/mach/uncompress.h
+new file mode 100644
+index 00000000..7df9d0fd
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/include/mach/uncompress.h
+@@ -0,0 +1,51 @@
++/*
++ *  arch/arm/mach-GM-Duo/include/mach/uncompress.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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 <mach/platform/board.h>
++
++#define SERIAL_THR	0x00
++#define SERIAL_LSR	0x14
++#define SERIAL_LSR_THRE	0x20
++
++#define readl(a)	(*(volatile unsigned int *)(a))
++#define writel(v,a)	(*(volatile unsigned int *)(a) = (v))
++
++/*
++ * This does not append a newline
++ */
++static inline void putc(int c)
++{
++	unsigned long base = DEBUG_LL_FTUART010_PA_BASE;
++
++	while ((readl(base + SERIAL_LSR) & SERIAL_LSR_THRE) == 0)
++		barrier();
++
++	writel(c, base + SERIAL_THR);
++}
++
++static inline void flush(void)
++{
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-M/Kconfig b/arch/arm/mach-GM-Duo/platform-GM8210-M/Kconfig
+new file mode 100644
+index 00000000..5a874b8e
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-M/Kconfig
+@@ -0,0 +1,53 @@
++#
++# arch/arm/mach-GM/platform-GM8210/Kconfig
++
++if PLATFORM_GM8210_M
++
++#config SYS_CLK
++config CLOCK_TICK_RATE
++        int "AHB System Clock"
++        default 33000000
++        help
++            Any fake value is ok. It almost obsolete.
++
++config GM8210_M_HZ
++    int "HZ of GM8210_M (FA726)"
++    range 100 1000
++    default 100
++    help
++      HZ defined in GM8210_M platform
++
++config PLATFORM_AXIDMA
++	bool "AXI DMA support"
++	default y
++
++config FTINTC030
++	bool "FTINTC030 support"
++	default y
++
++config FTINTC010EX
++	bool "FTINTC010EX supports 64 IRQs"
++	default y
++
++config FA626
++    bool "FA626 support"
++    default y
++
++config GM8312
++	bool "GM8312 support"
++	default y
++
++config GM8210_FPGA
++	bool "FPGA Verify"
++	default n
++    
++config GM8210_EP_MODE
++    bool "Dual GM8210 EP mode"
++    default n
++
++config FC7500
++    bool "FC7500 support"
++    depends on GM8210_EP_MODE
++    default y
++        
++endif
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-M/Makefile b/arch/arm/mach-GM-Duo/platform-GM8210-M/Makefile
+new file mode 100644
+index 00000000..5a158282
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-M/Makefile
+@@ -0,0 +1,11 @@
++#
++# Makefile for the GM platform dependent files
++
++# Object file lists.
++
++ifeq ($(CONFIG_GM8210_FPGA),y)
++obj-y		:= board.o pmu_fpga.o timer_fixup.o platform.o
++else
++obj-y		:= board.o pmu.o timer_fixup.o platform.o
++obj-$(CONFIG_GM8312)   += pmu_pcie.o 
++endif
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-M/board.c b/arch/arm/mach-GM-Duo/platform-GM8210-M/board.c
+new file mode 100644
+index 00000000..2ee603f5
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-M/board.c
+@@ -0,0 +1,500 @@
++/*
++ *  board depdenent initialization
++ *
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/setup.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/platform/board.h>
++#include <mach/platform/pmu.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/system.h>
++#ifdef CONFIG_GM8312
++#include <mach/ftintc010.h>
++#include <mach/platform/pmu_pcie.h>
++#endif
++#include <mach/ftintc030.h>
++#include <mach/fttmr010.h>
++#ifdef CONFIG_FTDMAC030
++#include <mach/ftdmac030.h>
++#endif
++
++#include <mach/fmem.h>
++#include <linux/dma-mapping.h>
++
++/* External functions and variables declaration
++ */
++extern void platform_devices_init(void);
++
++/* Local variables declaration
++ */
++void __iomem *ftintc030_base_addr;
++void __iomem *ftintc030_base_cpu_0_irq_base; //entry-macro.S will reference it
++
++#ifdef CONFIG_GM8312
++void __iomem *ftintc010_base_addr;
++#endif
++
++#ifdef CONFIG_FTDMAC030
++/*
++ * DMAC030 channel filter.
++ */
++static int board_dmac030_chan_filter(int chan_id)
++{
++    /* Master CPU only can use 0-3 */
++    if (chan_id >= 4)
++        return -1;
++
++    return 0;
++}
++#endif /* CONFIG_FTDMAC030 */
++
++/******************************************************************************
++ * IPs virtual address mapping
++ *****************************************************************************/
++static struct map_desc board_io_desc[] __initdata = {
++    /* PMU */
++    {
++        .virtual	= PMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PMU_FTPMU010_PA_BASE),
++		.length		= PMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART0 */
++    {
++        .virtual	= UART_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_0_PA_BASE),
++		.length		= UART_FTUART010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART2 */
++    {
++        .virtual	= UART_FTUART010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_2_PA_BASE),
++		.length		= UART_FTUART010_2_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART3 */
++    {
++        .virtual	= UART_FTUART010_3_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_3_PA_BASE),
++		.length		= UART_FTUART010_3_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART4 */
++    {
++        .virtual	= UART_FTUART010_4_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_4_PA_BASE),
++		.length		= UART_FTUART010_4_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART5 */
++    {
++        .virtual	= UART_FTUART010_5_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_5_PA_BASE),
++		.length		= UART_FTUART010_5_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* TIMER */
++    {
++        .virtual	= TIMER_FTTMR010_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_PA_BASE),
++		.length		= TIMER_FTTMR010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC030 */
++    {
++        .virtual	= INTC_FTINTC030_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC030_PA_BASE),
++		.length		= INTC_FTINTC030_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#ifdef CONFIG_GM8312
++    /* PCI_PMU */
++    {
++        .virtual	= PCIPMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PCIPMU_FTPMU010_PA_BASE),
++		.length		= PCIPMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC010 */
++    {
++        .virtual	= INTC_FTINTC010_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC010_PA_BASE),
++		.length		= INTC_FTINTC010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#endif
++};
++
++/* fixup the memory for MACHINE_START. The parameters come from commandline of menuconfig
++ */
++static void __init board_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    fmem_fixup_memory(tag, cmdline, mi);
++}
++
++/* 2. create the iotable for IPs in MACHINE_START
++ */
++static void __init board_map_io(void)
++{
++    iotable_init(&board_io_desc[0], ARRAY_SIZE(board_io_desc));
++
++    /* set the base to pmu module */
++    pmu_earlyinit((void *)PMU_FTPMU010_VA_BASE);
++#ifdef CONFIG_GM8312
++    pmu_pcie_earlyinit((void *)PCIPMU_FTPMU010_VA_BASE);
++#endif
++    /* init dma coherent mapping size,
++     * CONSISTENT_DMA_SIZE is defined in memory.h
++     * max allowable dma consistent size is 14M (0xFFE0_0000 - 0xFF00_00000)
++     * set as 12M to avoid unexpected data overlay, NISH_20121015
++     */
++    #ifdef CONSISTENT_DMA_SIZE
++    init_consistent_dma_size(CONSISTENT_DMA_SIZE);
++    #endif
++}
++
++#ifdef CONFIG_GM8312
++/* HDCP of HDMI is useless, so we use the last 16 bytes as the memory destination
++ * format: [0]init_done value, [4]who owned the key, [8]lock/unlock value, [c]: how long
++ */
++typedef struct {
++    unsigned int init_done;
++    unsigned int lock;
++    unsigned int owner;
++    unsigned int wait_cnt;
++    unsigned int lock_cnt;
++    unsigned int statistic;   /* statistic only */
++    unsigned int last_freer;
++    unsigned int reserved[1];
++} lock_content_t;
++
++#define LOCK_VAL        0xAAAA0000
++#define UNLOCK_VAL      0x00005555
++#define INIT_DONE       0x00112233
++#define LOCK_OWNER      0x000FA726
++
++static unsigned int hdmi_va;
++
++static void board_bus_lock_vainit(void)
++{
++    hdmi_va = (unsigned int)ioremap_nocache(HDMI_FTHDCPMEM_PA_BASE, 512);
++    if (!hdmi_va)
++        panic("Error to allocate va! \n");
++
++    /* memory clear was done in uboot */
++}
++
++void board_bus_lock_init(bus_lock_t bus)
++{
++    volatile int i;
++    volatile u32 base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE) {
++        memset((char *)content, 0, sizeof(lock_content_t));
++        content->lock = UNLOCK_VAL;
++        content->init_done = INIT_DONE;
++    }
++
++    //delay a while prevent from multiple CPUs re-entrant
++    for (i = 0; i < 0x100; i ++)
++        ioread32(hdmi_va);
++}
++EXPORT_SYMBOL(board_bus_lock_init);
++
++void board_bus_lock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setlock = LOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner == LOCK_OWNER) {
++        content->lock_cnt ++;
++        content->statistic ++;
++        return;
++    }
++
++    ptr = base + 4;
++re_try:
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setlock), "r" (ptr)
++                : "memory", "cc");
++    if (retval != UNLOCK_VAL) {
++        if (irqs_disabled() || in_interrupt())
++	    udelay(100);
++	else
++	    msleep(1);
++        content->wait_cnt ++;
++        goto re_try;
++    }
++
++    content->owner = LOCK_OWNER;
++    content->lock_cnt ++;
++    content->statistic ++;
++    content->wait_cnt = 0;
++    content->last_freer = 0;
++}
++EXPORT_SYMBOL(board_bus_lock);
++
++void board_bus_unlock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setunlock = UNLOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner != LOCK_OWNER)
++        panic("the locker:%d has wrong owner:0x%x! \n", bus, content->owner);
++
++    content->lock_cnt --;
++    if (content->lock_cnt)
++        return;
++
++    content->owner = 0;   //no owner
++    content->last_freer = LOCK_OWNER;
++
++    ptr = base + 4;
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setunlock), "r" (ptr)
++                : "memory", "cc");
++
++    if (retval != LOCK_VAL) {
++        int i;
++
++        for (;;) {
++            printk("Error value 0x%x in locker:%d! \n", retval, bus);
++            msleep(990);
++
++            for (i = 0; i < 8; i ++)
++                printk("content[%d] = 0x%x \n", i, ioread32(base + i * 4));
++        }
++    }
++}
++EXPORT_SYMBOL(board_bus_unlock);
++
++/* return value:
++ *  -1 for fail which means the bus was locked by others
++ *  0 for grab the lock success
++ */
++int board_bus_trylock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setlock = LOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner == LOCK_OWNER) {
++        content->lock_cnt ++;
++        content->statistic ++;
++        return 0;
++    }
++
++    ptr = base + 4;
++
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setlock), "r" (ptr)
++                : "memory", "cc");
++    if (retval != UNLOCK_VAL)
++        return -1;
++
++    content->owner = LOCK_OWNER;
++    content->lock_cnt ++;
++    content->statistic ++;
++    content->wait_cnt = 0;
++    content->last_freer = 0;
++
++    return 0;
++}
++EXPORT_SYMBOL(board_bus_trylock);
++#endif /* CONFIG_GM8312 */
++
++static void __init board_init_irq(void)
++{
++	struct ftintc030_trigger_type master_trigger_type = {
++		.irqmode[0]	= PLATFORM_IRQ_TRIGGER_MODE1,
++		.irqlevel[0]	= ~PLATFORM_IRQ_TRIGGER_LEVEL1,
++		.fiqmode[0]	= PLATFORM_FIQ_TRIGGER_MODE1,
++		.fiqlevel[0]	= ~PLATFORM_FIQ_TRIGGER_LEVEL1,
++
++		.irqmode[1]	= PLATFORM_IRQ_TRIGGER_MODE2,
++		.irqlevel[1]	= ~PLATFORM_IRQ_TRIGGER_LEVEL2 | (1 << (EXT_INT_0_IRQ - 32)),
++		.fiqmode[1]	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel[1]	= ~PLATFORM_FIQ_TRIGGER_LEVEL2 | (1 << (EXT_INT_0_IRQ - 32)),
++
++		.irqmode[2]	= PLATFORM_IRQ_TRIGGER_MODE3,
++		.irqlevel[2]	= ~PLATFORM_IRQ_TRIGGER_LEVEL3,
++		.fiqmode[2]	= PLATFORM_FIQ_TRIGGER_MODE3,
++		.fiqlevel[2]	= ~PLATFORM_FIQ_TRIGGER_LEVEL3,
++
++		.irqmode[3]	= PLATFORM_IRQ_TRIGGER_MODE4,
++		.irqlevel[3]	= ~PLATFORM_IRQ_TRIGGER_LEVEL4,
++		.fiqmode[3]	= PLATFORM_FIQ_TRIGGER_MODE4,
++		.fiqlevel[3]	= ~PLATFORM_FIQ_TRIGGER_LEVEL4,
++
++		.irqmode[4]	= PLATFORM_IRQ_TRIGGER_MODE5,
++		.irqlevel[4]	= ~PLATFORM_IRQ_TRIGGER_LEVEL5,
++		.fiqmode[4]	= PLATFORM_FIQ_TRIGGER_MODE5,
++		.fiqlevel[4]	= ~PLATFORM_FIQ_TRIGGER_LEVEL5,
++
++		.irqmode[5]	= PLATFORM_IRQ_TRIGGER_MODE6,
++		.irqlevel[5]	= ~PLATFORM_IRQ_TRIGGER_LEVEL6,
++		.fiqmode[5]	= PLATFORM_FIQ_TRIGGER_MODE6,
++		.fiqlevel[5]	= ~PLATFORM_FIQ_TRIGGER_LEVEL6,
++
++		.irqmode[6]	= PLATFORM_IRQ_TRIGGER_MODE7,
++		.irqlevel[6]	= ~PLATFORM_IRQ_TRIGGER_LEVEL7,
++		.fiqmode[6]	= PLATFORM_FIQ_TRIGGER_MODE7,
++		.fiqlevel[6]	= ~PLATFORM_FIQ_TRIGGER_LEVEL7,
++
++		.irqmode[7]	= PLATFORM_IRQ_TRIGGER_MODE8,
++		.irqlevel[7]	= ~PLATFORM_IRQ_TRIGGER_LEVEL8,
++		.fiqmode[7]	= PLATFORM_FIQ_TRIGGER_MODE8,
++		.fiqlevel[7]	= ~PLATFORM_FIQ_TRIGGER_LEVEL8,
++	};
++
++#ifdef CONFIG_GM8312
++	struct ftintc010_trigger_type pcie_trigger_type = {
++		.irqmode	= PLATFORM_IRQ_TRIGGER_MODE2 | (0x1 << 8), /* hdmi edge trigger */
++		.irqlevel	= ~PLATFORM_IRQ_TRIGGER_LEVEL2,
++		.fiqmode	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel	= ~PLATFORM_FIQ_TRIGGER_LEVEL2,
++#ifdef CONFIG_FTINTC010EX
++        	.irqmodeex	= PLATFORM_IRQ_TRIGGER_MODEEX2,
++		.irqlevelex	= ~PLATFORM_IRQ_TRIGGER_LEVELEX2,
++		.fiqmodeex	= PLATFORM_FIQ_TRIGGER_MODEEX2,
++		.fiqlevelex	= ~PLATFORM_FIQ_TRIGGER_LEVELEX2,
++#endif
++	};
++#endif
++	/*
++	 * initialize primary interrupt controller
++	 */
++	ftintc030_base_addr = __io(INTC_FTINTC030_VA_BASE);
++	ftintc030_base_cpu_0_irq_base = __io(INTC_FTINTC030_VA_BASE + FTINTC030_OFFSET_CPU_0_IRQ);
++
++	ftintc030_init(0, ftintc030_base_addr, 0, &master_trigger_type);
++
++#ifdef CONFIG_GM8312
++    board_bus_lock_vainit();
++
++	ftintc010_base_addr = __io(INTC_FTINTC010_VA_BASE);
++	ftintc010_init(0, ftintc010_base_addr, PLATFORM_IRQ_TOTALCOUNT, &pcie_trigger_type);
++	if (1) {
++	    /* Enable prefetch for H2XBrg_7 for DMAC.
++	     * Limitation: If read through AXI-PCIe controller IP�Aread data width < 64 bit,
++	     * burst length only can be "1". Thus we enable pre-fetech function to solve this issue.
++	     */
++	    void *vbase;
++	    u32 tmp;
++
++	    vbase = (void *)ioremap_nocache(PCIE_H2XBRG_7_PA_BASE, PCI3_H2SBRG_7_PA_SIZE);
++	    tmp = ioread32(vbase) & ~(0x7 << 4);    // bit [6:4] (prefetch number)
++	    tmp |= ((0xA << 16) | (0x2 << 4));  //suggest from Kay, 2013/3/27 10:57AM
++	    iowrite32(tmp, vbase);
++        __iounmap(vbase);
++	}
++#endif
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 1,
++};
++
++static void __init board_sys_timer_init(void)
++{
++    unsigned int pclk = pmu_get_apb0_clk();
++	printk("Timer use APB0 clock\n");
++
++	fttmr010_0_clockevent.freq = pclk;
++	fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++	fttmr010_1_clocksource.freq = pclk;
++	fttmr010_clocksource_init(&fttmr010_1_clocksource);
++}
++
++struct sys_timer board_sys_timer = {
++	.init	= board_sys_timer_init,
++};
++
++/* board init */
++static void __init board_init_machine(void)
++{
++    int i;
++
++    platform_devices_init();
++
++    /* dump iotable information
++     */
++    for (i = 0; i < ARRAY_SIZE(board_io_desc); i ++) {
++        printk("iotable: VA: 0x%x, PA: 0x%x, Length: %d \n",
++                (u32)board_io_desc[i].virtual,
++                (u32)board_io_desc[i].pfn << PAGE_SHIFT,
++                (u32)board_io_desc[i].length);
++    }
++
++#ifdef CONFIG_FTDMAC030
++    ftdmac030_set_platform_chanfilter(board_dmac030_chan_filter);
++#endif
++}
++
++MACHINE_START(GM, BOARD_NAME)
++	.atag_offset	= BOOT_PARAMETER_PA_OFFSET,   //boot command line, after kernel 3.2 change as relative address
++	.map_io		    = board_map_io,
++	.init_irq	    = board_init_irq,
++	.timer		    = &board_sys_timer,
++	.fixup          = board_fixup_memory,
++	.init_machine	= board_init_machine,
++	.restart	= arch_reset,
++MACHINE_END
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-M/platform.c b/arch/arm/mach-GM-Duo/platform-GM8210-M/platform.c
+new file mode 100644
+index 00000000..910b1f81
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-M/platform.c
+@@ -0,0 +1,620 @@
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/dma-mapping.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach-types.h>
++#include <mach/platform/board.h>
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++#if defined(CONFIG_I2C0_IP) || defined(CONFIG_GM8210_FPGA)
++/* i2c:0 */
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start  = I2C_FTI2C010_0_PA_BASE,
++		.end    = I2C_FTI2C010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_0_IRQ,
++		.end	= I2C_FTI2C010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		    = 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C1_IP
++/* i2c:1 */
++static struct resource ftiic010_1_resources[] = {
++	{
++		.start  = I2C_FTI2C010_1_PA_BASE,
++		.end    = I2C_FTI2C010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_1_IRQ,
++		.end	= I2C_FTI2C010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_1_device = {
++	.name		= "ftiic010",
++	.id		    = 1,
++	.num_resources	= ARRAY_SIZE(ftiic010_1_resources),
++	.resource	= ftiic010_1_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C2_IP
++/* i2c:2 */
++static struct resource ftiic010_2_resources[] = {
++	{
++		.start  = I2C_FTI2C010_2_PA_BASE,
++		.end    = I2C_FTI2C010_2_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_2_IRQ,
++		.end	= I2C_FTI2C010_2_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_2_device = {
++	.name		= "ftiic010",
++	.id		    = 2,
++	.num_resources	= ARRAY_SIZE(ftiic010_2_resources),
++	.resource	= ftiic010_2_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C3_IP
++/* i2c:3 */
++static struct resource ftiic010_3_resources[] = {
++	{
++		.start  = I2C_FTI2C010_3_PA_BASE,
++		.end    = I2C_FTI2C010_3_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_3_IRQ,
++		.end	= I2C_FTI2C010_3_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_3_device = {
++	.name		= "ftiic010",
++	.id		    = 3,
++	.num_resources	= ARRAY_SIZE(ftiic010_3_resources),
++	.resource	= ftiic010_2_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C4_IP
++/* i2c:4 */
++static struct resource ftiic010_4_resources[] = {
++	{
++		.start  = I2C_FTI2C010_4_PA_BASE,
++		.end    = I2C_FTI2C010_4_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_4_IRQ,
++		.end	= I2C_FTI2C010_4_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_4_device = {
++	.name		= "ftiic010",
++	.id		    = 4,
++	.num_resources	= ARRAY_SIZE(ftiic010_4_resources),
++	.resource	= ftiic010_4_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C5_IP
++/* i2c:5 */
++static struct resource ftiic010_5_resources[] = {
++	{
++		.start  = I2C_FTI2C010_5_PA_BASE,
++		.end    = I2C_FTI2C010_5_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_5_IRQ,
++		.end	= I2C_FTI2C010_5_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_5_device = {
++	.name		= "ftiic010",
++	.id		    = 4,
++	.num_resources	= ARRAY_SIZE(ftiic010_5_resources),
++	.resource	= ftiic010_5_resources,
++};
++#endif
++
++/******************************************************************************
++ * USB hosts
++ *****************************************************************************/
++#ifdef CONFIG_GM_FOTG2XX
++/* OTG:0 */
++static struct resource fotg210_0_resources[] = {
++	{
++		.start  = USB_FOTG2XX_0_PA_BASE,
++		.end    = USB_FOTG2XX_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_0_IRQ,
++		.end    = USB_FOTG2XX_0_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_0_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_0_device = {
++	.name           = "fotg210",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(fotg210_0_resources),
++	.resource       = fotg210_0_resources,
++	.dev = {
++		.dma_mask = &fotg210_0_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++/* OTG:1 */
++struct resource fotg210_1_resources[] = {
++	{
++		.start  = USB_FOTG2XX_1_PA_BASE,
++		.end    = USB_FOTG2XX_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_1_IRQ,
++		.end    = USB_FOTG2XX_1_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_1_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_1_device = {
++	.name           = "fotg210",
++	.id             = 1,
++	.num_resources  = ARRAY_SIZE(fotg210_1_resources),
++	.resource       = fotg210_1_resources,
++	.dev = {
++		.dma_mask = &fotg210_1_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++/* OTG:2 */
++static struct resource fotg210_2_resources[] = {
++	{
++		.start  = USB_FOTG2XX_2_PA_BASE,
++		.end    = USB_FOTG2XX_2_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_2_IRQ,
++		.end    = USB_FOTG2XX_2_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_2_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_2_device = {
++	.name           = "fotg210",
++//    .name           = "usb1.1",
++	.id             = 2,
++	.num_resources  = ARRAY_SIZE(fotg210_2_resources),
++	.resource       = fotg210_2_resources,
++	.dev = {
++		.dma_mask = &fotg210_2_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif
++
++/* FTSDC021 */
++static struct resource ftsdc021_resource[] = {
++	[0] = {
++	       .start = SDC_FTSDC021_PA_BASE,
++	       .end = SDC_FTSDC021_PA_LIMIT,
++	       .flags = IORESOURCE_MEM,
++	       },
++	[1] = {
++	       .start = SDC_FTSDC021_0_IRQ,
++	       .end = SDC_FTSDC021_0_IRQ,
++	       .flags = IORESOURCE_IRQ,
++	       }
++};
++static u64 ftsdc021_dmamask = 0xFFFFFFUL;
++static struct platform_device ftsdc021_device = {
++	.name = "ftsdc021",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(ftsdc021_resource),
++	.resource = ftsdc021_resource,
++	.dev = {
++		.dma_mask = &ftsdc021_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/******************************************************************************
++ * GPIO devices
++ *****************************************************************************/
++#if defined(CONFIG_GPIO_FTGPIO010)
++/* GPIO 0 */
++static struct resource ftgpio010_0_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_0_PA_BASE,
++		.end 	= GPIO_FTGPIO010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_0_IRQ,
++		.end	= GPIO_FTGPIO010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_0_device = {
++	.name	= "ftgpio010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgpio010_0_resource),
++	.resource	= ftgpio010_0_resource
++};
++
++/* GPIO 1 */
++static struct resource ftgpio010_1_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_1_PA_BASE,
++		.end 	= GPIO_FTGPIO010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_1_IRQ,
++		.end	= GPIO_FTGPIO010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_1_device = {
++	.name	= "ftgpio010",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgpio010_1_resource),
++	.resource	= ftgpio010_1_resource
++};
++#endif
++
++/******************************************************************************
++ * SATA devices
++ *****************************************************************************/
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++/* SATA0 */
++static struct resource ftsata100_0_resource[] = {
++    {
++        .start = SATA_FTSATA100_0_PA_BASE,
++        .end   = SATA_FTSATA100_0_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_0_IRQ,
++        .end   = SATA_FTSATA100_0_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_0_dmamask = ~(u32)0;
++static struct platform_device ftsata100_0_device = {
++	.name           = "ftsata100",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(ftsata100_0_resource),
++	.resource       = ftsata100_0_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_0_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/* SATA1 */
++static struct resource ftsata100_1_resource[] = {
++    {
++        .start = SATA_FTSATA100_1_PA_BASE,
++        .end   = SATA_FTSATA100_1_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_1_IRQ,
++        .end   = SATA_FTSATA100_1_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_1_dmamask = ~(u32)0;
++static struct platform_device ftsata100_1_device = {
++	.name           = "ftsata100",
++	.id             = 1,
++	.num_resources  = ARRAY_SIZE(ftsata100_1_resource),
++	.resource       = ftsata100_1_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_1_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/* SATA2 */
++static struct resource ftsata100_2_resource[] = {
++    {
++        .start = SATA_FTSATA100_2_PA_BASE,
++        .end   = SATA_FTSATA100_2_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_2_IRQ,
++        .end   = SATA_FTSATA100_2_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_2_dmamask = ~(u32)0;
++static struct platform_device ftsata100_2_device = {
++	.name           = "ftsata100",
++	.id             = 2,
++	.num_resources  = ARRAY_SIZE(ftsata100_2_resource),
++	.resource       = ftsata100_2_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_2_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/* SATA3 */
++static struct resource ftsata100_3_resource[] = {
++    {
++        .start = SATA_FTSATA100_3_PA_BASE,
++        .end   = SATA_FTSATA100_3_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_3_IRQ,
++        .end   = SATA_FTSATA100_3_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_3_dmamask = ~(u32)0;
++static struct platform_device ftsata100_3_device = {
++	.name           = "ftsata100",
++	.id             = 3,
++	.num_resources  = ARRAY_SIZE(ftsata100_3_resource),
++	.resource       = ftsata100_3_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_3_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif // #ifdef CONFIG_SATA_AHCI_PLATFORM
++
++/******************************************************************************
++ * AHB DMA controllers
++ *****************************************************************************/
++#ifdef CONFIG_FTDMAC020
++static struct resource ftdmac020_0_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_0_PA_BASE,
++		.end	= DMAC_FTDMAC020_0_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_0_IRQ,
++		.end    = DMAC_FTDMAC020_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_0_device = {
++	.name		= "ftdmac020",
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_0_resources),
++	.resource	= ftdmac020_0_resources,
++};
++
++#ifdef CONFIG_GM8312
++static struct resource ftdmac020_1_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_1_PA_BASE,
++		.end	= DMAC_FTDMAC020_1_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_1_IRQ,
++		.end    = DMAC_FTDMAC020_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_1_device = {
++	.name		= "ftdmac020",
++	.id		    = 1,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_1_resources),
++	.resource	= ftdmac020_1_resources,
++};
++#endif /* CONFIG_GM8312 */
++#endif /* CONFIG_FTDMAC020 */
++
++#ifdef CONFIG_FTDMAC030
++static struct resource ftdmac030_resources[] = {
++	{
++		.start	= XDMAC_FTDMAC030_PA_BASE,
++		.end	= XDMAC_FTDMAC030_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= XDMAC_FTDMAC030_IRQ,
++		.end    = XDMAC_FTDMAC030_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++#define DRV_NAME	"ftdmac030"
++static struct platform_device ftdmac030_device = {
++	.name		= DRV_NAME,
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac030_resources),
++	.resource	= ftdmac030_resources,
++};
++#endif /* CONFIG_FTDMAC030 */
++
++/******************************************************************************
++ * SPI020 controllers
++ *****************************************************************************/
++#ifdef CONFIG_SPI_FTSPI020
++static struct resource ftspi020_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,     /* Register Base address */
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static u64 ftspi020_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftspi020_device = {
++    .name = "ftspi020",
++    .id = 0,//must match with bus_num
++    .num_resources = ARRAY_SIZE(ftspi020_resource),
++    .resource = ftspi020_resource,
++    .dev = {
++            .dma_mask = &ftspi020_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            },
++};
++#endif /* CONFIG_SPI_FTSPI020 */
++
++void memory_repair_dis(void)
++{
++	u32 reg = 0, timeout = 0x10000;
++
++	/* enable memory_repair_dis */
++	reg = ioread32(PMU_FTPMU010_VA_BASE + 0xa4);
++	reg = reg & ~(1 << 29);
++	iowrite32(reg, (PMU_FTPMU010_VA_BASE + 0xa4));
++
++	// pull-low rst_l
++	reg = ioread32(PMU_FTPMU010_VA_BASE + 0xa4);
++	reg = reg & ~(1 << 30);
++	iowrite32(reg, (PMU_FTPMU010_VA_BASE + 0xa4));
++
++	// pull-high rst_l
++	reg = ioread32(PMU_FTPMU010_VA_BASE + 0xa4);
++	reg = reg | (1 << 30);
++	iowrite32(reg, (PMU_FTPMU010_VA_BASE + 0xa4));
++
++	// set fen=1
++	reg = ioread32(PMU_FTPMU010_VA_BASE+0xa4);
++	reg = reg | (1 << 28);
++	iowrite32(reg, (PMU_FTPMU010_VA_BASE + 0xa4));
++
++	// wait fuse_ready
++	while(timeout --){
++		if(ioread32(PMU_FTPMU010_VA_BASE + 0x80) & 0x20000)
++			break;
++	}
++	if(timeout)
++	    printk("memory_repair_dis fail, if EVB is FPGA, don't care\n");
++}
++
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/
++static struct platform_device *gm_devices[] __initdata =
++{
++	/* I2C */
++#if defined(CONFIG_I2C0_IP) || defined(CONFIG_GM8210_FPGA)
++	&ftiic010_0_device,
++#endif
++#ifdef CONFIG_I2C1_IP
++	&ftiic010_1_device,
++#endif
++#ifdef CONFIG_I2C2_IP
++	&ftiic010_2_device,
++#endif
++#ifdef CONFIG_I2C3_IP
++	&ftiic010_3_device,
++#endif
++#ifdef CONFIG_I2C4_IP
++	&ftiic010_4_device,
++#endif
++#ifdef CONFIG_I2C5_IP
++    &ftiic010_5_device,
++#endif
++#ifdef CONFIG_GM_FOTG2XX
++	/* OTG */
++	&fotg210_0_device,
++	&fotg210_1_device,
++	&fotg210_2_device,
++#endif
++	&ftsdc021_device,
++#if defined(CONFIG_GPIO_FTGPIO010)
++    &ftgpio010_0_device,
++    &ftgpio010_1_device,
++#endif
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++	&ftsata100_0_device,
++	&ftsata100_1_device,
++	&ftsata100_2_device,
++	&ftsata100_3_device,
++#endif
++#ifdef CONFIG_FTDMAC020
++    &ftdmac020_0_device,
++#ifdef CONFIG_GM8312
++    &ftdmac020_1_device,
++#endif
++#endif /* CONFIG_FTDMAC020 */
++#ifdef CONFIG_SPI_FTSPI020
++    &ftspi020_device,
++#endif
++#ifdef CONFIG_FTDMAC030
++    &ftdmac030_device,
++#endif
++};
++
++void __init platform_devices_init(void)
++{
++    /* add platform devices here
++     */
++
++    /* will invoke platform_device_register() to register all platform devices
++     */
++	platform_add_devices(gm_devices, ARRAY_SIZE(gm_devices));
++	//memory_repair_dis();
++}
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu.c b/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu.c
+new file mode 100644
+index 00000000..f9c27c4b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu.c
+@@ -0,0 +1,492 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++static int gpio_fd = -1;
++static int dmac_fd = -1;
++static int cpuintr_fd = -1;
++#ifdef CONFIG_PLATFORM_AXIDMA
++static int xdmac_fd = -1;
++#endif
++static int mcp100_gate_fd = -1;
++
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++
++#ifdef CONFIG_I2C0_IP
++    {0xB8, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // Disable i2c0 gating clock off
++    {0x44, (0x1 << 12), (0x1 << 12), (0x1 << 12), (0x1 << 12)}, // Enable i2c0 schmitt trigger
++#endif
++#ifdef CONFIG_I2C1_IP
++	{0xBC, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)}, // Enable i2c1 gating clock off
++    {0x44, (0x1 << 16), (0x1 << 16), (0x1 << 16), (0x1 << 16)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 22), (0x3 << 22), (0x0 << 22), (0x3 << 22)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C2_IP
++	{0xBC, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)}, // i2c1 gating clock off
++    {0x44, (0x1 << 17), (0x1 << 17), (0x1 << 17), (0x1 << 17)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 24), (0x3 << 24), (0x0 << 24), (0x3 << 24)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C3_IP
++	{0xBC, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // i2c1 gating clock off
++    {0x44, (0x1 << 18), (0x1 << 18), (0x1 << 18), (0x1 << 18)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 26), (0x3 << 26), (0x0 << 26), (0x3 << 26)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C4_IP
++	{0xBC, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, // i2c1 gating clock off
++    {0x44, (0x1 << 19), (0x1 << 19), (0x1 << 19), (0x1 << 19)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 28), (0x3 << 28), (0x0 << 28), (0x3 << 28)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C5_IP
++    {0xBC, (0x1 << 10), (0x1 << 10), (0x0 << 10), (0x1 << 10)}, // i2c1 gating clock off
++    {0x44, (0x1 << 20), (0x1 << 19), (0x1 << 20), (0x1 << 20)}, // i2c1 schmitt trigger
++    {0x4C, (0x3 <<  6), (0x3 <<  6), (0x0 <<  6), (0x3 <<  6)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* GPIO
++ */
++static pmuReg_t regGPIOArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x3C, (0x7 << 9), (0x7 << 9), (0x0 << 9), (0x7 << 9)},
++};
++
++static pmuRegInfo_t gpio_clk_info = {
++    "gpio_clk",
++    ARRAY_SIZE(regGPIOArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regGPIOArray
++};
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++/* CPU INTR
++ */
++static pmuReg_t regCPUINTArray[] = {
++ /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++    {0xA8,   0xFFFFFFFF, 0xFFFFFFFF,   0x0,        0x0},
++};
++
++static pmuRegInfo_t cpu_intr_info = {
++    "CPU_INTR",
++    ARRAY_SIZE(regCPUINTArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regCPUINTArray
++};
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++/* AXI DMAC
++ */
++static pmuReg_t regXDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB0, (0x1 << 19), (0x1 << 19), (0x0 << 19), (0x1 << 19)},
++};
++static pmuRegInfo_t xdmac_clk_info = {
++    "AXI_DMAC_CLK",
++    ARRAY_SIZE(regXDMACArray),
++    ATTR_TYPE_AXI,
++    regXDMACArray
++};
++#endif
++
++/* MCP100 gating clock. CPU COMM uses its SRAM to do communication.
++ */
++static pmuReg_t regMCPclkArray[] = {
++ /* reg_off  bit_masks    lock_bits  init_val     init_mask */
++    {0xB4,   (0x1 << 12), 0,         (0x0 << 12), (0x1 << 12)},
++};
++
++static pmuRegInfo_t mcp100_clk_info = {
++    "mcp100_gate",
++    ARRAY_SIZE(regMCPclkArray),
++    ATTR_TYPE_NONE,
++    regMCPclkArray
++};
++
++/* 0 for system running NAND, -1 for spi, 1 for SMC */
++int platform_check_flash_type(void)
++{
++	static unsigned int data = 0;
++	int ret = 0;
++
++	data = ioread32(pmu_base_addr + 0x4);
++
++    if (data & BIT22) {
++        if (data & BIT23)
++            ret = -1;
++        else
++            ret = 0;
++    } else {
++        ret = 1;
++    }
++
++	return ret;
++}
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	pmuver_t pmuver;
++	unsigned int product;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 *     821011: B version
++	 */
++	if (!version) {
++        product = (ioread32(pmu_base_addr) >> 16) & 0xFFFF;
++	    version = (ioread32(pmu_base_addr) >> 8) & 0xFF;
++
++	    printk("IC: GM%x, version: 0x%x \n", product, version);
++	}
++
++    switch (version) {
++      case 0x10:
++        pmuver = PMUVER_A;
++        break;
++      case 0x11:
++        pmuver = PMUVER_B;
++        break;
++      case 0x12:
++        pmuver = PMUVER_C;
++        break;
++      default:
++        pmuver = PMUVER_UNKNOWN;
++        break;
++    }
++
++	return (unsigned int)pmuver;
++}
++
++//format: xxxx_yyyy. xxxx: 8210, yyyy:IC revision
++unsigned int pmu_get_chipversion(void)
++{
++    unsigned int value = (0x8210 << 16);
++
++    value |= pmu_get_version();
++
++    return value;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return (ioread32(pmu_base_addr + 0x30) >> 16);
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 3) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static unsigned int pmu_read_pll4out(void)
++{
++	u32 value;
++
++    value = (ioread32(pmu_base_addr + 0x38) >> 4 ) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static unsigned int pmu_read_pll3out(void)
++{
++    u32 mul, value = 0;
++
++    if (ioread32(pmu_base_addr + 0x28) & (1 << 15)) {   /* no pll3 */
++        printk("PLL3 not support this mode\n");
++    } else {
++  	    mul = (ioread32(pmu_base_addr + 0x34) >> 4) & 0x7F;
++  	    value = (SYS_CLK * mul) / 2;
++    }
++
++    return value;
++}
++
++static unsigned int pmu_read_pll5out(void)
++{
++    return 100000000;
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 17) & 0x3;
++
++    switch(value){
++      case 0:
++  	    value = (pmu_read_pll1out() * 2) / 5;
++  	    break;
++      case 1:
++  	    value = pmu_read_pll1out() / 3;
++  	    break;
++      case 2:
++  	    value = pmu_read_pll1out() / 4;
++  	    break;
++      case 3:
++        if (pmu_get_version() == PMUVER_A)
++            value = pmu_read_pll1out() / 5;
++        else
++            value = pmu_read_pll4out() / 3;
++      	break;
++      default:
++  	    printk("AHB not support this mode\n");
++  	    break;
++	}
++
++    return value;
++}
++
++static unsigned int pmu_get_axi_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++
++    if(value & (1 << 19))
++  	value = pmu_read_pll1out() / 3;
++    else
++  	value = (pmu_read_pll1out() * 2) / 5;
++
++    return value;
++}
++
++unsigned int pmu_get_apb0_clk(void)
++{
++    return pmu_get_axi_clk() / 8;
++}
++
++unsigned int pmu_get_apb1_clk(void)
++{
++    return pmu_get_axi_clk() / 2;
++}
++
++unsigned int pmu_get_apb2_clk(void)
++{
++    return pmu_get_ahb_clk() / 4;
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    if(value & (1 << 22))
++        if(value & (1 << 24)){
++            value = (ioread32(pmu_base_addr + 0x38) >> 4) & 0x7F;
++  	        value = (SYS_CLK * value);
++  	    }
++  	    else
++  	        value = pmu_read_pll1out() / 3;
++    else
++  	    value = pmu_read_pll1out();
++
++    return value;
++}
++
++static unsigned int pmu_get_sys_clk(void)
++{
++    return 30*1000000;  //30Mhz
++}
++
++static unsigned int pmu_get_ep_cnt(void)
++{
++    u32 value;
++
++    value = (ftpmu010_read_reg(0xBC) >> 24) & 0xFF;
++
++    if (value > 1)
++        value = 0;  /* uninit value */
++
++    return value;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk",   ATTR_TYPE_AXI,    0}, pmu_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb0_clk},
++    {{"pclk1",  ATTR_TYPE_APB1,   0}, pmu_get_apb1_clk},
++    {{"pclk2",  ATTR_TYPE_APB2,   0}, pmu_get_apb2_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"pll4",   ATTR_TYPE_PLL4,   0}, pmu_read_pll4out},
++    {{"pll5",   ATTR_TYPE_PLL5,   0}, pmu_read_pll5out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++    {{"chipver",   ATTR_TYPE_CHIPVER, 0}, pmu_get_chipversion},
++	{{"sysclk",    ATTR_TYPE_SYSCLK,  0}, pmu_get_sys_clk},
++    {{"pci_epcnt", ATTR_TYPE_EPCNT,   0}, pmu_get_ep_cnt},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(clock_info); tmp ++) {
++            if (clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (clock_info[tmp].clock_fun) {
++                clock_info[tmp].clock.value = clock_info[tmp].clock_fun();
++                ftpmu010_deregister_attr(&clock_info[tmp].clock);
++                ret = ftpmu010_register_attr(&clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++    cpuintr_fd = ftpmu010_register_reg(&cpu_intr_info);
++    if (unlikely(cpuintr_fd < 0)){
++        printk("CPU INTR registers to PMU fail! \n");
++    }
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++    /* register AXI DMAC to pmu core */
++    xdmac_fd = ftpmu010_register_reg(&xdmac_clk_info);
++    if (unlikely(xdmac_fd < 0)){
++        printk("AXI DMAC registers to PMU fail! \n");
++    }
++#endif
++
++    mcp100_gate_fd = ftpmu010_register_reg(&mcp100_clk_info);
++    if (unlikely(mcp100_gate_fd < 0)){
++        printk("MCP100 gate registers to PMU fail! \n");
++    }
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++
++    /* clear the memory to zero */
++    iowrite32(0, (void *)pmu_base_addr + 0x6C);
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu_fpga.c b/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu_fpga.c
+new file mode 100644
+index 00000000..b8948429
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu_fpga.c
+@@ -0,0 +1,396 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h> 
++#ifdef CONFIG_GM8312
++#include <mach/ftpmu010_pcie.h>
++#endif
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++static int gpio_fd = -1;
++static int dmac_fd = -1;
++#ifdef CONFIG_GM8312
++static int gm8312_fd = -1;
++#endif
++static int cpuintr_fd = -1;
++#ifdef CONFIG_PLATFORM_AXIDMA
++static int xdmac_fd = -1;
++#endif
++
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++#ifdef CONFIG_GM8312
++static pmuPcieReg_t reg8312Array[] = {
++ /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++    {0x30, (0x1 << 8), (0x1 << 8), (0x0 << 8), (0x1 << 8)}, // Enable dmac CLK
++    {0x30, (0x1 << 10), (0x1 << 10), (0x0 << 10), (0x1 << 10)}, // Enable ahbc CLK
++    {0x30, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)}, // Enable PCIE_AXI_BRG       
++    {0x34, (0x1 << 1), (0x1 << 1), (0x0 << 1), (0x1 << 1)}, // Enable axic CLK
++    {0x34, (0x1 << 2), (0x1 << 2), (0x0 << 2), (0x1 << 2)}, // Enable X2H APB CLK
++    {0x34, (0x1 << 8), (0x1 << 8), (0x0 << 8), (0x1 << 8)}, // Enable INTC CLK    
++    {0x34, (0xFF << 9), (0xFF << 9), (0x0 << 9), (0xFF << 9)}, // Enable H2X APB CLK
++    {0x34, (0x3 << 23), (0x3 << 23), (0x0 << 23), (0x3 << 23)}, // Enable PCIE_AXI_BRG
++};
++static pmuPcieRegInfo_t gm8312_clk_info = {
++    "8312_clk",
++    ARRAY_SIZE(reg8312Array),
++    ATTR_TYPE_NONE, /* no clock source */
++    reg8312Array
++};
++#endif
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    
++#ifdef CONFIG_I2C0_IP
++    {0xB8, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // Disable i2c0 gating clock off	
++    {0x44, (0x1 << 12), (0x1 << 12), (0x1 << 12), (0x1 << 12)}, // Enable i2c0 schmitt trigger
++#endif    
++#ifdef CONFIG_I2C1_IP
++	{0xBC, (0x1 << 16), (0x1 << 16), (0x1 << 16), (0x1 << 16)}, // Enable i2c1 gating clock off        
++    {0x44, (0x1 << 16), (0x1 << 16), (0x1 << 16), (0x1 << 16)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 22), (0x3 << 22), (0x0 << 22), (0x3 << 22)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C2_IP    
++	{0xBC, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)}, // i2c1 gating clock off
++    {0x44, (0x1 << 17), (0x1 << 17), (0x1 << 17), (0x1 << 17)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 24), (0x3 << 24), (0x0 << 24), (0x3 << 24)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS 
++#endif
++#ifdef CONFIG_I2C3_IP
++	{0xBC, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // i2c1 gating clock off    
++    {0x44, (0x1 << 18), (0x1 << 18), (0x1 << 18), (0x1 << 18)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 26), (0x3 << 26), (0x0 << 26), (0x3 << 26)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS 
++#endif
++#ifdef CONFIG_I2C4_IP
++	{0xBC, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, // i2c1 gating clock off    
++    {0x44, (0x1 << 19), (0x1 << 19), (0x1 << 19), (0x1 << 19)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 28), (0x3 << 28), (0x0 << 28), (0x3 << 28)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS 
++#endif
++#ifdef CONFIG_I2C5_IP
++    {0xBC, (0x1 << 10), (0x1 << 10), (0x0 << 10), (0x1 << 10)}, // i2c1 gating clock off
++    {0x44, (0x1 << 20), (0x1 << 19), (0x1 << 20), (0x1 << 20)}, // i2c1 schmitt trigger
++    {0x4C, (0x3 <<  6), (0x3 <<  6), (0x0 <<  6), (0x3 <<  6)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS 
++#endif
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* GPIO
++ */
++static pmuReg_t regGPIOArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x3C, (0x7 << 9), (0x7 << 9), (0x0 << 9), (0x7 << 9)},
++};
++
++static pmuRegInfo_t gpio_clk_info = {
++    "gpio_clk",
++    ARRAY_SIZE(regGPIOArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regGPIOArray
++};
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++/* CPU INTR
++ */
++static pmuReg_t regCPUINTArray[] = {
++ /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++    {0xA8,   0xFFFFFFFF, 0xFFFFFFFF,   0x0,        0x0},
++};
++
++static pmuRegInfo_t cpu_intr_info = {
++    "CPU_INTR",
++    ARRAY_SIZE(regCPUINTArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regCPUINTArray
++};
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++/* AXI DMAC
++ */
++static pmuReg_t regXDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB0, (0x1 << 19), (0x1 << 19), (0x0 << 19), (0x1 << 19)},
++};
++static pmuRegInfo_t xdmac_clk_info = {
++    "AXI_DMAC_CLK",
++    ARRAY_SIZE(regXDMACArray),
++    ATTR_TYPE_AXI,
++    regXDMACArray
++};
++#endif
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	int inc = 0;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 */
++	if (!version) {
++
++	    version = ioread32(pmu_base_addr) >> 8;
++
++	    switch ((ioread32(pmu_base_addr) >> 5) & 0x7)
++	    {
++			case 0 : inc = 0; break;
++			case 2 : inc = 1; break;
++			case 6 : inc = 2; break;
++			case 7 : inc = 3; break;
++			default: inc = 0; break;
++		}
++		if ((version & 0xf0) == 0x10) {
++			/* 8210 series */
++			printk("IC: GM%04x(%c)\n", ((version >> 8) & 0xffff) + inc, (version & 0xff) + 'A' - 0x10);
++		} else {
++			printk("IC: ID not be found\n");
++		}
++	}
++
++	return version;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return (ioread32(pmu_base_addr + 0x30) >> 16);
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 3) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static inline u32 pmu_read_pll2out(void)
++{
++    printk("GM8210 not use PLL2\n");
++    return 0;
++}
++
++static unsigned int pmu_read_pll4out(void)
++{
++    return 768000000;
++}
++
++static unsigned int pmu_read_pll3out(void)
++{
++    return 648 * 1000000;
++}
++
++static unsigned int pmu_read_pll5out(void)
++{
++    return 100000000;
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++    return 20000000;
++}
++
++static unsigned int pmu_get_axi_clk(void)
++{
++    return 50000000;
++}
++
++unsigned int pmu_get_apb0_clk(void)
++{
++    return 20000000;//pmu_get_axi_clk() / 2;
++}
++
++unsigned int pmu_get_apb1_clk(void)
++{
++    return 20000000;//pmu_get_axi_clk() / 8;
++}
++
++unsigned int pmu_get_apb2_clk(void)
++{
++    return 20000000;//pmu_get_ahb_clk() / 4;
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    if(value & (1 << 22))
++  	value = pmu_read_pll1out() / 3;
++    else
++  	value = pmu_read_pll1out();
++
++    return value;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk",   ATTR_TYPE_AXI,    0}, pmu_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    //{{"pclk",   ATTR_TYPE_APB,    0}, pmu_get_apb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb0_clk},
++    {{"pclk1",  ATTR_TYPE_APB1,   0}, pmu_get_apb1_clk},
++    {{"pclk2",  ATTR_TYPE_APB2,   0}, pmu_get_apb2_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll2",   ATTR_TYPE_PLL2,   0}, pmu_read_pll2out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"pll4",   ATTR_TYPE_PLL4,   0}, pmu_read_pll4out},
++    {{"pll5",   ATTR_TYPE_PLL5,   0}, pmu_read_pll5out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++
++        /* this attribute exists */
++        if (clock_info[attr].clock_fun) {
++            clock_info[attr].clock.value = clock_info[attr].clock_fun();
++            ftpmu010_deregister_attr(&clock_info[attr].clock);
++            ret = ftpmu010_register_attr(&clock_info[attr].clock);
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++    cpuintr_fd = ftpmu010_register_reg(&cpu_intr_info);
++    if (unlikely(cpuintr_fd < 0)){
++        printk("CPU INTR registers to PMU fail! \n");
++    }
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++    /* register AXI DMAC to pmu core */
++    xdmac_fd = ftpmu010_register_reg(&xdmac_clk_info);
++    if (unlikely(xdmac_fd < 0)){
++        printk("AXI DMAC registers to PMU fail! \n");
++    }
++#endif
++
++#ifdef CONFIG_GM8312
++    ftpmu010_pcie_init((void *)PCIPMU_FTPMU010_VA_BASE);
++    
++    /* register GM8312 bus to pmu core */
++    gm8312_fd = ftpmu010_pcie_register_reg(&gm8312_clk_info);
++    if (unlikely(gm8312_fd < 0)){
++        printk("GM8312 CLK registers to PMU fail! \n");
++    }       
++#endif
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu_pcie.c b/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu_pcie.c
+new file mode 100644
+index 00000000..880af716
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-M/pmu_pcie.c
+@@ -0,0 +1,191 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++#include <mach/ftpmu010_pcie.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int gm8312_fd = -1;
++static int cpuintr_fd = -1;
++
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_pcie_gate_clk_t pcie_gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_PCIE_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++
++    /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++static pmuPcieReg_t reg8312Array[] = {
++    /* Enable dmac CLK, ahbc CLK, PCIE_AXI_BRG */
++    {0x30, (0x1 << 8) | (0x1 << 10) | (0x1 << 13), (0x1 << 8) | (0x1 << 10) | (0x1 << 13), 0x0, (0x1 << 8) | (0x1 << 10) | (0x1 << 13)},
++
++    /* Enable AXIC_APB_CLK, X2H APB CLK, INTC CLK, H2X APB CLK, PCIE_AXI_BRG, H2X7_APB_CLK */
++    {0x34, (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 << 16) | (0x3 << 23), (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 <<16) |  (0x3 << 23), 0x0, (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 << 16) | (0x3 << 23)},
++};
++static pmuPcieRegInfo_t gm8312_clk_info = {
++    "8312_clk",
++    ARRAY_SIZE(reg8312Array),
++    ATTR_TYPE_PCIE_NONE, /* no clock source */
++    reg8312Array
++};
++
++static unsigned int pmu_pcie_get_version(void)
++{
++	static unsigned int version = 0;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 */
++	if (!version) {
++
++	    version = ioread32(pmu_base_addr) >> 8;
++		printk("IC: GM%04x(%c)\n", ((version >> 8) & 0xffff), (version & 0xff) + 'A' - 0x10);
++	}
++
++	return version;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_pcie_read_pll1out(void)
++{
++    u32 value = 0, pll_ns, pll_ms;
++
++    value = ioread32(pmu_base_addr + 0x08);
++    pll_ns = (value >> 2) & 0xFF;
++    pll_ms = (value >> 10) & 0x1F;
++
++    return (SYS_CLK * pll_ns / pll_ms);
++}
++
++static unsigned int pmu_pcie_get_axi_clk(void)
++{
++    return pmu_pcie_read_pll1out() / 2;
++}
++
++static unsigned int pmu_pcie_get_ahb_clk(void)
++{
++    return pmu_pcie_read_pll1out() / 2;
++}
++
++unsigned int pmu_pcie_get_apb_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x34);
++    value = (value >> 26) & 0x1F;
++
++    return pmu_pcie_get_ahb_clk() / (value + 1);
++}
++
++struct clock_s
++{
++    attrPcieInfo_t   clock;
++    u32         (*clock_fun)(void);
++} pcie_clock_info[] = {
++    {{"aclk",   ATTR_TYPE_PCIE_AXI,    0}, pmu_pcie_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_PCIE_AHB,    0}, pmu_pcie_get_ahb_clk},
++    {{"pclk",   ATTR_TYPE_PCIE_APB,    0}, pmu_pcie_get_apb_clk},
++    {{"pll1",   ATTR_TYPE_PCIE_PLL1,   0}, pmu_pcie_read_pll1out},
++    {{"pmuver", ATTR_TYPE_PCIE_PMUVER, 0}, pmu_pcie_get_version},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_PCIE_TYPE_T attr = (ATTR_PCIE_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(pcie_clock_info); tmp ++) {
++            if (pcie_clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (pcie_clock_info[tmp].clock_fun) {
++                pcie_clock_info[tmp].clock.value = pcie_clock_info[tmp].clock_fun();
++                ftpmu010_pcie_deregister_attr(&pcie_clock_info[tmp].clock);
++                ret = ftpmu010_pcie_register_attr(&pcie_clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_pcie_postinit(void)
++{
++    int i;
++
++    printk("PCIE PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_pcie_init(pmu_base_addr, &pcie_gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(pcie_clock_info); i ++)
++    {
++        if (pcie_clock_info[i].clock_fun)
++            pcie_clock_info[i].clock.value = pcie_clock_info[i].clock_fun();
++
++        ftpmu010_pcie_register_attr(&pcie_clock_info[i].clock);
++    }
++
++    /* register GM8312 bus to pmu core */
++    gm8312_fd = ftpmu010_pcie_register_reg(&gm8312_clk_info);
++    if (unlikely(gm8312_fd < 0)){
++        printk("GM8312 CLK registers to PMU fail! \n");
++    }
++
++    return 0;
++}
++
++arch_initcall(pmu_pcie_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_pcie_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-M/timer_fixup.c b/arch/arm/mach-GM-Duo/platform-GM8210-M/timer_fixup.c
+new file mode 100644
+index 00000000..66920651
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-M/timer_fixup.c
+@@ -0,0 +1,128 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/ftpmu010.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/fiq.h>
++#include <mach/platform/board.h>
++
++#define CONFIG_MAX_TICK     0xffffffff
++static int timer_init_ready = 0;
++
++/*
++ * Get the max ms the this timer
++ */
++unsigned int video_gettime_max_ms(void)
++{
++    return (CONFIG_MAX_TICK / APB0_CLK_IN) * 1000;
++}
++
++/* calculate the max hz in max_ms
++ */
++unsigned int video_gettime_max_hz(void)
++{
++    unsigned int max_hz;
++
++    /* calculate the max hz in max_ms. Actually it is (video_gettime_max_ms() / 1000) * APB0_CLK_IN
++     */
++    max_hz = video_gettime_max_ms() * (APB0_CLK_IN / 1000);
++
++    return max_hz;
++}
++
++unsigned int video_gettime_ms(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++unsigned int video_gettime_us(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++
++        return (value - tick_diff) / (ft_apb_clk / 1000000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++/*
++ * Entry Point of this module. It may be declared by arch_initcall section
++ */
++static int __init fixup_timer_init(void)
++{
++    //use timer3, 42s will overflow in AHB clock 200HZ
++    unsigned int ft_apb_clk = APB0_CLK_IN;
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++    unsigned int max_tick;
++
++    if (*(unsigned int *)(timer_base + 0x30) & (0x1 << 6))
++    {
++        printk("Timer3 is alredy been used!\n");
++        return 0;
++    }
++
++    max_tick = video_gettime_max_ms() * (ft_apb_clk / 1000);    //the max hz count in TmxCounter
++
++    printk("Video Timer(timer3) Max %dms in 0x%x HZ.\n", video_gettime_max_ms(), max_tick);
++
++    /* the following configuration is for TIMER3 */
++    *(volatile unsigned int *)(timer_base + 0x20) = CONFIG_MAX_TICK - max_tick; //keep the start count in start counter
++    *(volatile unsigned int *)(timer_base + 0x24) = CONFIG_MAX_TICK - max_tick; //reLoad counter
++    *(volatile unsigned int *)(timer_base + 0x38) |= (0x7 << 6);   //IRQ disable
++    *(volatile unsigned int *)(timer_base + 0x30) |= ((0x1 << 6) | (0x1 << 11));    //enable timer3, count up
++    timer_init_ready = 1;
++
++    return 0;
++}
++
++static void fixup_timer_exit(void)
++{
++    if (timer_init_ready == 1)
++    {
++        unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        *(volatile unsigned int *)(timer_base + 0x30) &= ~(0x1 << 6);//disable timer2, count up
++        timer_init_ready = 0;
++    }
++	printk("%s: cleaning up\n",__func__);
++}
++
++module_init(fixup_timer_init);
++module_exit(fixup_timer_exit);
++
++EXPORT_SYMBOL(video_gettime_ms);
++EXPORT_SYMBOL(video_gettime_us);
++EXPORT_SYMBOL(video_gettime_max_ms);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("FIXUP timer driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-S/Kconfig b/arch/arm/mach-GM-Duo/platform-GM8210-S/Kconfig
+new file mode 100644
+index 00000000..2103e20d
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-S/Kconfig
+@@ -0,0 +1,44 @@
++#
++# arch/arm/mach-GM/platform-GM8210/Kconfig
++
++if PLATFORM_GM8210_S
++
++#config SYS_CLK
++config CLOCK_TICK_RATE
++        int "AHB System Clock"
++        default 33000000
++        help
++            Any fake value is ok. It is almost obsolete.
++
++config GM8210_S_HZ
++    int "HZ of GM8210_S (FA626)"
++    range 100 1000
++    default 1000
++    help
++      HZ defined in GM8210_S platform
++
++config PLATFORM_AXIDMA
++	bool "AXI DMA support"
++	default y
++
++config FTINTC030
++	bool "FTINTC030 support"
++	default y
++
++config FTINTC010EX
++	bool "FTINTC010EX supports 64 IRQs"
++	default y
++
++config FC7500
++    bool "FC7500 support"
++    default y
++
++config GM8312
++    bool "GM8312 support"
++    default y
++
++config GM8210_FPGA
++	bool "FPGA Verify"
++	default n
++
++endif
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-S/Makefile b/arch/arm/mach-GM-Duo/platform-GM8210-S/Makefile
+new file mode 100644
+index 00000000..aabad758
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-S/Makefile
+@@ -0,0 +1,11 @@
++#
++# Makefile for the GM platform dependent files
++
++# Object file lists.
++
++ifeq ($(CONFIG_GM8210_FPGA),y)
++obj-y		:= board.o pmu_fpga.o timer_fixup.o platform.o
++else
++obj-y		:= board.o pmu.o timer_fixup.o platform.o
++obj-$(CONFIG_GM8312)   += pmu_pcie.o
++endif
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-S/board.c b/arch/arm/mach-GM-Duo/platform-GM8210-S/board.c
+new file mode 100644
+index 00000000..9a9af40b
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-S/board.c
+@@ -0,0 +1,427 @@
++/*
++ *  board depdenent initialization
++ *
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/setup.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/platform/board.h>
++#include <mach/platform/pmu.h>
++#include <mach/platform/platform_io.h>
++#ifdef CONFIG_GM8312
++#include <mach/platform/pmu_pcie.h>
++#endif
++#include <mach/platform/system.h>
++#include <mach/ftintc030.h>
++#include <mach/fttmr010.h>
++#include <mach/fmem.h>
++#include <linux/dma-mapping.h> /* for init_consistent_dma_size() */
++#ifdef CONFIG_FTDMAC030
++#include <mach/ftdmac030.h>
++#endif
++
++/* External functions and variables declaration
++ */
++extern void platform_devices_init(void);
++
++/* Local variables declaration
++ */
++void __iomem *ftintc030_base_addr;
++void __iomem *ftintc030_base_cpu_1_irq_base; //entry-macro.S will reference it
++
++#ifdef CONFIG_FTDMAC030
++/*
++ * DMAC030 channel filter.
++ */
++static int board_dmac030_chan_filter(int chan_id)
++{
++    /* FA626 CPU only can use 5. 6 and 7 are used for cpu_comm */
++    if (chan_id == 5)
++        return 0;
++
++    return -1;
++}
++#endif /* CONFIG_FTDMAC030 */
++
++/******************************************************************************
++ * IPs virtual address mapping
++ *****************************************************************************/
++static struct map_desc board_io_desc[] __initdata = {
++    /* PMU */
++    {
++        .virtual	= PMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PMU_FTPMU010_PA_BASE),
++		.length		= PMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART0 */
++    {
++        .virtual	= UART_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_0_PA_BASE),
++		.length		= UART_FTUART010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* TIMER */
++    {
++        .virtual	= TIMER_FTTMR010_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_PA_BASE),
++		.length		= TIMER_FTTMR010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC030 */
++    {
++        .virtual	= INTC_FTINTC030_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC030_PA_BASE),
++		.length		= INTC_FTINTC030_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* PCI_PMU */
++    {
++        .virtual	= PCIPMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PCIPMU_FTPMU010_PA_BASE),
++		.length		= PCIPMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC010 */
++    {
++        .virtual	= INTC_FTINTC010_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC010_PA_BASE),
++		.length		= INTC_FTINTC010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++};
++
++/* fixup the memory for MACHINE_START. The parameters come from commandline of menuconfig
++ */
++static void __init board_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    fmem_fixup_memory(tag, cmdline, mi);
++}
++
++/* 2. create the iotable for IPs in MACHINE_START
++ */
++static void __init board_map_io(void)
++{
++    iotable_init(&board_io_desc[0], ARRAY_SIZE(board_io_desc));
++
++    /* set the base to pmu module */
++    pmu_earlyinit((void *)PMU_FTPMU010_VA_BASE);
++#ifdef CONFIG_GM8312
++    pmu_pcie_earlyinit((void *)PCIPMU_FTPMU010_VA_BASE);
++#endif
++    /* init dma coherent mapping size,
++     * CONSISTENT_DMA_SIZE is defined in memory.h
++     * max allowable dma consistent size is 14M (0xFFE0_0000 - 0xFF00_00000)
++     * set as 12M to avoid unexpected data overlay, NISH_20121015
++     */
++    #ifdef CONSISTENT_DMA_SIZE
++    init_consistent_dma_size(CONSISTENT_DMA_SIZE);
++    #endif
++}
++
++/* HDCP of HDMI is useless, so we use the last 16 bytes as the memory destination
++ * format: [0]init_done value, [4]who owned the key, [8]lock/unlock value, [c]: how long
++ */
++typedef struct {
++    unsigned int init_done;
++    unsigned int lock;
++    unsigned int owner;
++    unsigned int wait_cnt;
++    unsigned int lock_cnt;
++    unsigned int statistic;   /* statistic only */
++    unsigned int last_freer;
++    unsigned int reserved[1];
++} lock_content_t;
++
++#define LOCK_VAL        0xAAAA0000
++#define UNLOCK_VAL      0x00005555
++#define INIT_DONE       0x00112233
++#define LOCK_OWNER      0x000FA626
++
++static unsigned int hdmi_va;
++
++static void board_bus_lock_vainit(void)
++{
++    hdmi_va = (unsigned int)ioremap_nocache(HDMI_FTHDCPMEM_PA_BASE, 512);
++    if (!hdmi_va)
++        panic("Error to allocate va! \n");
++}
++
++void board_bus_lock_init(bus_lock_t bus)
++{
++    volatile int i;
++    volatile u32 base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE) {
++        memset((char *)content, 0, sizeof(lock_content_t));
++        content->lock = UNLOCK_VAL;
++        content->init_done = INIT_DONE;
++    }
++
++    //delay a while prevent from multiple CPUs re-entrant
++    for (i = 0; i < 0x100; i ++)
++        ioread32(hdmi_va);
++}
++EXPORT_SYMBOL(board_bus_lock_init);
++
++void board_bus_lock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setlock = LOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner == LOCK_OWNER) {
++        content->lock_cnt ++;
++        content->statistic ++;
++        return;
++    }
++
++    ptr = base + 4;
++re_try:
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setlock), "r" (ptr)
++                : "memory", "cc");
++    if (retval != UNLOCK_VAL) {
++        if (irqs_disabled() || in_interrupt())
++	    udelay(100);
++	else
++	    msleep(1);
++        content->wait_cnt ++;
++        goto re_try;
++    }
++
++    content->owner = LOCK_OWNER;
++    content->lock_cnt ++;
++    content->statistic ++;
++    content->wait_cnt = 0;
++    content->last_freer = 0;
++}
++EXPORT_SYMBOL(board_bus_lock);
++
++void board_bus_unlock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setunlock = UNLOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner != LOCK_OWNER)
++        panic("the locker:%d has wrong owner:0x%x! \n", bus, content->owner);
++
++    content->lock_cnt --;
++    if (content->lock_cnt)
++        return;
++
++    content->owner = 0;   //no owner
++    content->last_freer = LOCK_OWNER;
++
++    ptr = base + 4;
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setunlock), "r" (ptr)
++                : "memory", "cc");
++
++    if (retval != LOCK_VAL) {
++        int i;
++
++        for (;;) {
++            printk("Error value 0x%x in locker:%d! \n", retval, bus);
++            msleep(990);
++
++            for (i = 0; i < 8; i ++)
++                printk("content[%d] = 0x%x \n", i, ioread32(base + i * 4));
++        }
++    }
++}
++EXPORT_SYMBOL(board_bus_unlock);
++
++/* return value:
++ *  -1 for fail which means the bus was locked by others
++ *  0 for grab the lock success
++ */
++int board_bus_trylock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setlock = LOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner == LOCK_OWNER) {
++        content->lock_cnt ++;
++        content->statistic ++;
++        return 0;
++    }
++
++    ptr = base + 4;
++
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setlock), "r" (ptr)
++                : "memory", "cc");
++    if (retval != UNLOCK_VAL)
++        return -1;
++
++    content->owner = LOCK_OWNER;
++    content->lock_cnt ++;
++    content->statistic ++;
++    content->wait_cnt = 0;
++    content->last_freer = 0;
++
++    return 0;
++}
++EXPORT_SYMBOL(board_bus_trylock);
++
++static void __init board_init_irq(void)
++{
++	struct ftintc030_trigger_type master_trigger_type = {
++		.irqmode[0]	= PLATFORM_IRQ_TRIGGER_MODE1,
++		.irqlevel[0]	= ~PLATFORM_IRQ_TRIGGER_LEVEL1,
++		.fiqmode[0]	= PLATFORM_FIQ_TRIGGER_MODE1,
++		.fiqlevel[0]	= ~PLATFORM_FIQ_TRIGGER_LEVEL1,
++
++		.irqmode[1]	= PLATFORM_IRQ_TRIGGER_MODE2,
++		.irqlevel[1]	= ~PLATFORM_IRQ_TRIGGER_LEVEL2 | (1 << (EXT_INT_0_IRQ - 32)),
++		.fiqmode[1]	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel[1]	= ~PLATFORM_FIQ_TRIGGER_LEVEL2 | (1 << (EXT_INT_0_IRQ - 32)),
++
++		.irqmode[2]	= PLATFORM_IRQ_TRIGGER_MODE3,
++		.irqlevel[2]	= ~PLATFORM_IRQ_TRIGGER_LEVEL3,
++		.fiqmode[2]	= PLATFORM_FIQ_TRIGGER_MODE3,
++		.fiqlevel[2]	= ~PLATFORM_FIQ_TRIGGER_LEVEL3,
++
++		.irqmode[3]	= PLATFORM_IRQ_TRIGGER_MODE4,
++		.irqlevel[3]	= ~PLATFORM_IRQ_TRIGGER_LEVEL4,
++		.fiqmode[3]	= PLATFORM_FIQ_TRIGGER_MODE4,
++		.fiqlevel[3]	= ~PLATFORM_FIQ_TRIGGER_LEVEL4,
++
++		.irqmode[4]	= PLATFORM_IRQ_TRIGGER_MODE5,
++		.irqlevel[4]	= ~PLATFORM_IRQ_TRIGGER_LEVEL5,
++		.fiqmode[4]	= PLATFORM_FIQ_TRIGGER_MODE5,
++		.fiqlevel[4]	= ~PLATFORM_FIQ_TRIGGER_LEVEL5,
++
++		.irqmode[5]	= PLATFORM_IRQ_TRIGGER_MODE6,
++		.irqlevel[5]	= ~PLATFORM_IRQ_TRIGGER_LEVEL6,
++		.fiqmode[5]	= PLATFORM_FIQ_TRIGGER_MODE6,
++		.fiqlevel[5]	= ~PLATFORM_FIQ_TRIGGER_LEVEL6,
++
++		.irqmode[6]	= PLATFORM_IRQ_TRIGGER_MODE7,
++		.irqlevel[6]	= ~PLATFORM_IRQ_TRIGGER_LEVEL7,
++		.fiqmode[6]	= PLATFORM_FIQ_TRIGGER_MODE7,
++		.fiqlevel[6]	= ~PLATFORM_FIQ_TRIGGER_LEVEL7,
++
++		.irqmode[7]	= PLATFORM_IRQ_TRIGGER_MODE8,
++		.irqlevel[7]	= ~PLATFORM_IRQ_TRIGGER_LEVEL8,
++		.fiqmode[7]	= PLATFORM_FIQ_TRIGGER_MODE8,
++		.fiqlevel[7]	= ~PLATFORM_FIQ_TRIGGER_LEVEL8,
++	};
++
++    board_bus_lock_vainit();
++
++	/*
++	 * initialize primary interrupt controller
++	 */
++	ftintc030_base_addr = __io(INTC_FTINTC030_VA_BASE);
++	ftintc030_base_cpu_1_irq_base = __io(INTC_FTINTC030_VA_BASE + FTINTC030_OFFSET_CPU_1_IRQ);
++
++	ftintc030_init(0, ftintc030_base_addr, 0, &master_trigger_type);
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 1,
++};
++
++static void __init board_sys_timer_init(void)
++{
++    unsigned int pclk = pmu_get_apb0_clk();
++	printk("Timer use APB0 clock\n");
++
++	fttmr010_0_clockevent.freq = pclk;
++	fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++	fttmr010_1_clocksource.freq = pclk;
++	fttmr010_clocksource_init(&fttmr010_1_clocksource);
++}
++
++struct sys_timer board_sys_timer = {
++	.init	= board_sys_timer_init,
++};
++
++/* board init */
++static void __init board_init_machine(void)
++{
++    int i;
++
++    platform_devices_init();
++
++    /* dump iotable information
++     */
++    for (i = 0; i < ARRAY_SIZE(board_io_desc); i ++) {
++        printk("iotable: VA: 0x%x, PA: 0x%x, Length: %d \n",
++                (u32)board_io_desc[i].virtual,
++                (u32)board_io_desc[i].pfn << PAGE_SHIFT,
++                (u32)board_io_desc[i].length);
++    }
++
++#ifdef CONFIG_FTDMAC030
++    ftdmac030_set_platform_chanfilter(board_dmac030_chan_filter);
++#endif
++}
++
++MACHINE_START(GM, BOARD_NAME)
++	.atag_offset	= BOOT_PARAMETER_PA_OFFSET,   //boot command line, after kernel 3.2 change as relative address
++	.map_io		    = board_map_io,
++	.init_irq	    = board_init_irq,
++	.timer		    = &board_sys_timer,
++	.fixup          = board_fixup_memory,
++	.init_machine	= board_init_machine,
++	.restart	= arch_reset,
++MACHINE_END
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-S/platform.c b/arch/arm/mach-GM-Duo/platform-GM8210-S/platform.c
+new file mode 100644
+index 00000000..8d00b0df
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-S/platform.c
+@@ -0,0 +1,304 @@
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/dma-mapping.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach-types.h>
++#include <mach/platform/board.h>
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++#ifdef CONFIG_I2C0_IP
++/* i2c:0 */
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start  = I2C_FTI2C010_0_PA_BASE,
++		.end    = I2C_FTI2C010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_0_IRQ,
++		.end	= I2C_FTI2C010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		    = 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C1_IP
++/* i2c:1 */
++static struct resource ftiic010_1_resources[] = {
++	{
++		.start  = I2C_FTI2C010_1_PA_BASE,
++		.end    = I2C_FTI2C010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_1_IRQ,
++		.end	= I2C_FTI2C010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_1_device = {
++	.name		= "ftiic010",
++	.id		    = 1,
++	.num_resources	= ARRAY_SIZE(ftiic010_1_resources),
++	.resource	= ftiic010_1_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C2_IP
++/* i2c:2 */
++static struct resource ftiic010_2_resources[] = {
++	{
++		.start  = I2C_FTI2C010_2_PA_BASE,
++		.end    = I2C_FTI2C010_2_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_2_IRQ,
++		.end	= I2C_FTI2C010_2_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_2_device = {
++	.name		= "ftiic010",
++	.id		    = 2,
++	.num_resources	= ARRAY_SIZE(ftiic010_2_resources),
++	.resource	= ftiic010_2_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C3_IP
++/* i2c:3 */
++static struct resource ftiic010_3_resources[] = {
++	{
++		.start  = I2C_FTI2C010_3_PA_BASE,
++		.end    = I2C_FTI2C010_3_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_3_IRQ,
++		.end	= I2C_FTI2C010_3_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_3_device = {
++	.name		= "ftiic010",
++	.id		    = 3,
++	.num_resources	= ARRAY_SIZE(ftiic010_3_resources),
++	.resource	= ftiic010_2_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C4_IP
++/* i2c:4 */
++static struct resource ftiic010_4_resources[] = {
++	{
++		.start  = I2C_FTI2C010_4_PA_BASE,
++		.end    = I2C_FTI2C010_4_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_4_IRQ,
++		.end	= I2C_FTI2C010_4_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_4_device = {
++	.name		= "ftiic010",
++	.id		    = 4,
++	.num_resources	= ARRAY_SIZE(ftiic010_4_resources),
++	.resource	= ftiic010_4_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C5_IP
++/* i2c:4 */
++static struct resource ftiic010_5_resources[] = {
++	{
++		.start  = I2C_FTI2C010_5_PA_BASE,
++		.end    = I2C_FTI2C010_5_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_5_IRQ,
++		.end	= I2C_FTI2C010_5_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_5_device = {
++	.name		= "ftiic010",
++	.id		    = 4,
++	.num_resources	= ARRAY_SIZE(ftiic010_5_resources),
++	.resource	= ftiic010_5_resources,
++};
++#endif
++
++/******************************************************************************
++ * GPIO devices
++ *****************************************************************************/
++#if defined(CONFIG_GPIO_FTGPIO010)
++/* GPIO 0 */
++static struct resource ftgpio010_0_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_0_PA_BASE,
++		.end 	= GPIO_FTGPIO010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_0_IRQ,
++		.end	= GPIO_FTGPIO010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_0_device = {
++	.name	= "ftgpio010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgpio010_0_resource),
++	.resource	= ftgpio010_0_resource
++};
++
++/* GPIO 1 */
++static struct resource ftgpio010_1_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_1_PA_BASE,
++		.end 	= GPIO_FTGPIO010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_1_IRQ,
++		.end	= GPIO_FTGPIO010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_1_device = {
++	.name	= "ftgpio010",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgpio010_1_resource),
++	.resource	= ftgpio010_1_resource
++};
++#endif /* CONFIG_GPIO_FTGPIO010 */
++/******************************************************************************
++ * AHB DMA controllers
++ *****************************************************************************/
++#ifdef CONFIG_FTDMAC020
++static struct resource ftdmac020_0_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_0_PA_BASE,
++		.end	= DMAC_FTDMAC020_0_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_0_IRQ,
++		.end    = DMAC_FTDMAC020_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_0_device = {
++	.name		= "ftdmac020",
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_0_resources),
++	.resource	= ftdmac020_0_resources,
++};
++#endif /* CONFIG_FTDMAC020 */
++
++/******************************************************************************
++ * SPI020 controllers
++ *****************************************************************************/
++#ifdef CONFIG_SPI_FTSPI020
++static struct resource ftspi020_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,     /* Register Base address */
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static u64 ftspi020_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftspi020_device = {
++    .name = "ftspi020",
++    .id = 0,//must match with bus_num
++    .num_resources = ARRAY_SIZE(ftspi020_resource),
++    .resource = ftspi020_resource,
++    .dev = {
++            .dma_mask = &ftspi020_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            },
++};
++#endif /* CONFIG_SPI_FTSPI020 */
++
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/
++static struct platform_device *gm_devices[] __initdata =
++{
++	/* I2C */
++#ifdef CONFIG_I2C0_IP
++	&ftiic010_0_device,
++#endif
++#ifdef CONFIG_I2C1_IP
++	&ftiic010_1_device,
++#endif
++#ifdef CONFIG_I2C2_IP
++	&ftiic010_2_device,
++#endif
++#ifdef CONFIG_I2C3_IP
++	&ftiic010_3_device,
++#endif
++#ifdef CONFIG_I2C4_IP
++	&ftiic010_4_device,
++#endif
++#ifdef CONFIG_I2C5_IP
++    &ftiic010_5_device,
++#endif
++#if defined(CONFIG_GPIO_FTGPIO010)
++    &ftgpio010_0_device,
++    &ftgpio010_1_device,
++#endif
++#ifdef CONFIG_FTDMAC020
++    &ftdmac020_0_device,
++#endif
++#ifdef CONFIG_SPI_FTSPI020
++    &ftspi020_device,
++#endif
++};
++
++void __init platform_devices_init(void)
++{
++    /* add platform devices here
++     */
++
++    /* will invoke platform_device_register() to register all platform devices
++     */
++	platform_add_devices(gm_devices, ARRAY_SIZE(gm_devices));
++}
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu.c b/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu.c
+new file mode 100644
+index 00000000..64da0f36
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu.c
+@@ -0,0 +1,472 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++/* PMU register data */
++static int i2c_fd = -1;
++#ifdef CONFIG_GPIO_FTGPIO010
++static int gpio_fd = -1;
++#endif
++static int dmac_fd = -1;
++#ifdef CONFIG_PLATFORM_AXIDMA
++static int xdmac_fd = -1;
++#endif
++
++static int cpuintr_fd = -1;
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count, register (ofs, val, mask) */
++    {FTPMU_H264E_0, 2,     {{0xB0, (0x0 << 25),  (0x1 << 25)}, {0xB0, (0x0 << 3),  (0x1 << 3)}}},
++    {FTPMU_H264E_1, 2,     {{0xB4, (0x0 << 30),  (0x1 << 30)}, {0xB4, (0x0 << 8),  (0x1 << 8)}}},   /* mcp280off */
++    {FTPMU_H264D_0, 2,     {{0xB0, (0x0 << 24),  (0x1 << 24)}, {0xB0, (0x0 << 2),  (0x1 << 2)}}},
++    {FTPMU_H264D_1, 2,     {{0xB4, (0x0 << 29),  (0x1 << 29)}, {0xB4, (0x0 << 3),  (0x1 << 3)}}},   /* mcp300off */
++    {FTPMU_MCP100_0,1,     {{0xB4, (0x0 << 12),  (0x1 << 12)}}},   /* mcp100off */
++    {FTPMU_3DI_0,   2,     {{0xB0, (0x0 << 22),  (0x1 << 22)}, {0xB0, (0x0 << 15), (0x1 << 15)}}},  /* di3d0off */
++  	{FTPMU_SCALER_0,2,     {{0xB0, (0x0 << 26),  (0x1 << 26)}, {0xB0, (0x0 << 4),  (0x1 << 4)}}},  /* scaroff */
++    {FTPMU_NONE,    0,     {{0x0,   0x0,         0x0}}} /* END, this row is necessary */
++};
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++
++#ifdef CONFIG_I2C0_IP
++    {0xB8, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // Disable i2c0 gating clock off
++    {0x44, (0x1 << 12), (0x1 << 12), (0x1 << 12), (0x1 << 12)}, // Enable i2c0 schmitt trigger
++#endif
++#ifdef CONFIG_I2C1_IP
++	{0xBC, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)}, // Enable i2c1 gating clock off
++    {0x44, (0x1 << 16), (0x1 << 16), (0x1 << 16), (0x1 << 16)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 22), (0x3 << 22), (0x0 << 22), (0x3 << 22)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C2_IP
++	{0xBC, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)}, // i2c1 gating clock off
++    {0x44, (0x1 << 17), (0x1 << 17), (0x1 << 17), (0x1 << 17)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 24), (0x3 << 24), (0x0 << 24), (0x3 << 24)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C3_IP
++	{0xBC, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // i2c1 gating clock off
++    {0x44, (0x1 << 18), (0x1 << 18), (0x1 << 18), (0x1 << 18)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 26), (0x3 << 26), (0x0 << 26), (0x3 << 26)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C4_IP
++	{0xBC, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, // i2c1 gating clock off
++    {0x44, (0x1 << 19), (0x1 << 19), (0x1 << 19), (0x1 << 19)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 28), (0x3 << 28), (0x0 << 28), (0x3 << 28)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C5_IP
++    {0xBC, (0x1 << 10), (0x1 << 10), (0x0 << 10), (0x1 << 10)}, // i2c1 gating clock off
++    {0x44, (0x1 << 20), (0x1 << 19), (0x1 << 20), (0x1 << 20)}, // i2c1 schmitt trigger
++    {0x4C, (0x3 <<  6), (0x3 <<  6), (0x0 <<  6), (0x3 <<  6)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* GPIO
++ */
++static pmuReg_t regGPIOArray[] = {
++     /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++        {0x3C, (0x7 << 9), (0x7 << 9), (0x0 << 9), (0x7 << 9)},
++};
++
++static pmuRegInfo_t gpio_clk_info = {
++        "gpio_clk",
++        ARRAY_SIZE(regGPIOArray),
++        ATTR_TYPE_NONE, /* no clock source */
++        regGPIOArray
++};
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++/* AXI DMAC
++ */
++static pmuReg_t regXDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB0, (0x1 << 19), (0x1 << 19), (0x0 << 19), (0x1 << 19)},
++};
++static pmuRegInfo_t xdmac_clk_info = {
++    "AXI_DMAC_CLK",
++    ARRAY_SIZE(regXDMACArray),
++    ATTR_TYPE_AXI,
++    regXDMACArray
++};
++#endif
++
++/* CPU INTR
++ */
++static pmuReg_t regCPUINTArray[] = {
++ /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++    {0xA8,   0xFFFFFFFF, 0xFFFFFFFF,   0x0,        0x0},
++};
++
++static pmuRegInfo_t cpu_intr_info = {
++    "CPU_INTR",
++    ARRAY_SIZE(regCPUINTArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regCPUINTArray
++};
++
++/* 0 for system running NAND, -1 for spi, 1 for SMC */
++int platform_check_flash_type(void)
++{
++	static unsigned int data = 0;
++	int ret = 0;
++
++	data = ioread32(pmu_base_addr + 0x4);
++
++    if (data & BIT22)
++        if (data & BIT23)
++            ret = -1;
++        else
++            ret = 0;
++    else
++        ret = 1;
++
++	return ret;
++}
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	pmuver_t pmuver;
++	unsigned int product;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 *     821011: B version
++	 */
++	if (!version) {
++        product = (ioread32(pmu_base_addr) >> 16) & 0xFFFF;
++	    version = (ioread32(pmu_base_addr) >> 8) & 0xFF;
++
++	    printk("IC: GM%x, version: 0x%x \n", product, version);
++	}
++
++    switch (version) {
++      case 0x10:
++        pmuver = PMUVER_A;
++        break;
++      case 0x11:
++        pmuver = PMUVER_B;
++        break;
++      case 0x12:
++        pmuver = PMUVER_C;
++        break;
++      default:
++        pmuver = PMUVER_UNKNOWN;
++        break;
++    }
++
++	return (unsigned int)pmuver;
++}
++
++//format: xxxx_yyyy. xxxx: 8210, yyyy:IC revision
++unsigned int pmu_get_chipversion(void)
++{
++    unsigned int value = (0x8210 << 16);
++
++    value |= pmu_get_version();
++
++    return value;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return (ioread32(pmu_base_addr + 0x30) >> 16);
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 3) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static unsigned int pmu_read_pll4out(void)
++{
++	u32 value;
++
++    value = (ioread32(pmu_base_addr + 0x38) >> 4 ) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static unsigned int pmu_read_pll3out(void)
++{
++    u32 mul, value = 0;
++
++    if (ioread32(pmu_base_addr + 0x28) & (1 << 15)) {
++        printk("PLL3 not support this mode\n");
++    } else {
++  	    mul = (ioread32(pmu_base_addr + 0x34) >> 4) & 0x7F;
++  	    value = (SYS_CLK * mul) / 2;
++    }
++
++    return value;
++}
++
++static unsigned int pmu_read_pll5out(void)
++{
++    return 100000000;
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 17) & 0x3;
++
++    switch(value){
++      case 0:
++  	    value = (pmu_read_pll1out() * 2) / 5;
++  	    break;
++      case 1:
++  	    value = pmu_read_pll1out() / 3;
++  	    break;
++      case 2:
++  	    value = pmu_read_pll1out() / 4;
++  	    break;
++      case 3:
++        if (pmu_get_version() == PMUVER_A)
++            value = pmu_read_pll1out() / 5;
++        else
++            value = pmu_read_pll4out() / 3;
++      	break;
++      default:
++  	    printk("AHB not support this mode\n");
++  	    break;
++	}
++
++    return value;
++}
++
++static unsigned int pmu_get_axi_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++
++    if(value & (1 << 19))
++  	value = pmu_read_pll1out() / 3;
++    else
++  	value = (pmu_read_pll1out() * 2) / 5;
++
++    return value;
++}
++
++unsigned int pmu_get_apb0_clk(void)
++{
++    return pmu_get_axi_clk() / 8;
++}
++
++unsigned int pmu_get_apb1_clk(void)
++{
++    return pmu_get_axi_clk() / 2;
++}
++
++unsigned int pmu_get_apb2_clk(void)
++{
++    return pmu_get_ahb_clk() / 4;
++}
++
++static unsigned int pmu_get_cpu_clk(void)//FA626
++{
++    u32 value = 0;
++
++    value = pmu_read_pll1out() * 2 / 3;
++
++    return value;
++}
++
++static unsigned int pmu_get_sys_clk(void)
++{
++    return 30*1000000;  //30Mhz
++}
++
++static unsigned int pmu_get_ep_cnt(void)
++{
++    u32 value;
++
++    value = (ftpmu010_read_reg(0xBC) >> 24) & 0xFF;
++
++    if (value > 1)
++        value = 0;  /* uninit value */
++
++    return value;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk",   ATTR_TYPE_AXI,    0}, pmu_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb0_clk},
++    {{"pclk1",  ATTR_TYPE_APB1,   0}, pmu_get_apb1_clk},
++    {{"pclk2",  ATTR_TYPE_APB2,   0}, pmu_get_apb2_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"pll4",   ATTR_TYPE_PLL4,   0}, pmu_read_pll4out},
++    {{"pll5",   ATTR_TYPE_PLL5,   0}, pmu_read_pll5out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++    {{"chipver",   ATTR_TYPE_CHIPVER, 0}, pmu_get_chipversion},
++    {{"sysclk",    ATTR_TYPE_SYSCLK,  0}, pmu_get_sys_clk},
++    {{"pci_epcnt", ATTR_TYPE_EPCNT,   0}, pmu_get_ep_cnt},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(clock_info); tmp ++) {
++            if (clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (clock_info[tmp].clock_fun) {
++                clock_info[tmp].clock.value = clock_info[tmp].clock_fun();
++                ftpmu010_deregister_attr(&clock_info[tmp].clock);
++                ret = ftpmu010_register_attr(&clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++#ifdef CONFIG_GPIO_FTGPIO010
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++#endif
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++    /* register AXI DMAC to pmu core */
++    xdmac_fd = ftpmu010_register_reg(&xdmac_clk_info);
++    if (unlikely(xdmac_fd < 0)){
++        printk("AXI DMAC registers to PMU fail! \n");
++    }
++#endif
++
++    /* cpu interrupt */
++    cpuintr_fd = ftpmu010_register_reg(&cpu_intr_info);
++    if (unlikely(cpuintr_fd < 0)){
++        printk("CPU INTR registers to PMU fail! \n");
++    }
++
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu_fpga.c b/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu_fpga.c
+new file mode 100644
+index 00000000..a2a0bf1a
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu_fpga.c
+@@ -0,0 +1,416 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#ifdef CONFIG_GM8312
++#include <mach/ftpmu010_pcie.h>
++#include <mach/platform/board.h>
++#endif
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int dmac_fd = -1;
++static int cpuintr_fd = -1;
++#ifdef CONFIG_PLATFORM_AXIDMA
++static int xdmac_fd = -1;
++#endif
++
++int ftpmu010_h264e_fd = -1;
++int ftpmu010_h264d_fd = -1;
++int ftpmu010_mcp100_fd = -1;
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count, register (ofs, val, mask) */
++    {FTPMU_H264E_0, 2,     {{0xB0, (0x0 << 25),  (0x1 << 25)}, {0xB0, (0x0 << 3),  (0x1 << 3)}}},
++    {FTPMU_H264E_1, 2,     {{0xB4, (0x0 << 30),  (0x1 << 30)}, {0xB4, (0x0 << 8),  (0x1 << 8)}}},   /* mcp280off */
++    {FTPMU_H264D_0, 2,     {{0xB0, (0x0 << 24),  (0x1 << 24)}, {0xB0, (0x0 << 2),  (0x1 << 2)}}},
++    {FTPMU_H264D_1, 2,     {{0xB4, (0x0 << 29),  (0x1 << 29)}, {0xB4, (0x0 << 3),  (0x1 << 3)}}},   /* mcp300off */    
++    {FTPMU_MCP100_0,1,     {{0xB4, (0x0 << 12),  (0x1 << 12)}}},   /* mcp100off */
++    {FTPMU_3DI_0,   2,     {{0xB0, (0x0 << 22),  (0x1 << 22)}, {0xB0, (0x0 << 15), (0x1 << 15)}}},  /* di3d0off */
++  	{FTPMU_SCALER_0,2,     {{0xB0, (0x0 << 26),  (0x1 << 26)}, {0xB0, (0x0 << 4),  (0x1 << 4)}}},  /* scaroff */
++    {FTPMU_NONE,    0,     {{0x0,   0x0,         0x0}}} /* END, this row is necessary */
++};
++
++/* DMAC 
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK", 
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB, 
++    regDMACArray
++};
++
++/* CPU INTR
++ */
++static pmuReg_t regCPUINTArray[] = {
++ /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++    {0xA8,   0xFFFFFFFF, 0xFFFFFFFF,   0x0,        0x0},
++};
++
++static pmuRegInfo_t cpu_intr_info = {
++    "CPU_INTR",
++    ARRAY_SIZE(regCPUINTArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regCPUINTArray
++};
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++/* AXI DMAC 
++ */
++static pmuReg_t regXDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB0, (0x1 << 19), (0x1 << 19), (0x0 << 19), (0x1 << 19)},
++};
++static pmuRegInfo_t xdmac_clk_info = {
++    "AXI_DMAC_CLK", 
++    ARRAY_SIZE(regXDMACArray),
++    ATTR_TYPE_AXI, 
++    regXDMACArray
++};
++#endif
++
++/* H264E
++ */
++static pmuReg_t regH264EArray[] = {
++    /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x28,      (0x1 << 31), (0x1 << 31),  (0x0 << 31), (0x0 << 31)},
++    {0xA0,      (0x3 << 1), (0x3 << 1),  (0x0 << 1), (0x0 << 1)},   
++    {0xB0,      (0x1 << 25), (0x1 << 25),  (0x0 << 25), (0x0 << 25)},  
++    {0xB0,      (0x1 << 3), (0x1 << 3),  (0x0 << 3), (0x0 << 3)},         
++    {0xB4,      (0x1 << 30), (0x1 << 30),  (0x0 << 30), (0x0 << 30)},
++    {0xB4,      (0x1 << 8), (0x1 << 8),  (0x0 << 8), (0x0 << 8)},    
++};
++static pmuRegInfo_t h264e_clk_info = {
++    "H264E_CLK", 
++    ARRAY_SIZE(regH264EArray),
++    ATTR_TYPE_PLL4,
++    regH264EArray
++};
++
++/* H264D
++ */
++static pmuReg_t regH264DArray[] = {
++    /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x28,      (0x1 << 30), (0x1 << 30),  (0x0 << 30), (0x0 << 30)},
++    {0xA0,      (0x3 << 3), (0x3 << 3),  (0x0 << 3), (0x0 << 3)},   
++    {0xB0,      (0x1 << 24), (0x1 << 24),  (0x0 << 24), (0x0 << 24)},  
++    {0xB0,      (0x1 << 2), (0x1 << 2),  (0x0 << 2), (0x0 << 2)},         
++    {0xB4,      (0x1 << 29), (0x1 << 29),  (0x0 << 29), (0x0 << 29)},
++    {0xB4,      (0x1 << 7), (0x1 << 7),  (0x0 << 7), (0x0 << 7)},    
++};
++static pmuRegInfo_t h264d_clk_info = {
++    "H264D_CLK", 
++    ARRAY_SIZE(regH264DArray),
++    ATTR_TYPE_PLL4,
++    regH264DArray
++};
++
++/* MCP100
++ */
++static pmuReg_t regMCP100Array[] = {
++    /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x28,      (0x1 << 16), (0x1 << 16),  (0x0 << 16), (0x0 << 16)},
++    {0xA0,      (0x1 << 16), (0x1 << 16),  (0x0 << 16), (0x0 << 16)},   
++    {0xB4,      (0x1 << 12), (0x1 << 12),  (0x0 << 12), (0x0 << 12)},
++};
++static pmuRegInfo_t mcp100_clk_info = {
++    "MCP100_CLK", 
++    ARRAY_SIZE(regMCP100Array),
++    ATTR_TYPE_PLL1,
++    regMCP100Array
++};
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	int inc = 0;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 */
++	if (!version) {
++	    
++	    version = ioread32(pmu_base_addr) >> 8;
++	    
++	    switch ((ioread32(pmu_base_addr) >> 5) & 0x7) 
++	    {		
++			case 0 : inc = 0; break;
++			case 2 : inc = 1; break;
++			case 6 : inc = 2; break;
++			case 7 : inc = 3; break;
++			default: inc = 0; break;
++		}
++		if ((version & 0xf0) == 0x10) {
++			/* 8210 series */
++			printk("IC: GM%04x(%c)\n", ((version >> 8) & 0xffff) + inc, (version & 0xff) + 'A' - 0x10);
++		} else {
++			printk("IC: ID not be found\n");
++		}
++	}
++
++	return version;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return (ioread32(pmu_base_addr + 0x30) >> 16);
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++    u32 value = 0;
++  
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 3) & 0x7F;
++    
++    return (SYS_CLK * value);
++}
++
++static inline u32 pmu_read_pll2out(void)
++{
++    printk("GM8210 not use PLL2\n"); 
++    return 0;
++}
++
++static unsigned int pmu_read_pll4out(void)
++{
++    return 768000000;
++}
++
++static unsigned int pmu_read_pll3out(void)
++{
++    u32 mul, value = 0;
++  
++    if(ioread32(pmu_base_addr + 0x28) & (1 << 15)) {
++        printk("PLL3 not support this mode\n");
++    }else{
++  	mul = (ioread32(pmu_base_addr + 0x34) >> 4) & 0xFF;
++  	value = SYS_CLK * mul / 2;
++    }
++    
++    return value * 1000000;
++}
++
++static unsigned int pmu_read_pll5out(void)
++{
++    return 100000000;
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 17) & 0x3;
++    
++    switch(value){
++    case 0:
++  	value = (pmu_read_pll1out() * 2) / 5;
++  	break;
++    case 1:
++  	value = pmu_read_pll1out() / 3;
++  	break;
++    case 2:
++  	value = pmu_read_pll1out() / 4;
++  	break;  	
++    case 3:
++  	value = pmu_read_pll1out() / 5;
++  	break;
++    default:
++  	printk("AHB not support this mode\n");
++  	break;  	  	
++	}  
++	  	
++    return value;
++}
++
++static unsigned int pmu_get_axi_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++  
++    if(value & (1 << 19))
++  	value = pmu_read_pll1out() / 3;
++    else
++  	value = (pmu_read_pll1out() * 2) / 5;
++	
++    return value;
++}
++
++unsigned int pmu_get_apb0_clk(void)
++{
++    return 20000000;//pmu_get_axi_clk() / 2;
++}
++
++unsigned int pmu_get_apb1_clk(void)
++{
++    return 20000000;//pmu_get_axi_clk() / 8;
++}
++
++unsigned int pmu_get_apb2_clk(void)
++{
++    return 20000000;//pmu_get_ahb_clk() / 4;
++}
++
++static unsigned int pmu_get_cpu_clk(void)//FA626
++{
++    u32 value = 0;
++  
++    value = pmu_read_pll1out() * 2 / 3;
++  	 
++    return value;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk",   ATTR_TYPE_AXI,    0}, pmu_get_axi_clk},    
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk}, 
++    //{{"pclk",   ATTR_TYPE_APB,    0}, pmu_get_apb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb0_clk},
++    {{"pclk1",  ATTR_TYPE_APB1,   0}, pmu_get_apb1_clk},
++    {{"pclk2",  ATTR_TYPE_APB2,   0}, pmu_get_apb2_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll2",   ATTR_TYPE_PLL2,   0}, pmu_read_pll2out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"pll4",   ATTR_TYPE_PLL4,   0}, pmu_read_pll4out},
++    {{"pll5",   ATTR_TYPE_PLL5,   0}, pmu_read_pll5out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++
++        /* this attribute exists */
++        if (clock_info[attr].clock_fun) {
++            clock_info[attr].clock.value = clock_info[attr].clock_fun();
++            ftpmu010_deregister_attr(&clock_info[attr].clock);
++            ret = ftpmu010_register_attr(&clock_info[attr].clock);
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{    
++    int i;
++    
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++        
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++    
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++        
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++        
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++    cpuintr_fd = ftpmu010_register_reg(&cpu_intr_info);
++    if (unlikely(cpuintr_fd < 0)){
++        printk("CPU INTR registers to PMU fail! \n");
++    }
++    
++#ifdef CONFIG_PLATFORM_AXIDMA
++    /* register AXI DMAC to pmu core */
++    xdmac_fd = ftpmu010_register_reg(&xdmac_clk_info);
++    if (unlikely(xdmac_fd < 0)){
++        printk("AXI DMAC registers to PMU fail! \n");
++    }
++#endif 
++
++#ifdef CONFIG_GM8312
++    ftpmu010_pcie_init((void *)PCIPMU_FTPMU010_VA_BASE);
++#endif
++
++    ftpmu010_h264e_fd = ftpmu010_register_reg(&h264e_clk_info);
++    if (unlikely(ftpmu010_h264e_fd < 0)){
++        printk("H264 Enc registers to PMU fail! \n");
++    }
++
++    ftpmu010_h264d_fd = ftpmu010_register_reg(&h264d_clk_info);
++    if (unlikely(ftpmu010_h264d_fd < 0)){
++        printk("H264 Dec registers to PMU fail! \n");
++    }
++        
++    ftpmu010_mcp100_fd = ftpmu010_register_reg(&mcp100_clk_info);
++    if (unlikely(ftpmu010_mcp100_fd < 0)){
++        printk("MCP100 registers to PMU fail! \n");
++    }
++          
++    return 0;
++}
++
++EXPORT_SYMBOL(ftpmu010_h264e_fd);
++EXPORT_SYMBOL(ftpmu010_h264d_fd);
++EXPORT_SYMBOL(ftpmu010_mcp100_fd);
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file 
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu_pcie.c b/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu_pcie.c
+new file mode 100644
+index 00000000..880af716
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-S/pmu_pcie.c
+@@ -0,0 +1,191 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++#include <mach/ftpmu010_pcie.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int gm8312_fd = -1;
++static int cpuintr_fd = -1;
++
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_pcie_gate_clk_t pcie_gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_PCIE_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++
++    /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++static pmuPcieReg_t reg8312Array[] = {
++    /* Enable dmac CLK, ahbc CLK, PCIE_AXI_BRG */
++    {0x30, (0x1 << 8) | (0x1 << 10) | (0x1 << 13), (0x1 << 8) | (0x1 << 10) | (0x1 << 13), 0x0, (0x1 << 8) | (0x1 << 10) | (0x1 << 13)},
++
++    /* Enable AXIC_APB_CLK, X2H APB CLK, INTC CLK, H2X APB CLK, PCIE_AXI_BRG, H2X7_APB_CLK */
++    {0x34, (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 << 16) | (0x3 << 23), (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 <<16) |  (0x3 << 23), 0x0, (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 << 16) | (0x3 << 23)},
++};
++static pmuPcieRegInfo_t gm8312_clk_info = {
++    "8312_clk",
++    ARRAY_SIZE(reg8312Array),
++    ATTR_TYPE_PCIE_NONE, /* no clock source */
++    reg8312Array
++};
++
++static unsigned int pmu_pcie_get_version(void)
++{
++	static unsigned int version = 0;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 */
++	if (!version) {
++
++	    version = ioread32(pmu_base_addr) >> 8;
++		printk("IC: GM%04x(%c)\n", ((version >> 8) & 0xffff), (version & 0xff) + 'A' - 0x10);
++	}
++
++	return version;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_pcie_read_pll1out(void)
++{
++    u32 value = 0, pll_ns, pll_ms;
++
++    value = ioread32(pmu_base_addr + 0x08);
++    pll_ns = (value >> 2) & 0xFF;
++    pll_ms = (value >> 10) & 0x1F;
++
++    return (SYS_CLK * pll_ns / pll_ms);
++}
++
++static unsigned int pmu_pcie_get_axi_clk(void)
++{
++    return pmu_pcie_read_pll1out() / 2;
++}
++
++static unsigned int pmu_pcie_get_ahb_clk(void)
++{
++    return pmu_pcie_read_pll1out() / 2;
++}
++
++unsigned int pmu_pcie_get_apb_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x34);
++    value = (value >> 26) & 0x1F;
++
++    return pmu_pcie_get_ahb_clk() / (value + 1);
++}
++
++struct clock_s
++{
++    attrPcieInfo_t   clock;
++    u32         (*clock_fun)(void);
++} pcie_clock_info[] = {
++    {{"aclk",   ATTR_TYPE_PCIE_AXI,    0}, pmu_pcie_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_PCIE_AHB,    0}, pmu_pcie_get_ahb_clk},
++    {{"pclk",   ATTR_TYPE_PCIE_APB,    0}, pmu_pcie_get_apb_clk},
++    {{"pll1",   ATTR_TYPE_PCIE_PLL1,   0}, pmu_pcie_read_pll1out},
++    {{"pmuver", ATTR_TYPE_PCIE_PMUVER, 0}, pmu_pcie_get_version},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_PCIE_TYPE_T attr = (ATTR_PCIE_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(pcie_clock_info); tmp ++) {
++            if (pcie_clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (pcie_clock_info[tmp].clock_fun) {
++                pcie_clock_info[tmp].clock.value = pcie_clock_info[tmp].clock_fun();
++                ftpmu010_pcie_deregister_attr(&pcie_clock_info[tmp].clock);
++                ret = ftpmu010_pcie_register_attr(&pcie_clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_pcie_postinit(void)
++{
++    int i;
++
++    printk("PCIE PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_pcie_init(pmu_base_addr, &pcie_gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(pcie_clock_info); i ++)
++    {
++        if (pcie_clock_info[i].clock_fun)
++            pcie_clock_info[i].clock.value = pcie_clock_info[i].clock_fun();
++
++        ftpmu010_pcie_register_attr(&pcie_clock_info[i].clock);
++    }
++
++    /* register GM8312 bus to pmu core */
++    gm8312_fd = ftpmu010_pcie_register_reg(&gm8312_clk_info);
++    if (unlikely(gm8312_fd < 0)){
++        printk("GM8312 CLK registers to PMU fail! \n");
++    }
++
++    return 0;
++}
++
++arch_initcall(pmu_pcie_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_pcie_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210-S/timer_fixup.c b/arch/arm/mach-GM-Duo/platform-GM8210-S/timer_fixup.c
+new file mode 100644
+index 00000000..66920651
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210-S/timer_fixup.c
+@@ -0,0 +1,128 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/ftpmu010.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/fiq.h>
++#include <mach/platform/board.h>
++
++#define CONFIG_MAX_TICK     0xffffffff
++static int timer_init_ready = 0;
++
++/*
++ * Get the max ms the this timer
++ */
++unsigned int video_gettime_max_ms(void)
++{
++    return (CONFIG_MAX_TICK / APB0_CLK_IN) * 1000;
++}
++
++/* calculate the max hz in max_ms
++ */
++unsigned int video_gettime_max_hz(void)
++{
++    unsigned int max_hz;
++
++    /* calculate the max hz in max_ms. Actually it is (video_gettime_max_ms() / 1000) * APB0_CLK_IN
++     */
++    max_hz = video_gettime_max_ms() * (APB0_CLK_IN / 1000);
++
++    return max_hz;
++}
++
++unsigned int video_gettime_ms(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++unsigned int video_gettime_us(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++
++        return (value - tick_diff) / (ft_apb_clk / 1000000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++/*
++ * Entry Point of this module. It may be declared by arch_initcall section
++ */
++static int __init fixup_timer_init(void)
++{
++    //use timer3, 42s will overflow in AHB clock 200HZ
++    unsigned int ft_apb_clk = APB0_CLK_IN;
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++    unsigned int max_tick;
++
++    if (*(unsigned int *)(timer_base + 0x30) & (0x1 << 6))
++    {
++        printk("Timer3 is alredy been used!\n");
++        return 0;
++    }
++
++    max_tick = video_gettime_max_ms() * (ft_apb_clk / 1000);    //the max hz count in TmxCounter
++
++    printk("Video Timer(timer3) Max %dms in 0x%x HZ.\n", video_gettime_max_ms(), max_tick);
++
++    /* the following configuration is for TIMER3 */
++    *(volatile unsigned int *)(timer_base + 0x20) = CONFIG_MAX_TICK - max_tick; //keep the start count in start counter
++    *(volatile unsigned int *)(timer_base + 0x24) = CONFIG_MAX_TICK - max_tick; //reLoad counter
++    *(volatile unsigned int *)(timer_base + 0x38) |= (0x7 << 6);   //IRQ disable
++    *(volatile unsigned int *)(timer_base + 0x30) |= ((0x1 << 6) | (0x1 << 11));    //enable timer3, count up
++    timer_init_ready = 1;
++
++    return 0;
++}
++
++static void fixup_timer_exit(void)
++{
++    if (timer_init_ready == 1)
++    {
++        unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        *(volatile unsigned int *)(timer_base + 0x30) &= ~(0x1 << 6);//disable timer2, count up
++        timer_init_ready = 0;
++    }
++	printk("%s: cleaning up\n",__func__);
++}
++
++module_init(fixup_timer_init);
++module_exit(fixup_timer_exit);
++
++EXPORT_SYMBOL(video_gettime_ms);
++EXPORT_SYMBOL(video_gettime_us);
++EXPORT_SYMBOL(video_gettime_max_ms);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("FIXUP timer driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210/Kconfig b/arch/arm/mach-GM-Duo/platform-GM8210/Kconfig
+new file mode 100644
+index 00000000..ed8afe22
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210/Kconfig
+@@ -0,0 +1,52 @@
++#
++# arch/arm/mach-GM/platform-GM8210/Kconfig
++
++if PLATFORM_GM8210
++
++#config SYS_CLK
++config CLOCK_TICK_RATE
++        int "AHB System Clock"
++        default 33000000
++        help
++            Any fake value is ok. It almost obsolete.
++
++config GM8210_TIMER_HZ
++    int "HZ of GM8210"
++    range 100 1000
++    default 1000
++    help
++      HZ defined in GM8210 platform
++
++config PLATFORM_AXIDMA
++	bool "AXI DMA support"
++	default y
++
++config FTINTC030
++	bool "FTINTC030 support"
++	default y
++
++config FTINTC010EX
++	bool "FTINTC010EX supports 64 IRQs"
++	default y
++
++config FA626
++    bool "FA626 support"
++    default y
++
++config FC7500
++    bool "FC7500 support"
++    default y
++
++config GM8312
++	bool "GM8312 support"
++	default y
++
++config GM8210_EP_MODE
++    bool "Dual GM8210 EP mode"
++    default n
++
++config GM8210_FPGA
++	bool "FPGA Verify"
++	default n
++
++endif
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210/Makefile b/arch/arm/mach-GM-Duo/platform-GM8210/Makefile
+new file mode 100644
+index 00000000..5a158282
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210/Makefile
+@@ -0,0 +1,11 @@
++#
++# Makefile for the GM platform dependent files
++
++# Object file lists.
++
++ifeq ($(CONFIG_GM8210_FPGA),y)
++obj-y		:= board.o pmu_fpga.o timer_fixup.o platform.o
++else
++obj-y		:= board.o pmu.o timer_fixup.o platform.o
++obj-$(CONFIG_GM8312)   += pmu_pcie.o 
++endif
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210/board.c b/arch/arm/mach-GM-Duo/platform-GM8210/board.c
+new file mode 100644
+index 00000000..30e9a0f3
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210/board.c
+@@ -0,0 +1,639 @@
++/*
++ *  board depdenent initialization
++ *
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/setup.h>
++#include <asm/io.h>
++#include <asm/cputype.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <mach/platform/board.h>
++#include <mach/platform/pmu.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/system.h>
++#ifdef CONFIG_GM8312
++#include <mach/ftintc010.h>
++#include <mach/platform/pmu_pcie.h>
++#endif
++#include <mach/ftintc030.h>
++#include <mach/fttmr010.h>
++#ifdef CONFIG_FTDMAC030
++#include <mach/ftdmac030.h>
++#endif
++
++#include <mach/fmem.h>
++#include <linux/dma-mapping.h>
++
++/* External functions and variables declaration
++ */
++extern void platform_devices_init(void);
++
++/* Local variables declaration
++ */
++void __iomem *ftintc030_base_addr;
++void __iomem *ftintc030_base_cpu_0_irq_base; //entry-macro.S will reference it
++void __iomem *ftintc030_base_cpu_1_irq_base; //entry-macro.S will reference it
++
++#ifdef CONFIG_GM8312
++void __iomem *ftintc010_base_addr;
++#endif
++
++static fmem_pci_id_t  pci_id = -1;
++static fmem_cpu_id_t  cpu_id = -1;
++
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++#ifdef CONFIG_FTDMAC030
++/*
++ * DMAC030 channel filter.
++ */
++static int board_dmac030_chan_filter(int chan_id)
++{
++    int ret = 0;
++
++    if (get_cpu_id() == 0x726) {
++        if (pci_id == -1)
++            fmem_get_identifier(&pci_id, &cpu_id);
++
++        /* Master CPU only can use 0-3 */
++        if (chan_id >= 4)
++            ret = -1;
++        else
++            ret = 0;
++
++        /* EP, chan_id 3 is used for 2ddma */
++        if ((pci_id != FMEM_PCI_HOST) && (chan_id == 3))
++            ret = -1;
++    } else {
++        /* FA626 CPU only can use 4, 5. 6 and 7 are used for cpu_comm */
++        if (chan_id >= 4)
++            ret = 0;
++        else
++            ret = -1;
++    }
++
++    return ret;
++}
++#endif /* CONFIG_FTDMAC030 */
++
++/******************************************************************************
++ * IPs virtual address mapping
++ *****************************************************************************/
++static struct map_desc board_io_desc[] __initdata = {
++    /* PMU */
++    {
++        .virtual	= PMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PMU_FTPMU010_PA_BASE),
++		.length		= PMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART0 */
++    {
++        .virtual	= UART_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_0_PA_BASE),
++		.length		= UART_FTUART010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART1 */
++    {
++        .virtual    = UART_FTUART010_1_VA_BASE,
++        .pfn        = __phys_to_pfn(UART_FTUART010_1_PA_BASE),
++        .length     = UART_FTUART010_1_VA_SIZE,
++        .type       = MT_DEVICE,
++    },
++    /* UART2 */
++    {
++        .virtual	= UART_FTUART010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_2_PA_BASE),
++		.length		= UART_FTUART010_2_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART3 */
++    {
++        .virtual	= UART_FTUART010_3_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_3_PA_BASE),
++		.length		= UART_FTUART010_3_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART4 */
++    {
++        .virtual	= UART_FTUART010_4_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_4_PA_BASE),
++		.length		= UART_FTUART010_4_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART5 */
++    {
++        .virtual	= UART_FTUART010_5_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_5_PA_BASE),
++		.length		= UART_FTUART010_5_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* TIMER0 */
++    {
++        .virtual	= TIMER_FTTMR010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_0_PA_BASE),
++		.length		= TIMER_FTTMR010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* TIMER2 */
++    {
++        .virtual	= TIMER_FTTMR010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_2_PA_BASE),
++		.length		= TIMER_FTTMR010_2_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC030 */
++    {
++        .virtual	= INTC_FTINTC030_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC030_PA_BASE),
++		.length		= INTC_FTINTC030_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#ifdef CONFIG_GM8312
++    /* PCI_PMU */
++    {
++        .virtual	= PCIPMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PCIPMU_FTPMU010_PA_BASE),
++		.length		= PCIPMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC010 */
++    {
++        .virtual	= INTC_FTINTC010_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC010_PA_BASE),
++		.length		= INTC_FTINTC010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#endif
++};
++
++/* fixup the memory for MACHINE_START. The parameters come from commandline of menuconfig
++ */
++static void __init board_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    fmem_fixup_memory(tag, cmdline, mi);
++}
++
++/* 2. create the iotable for IPs in MACHINE_START
++ */
++static void __init board_map_io(void)
++{
++    iotable_init(&board_io_desc[0], ARRAY_SIZE(board_io_desc));
++
++    /* set the base to pmu module */
++    pmu_earlyinit((void *)PMU_FTPMU010_VA_BASE);
++#ifdef CONFIG_GM8312
++    pmu_pcie_earlyinit((void *)PCIPMU_FTPMU010_VA_BASE);
++#endif
++    /* init dma coherent mapping size,
++     * CONSISTENT_DMA_SIZE is defined in memory.h
++     * max allowable dma consistent size is 14M (0xFFE0_0000 - 0xFF00_00000)
++     * set as 12M to avoid unexpected data overlay, NISH_20121015
++     */
++    #ifdef CONSISTENT_DMA_SIZE
++    init_consistent_dma_size(CONSISTENT_DMA_SIZE);
++    #endif
++}
++
++#ifdef CONFIG_GM8312
++/* HDCP of HDMI is useless, so we use the last 16 bytes as the memory destination
++ * format: [0]init_done value, [4]who owned the key, [8]lock/unlock value, [c]: how long
++ */
++typedef struct {
++    unsigned int init_done;
++    unsigned int lock;
++    unsigned int owner;
++    unsigned int wait_cnt;
++    unsigned int lock_cnt;
++    unsigned int statistic;   /* statistic only */
++    unsigned int last_freer;
++    unsigned int reserved[1];
++} lock_content_t;
++
++#define LOCK_VAL        0xAAAA0000
++#define UNLOCK_VAL      0x00005555
++#define INIT_DONE       0x00112233
++#define LOCK_OWNER      get_cpu_id() //0x000FA726
++
++static unsigned int hdmi_va;
++
++static void board_bus_lock_vainit(void)
++{
++    void *vaddr, *vaddr2;
++    volatile u32 paddr;
++
++    /* memory clear was done in uboot */
++    hdmi_va = (unsigned int)ioremap_nocache(HDMI_FTHDCPMEM_PA_BASE, 512);
++    if (!hdmi_va)
++        panic("Error to allocate va! \n");
++
++    if (pci_id == -1)
++        fmem_get_identifier(&pci_id, &cpu_id);
++
++    switch (pci_id) {
++      case FMEM_PCI_HOST:
++        if (cpu_id == FMEM_CPU_FA726) {
++            /* provide the memory */
++            vaddr = (void *)kmalloc(PAGE_SIZE, GFP_KERNEL);
++            if (!vaddr) panic("%s, error! \n", __func__);
++
++            paddr = __pa(vaddr);
++            vaddr2 = (void *)ioremap(paddr, PAGE_SIZE);
++            memset(vaddr2, 0, PAGE_SIZE);
++            iowrite32(paddr, hdmi_va);
++            /* new hdmi_va */
++            hdmi_va = (unsigned int)vaddr2;
++        } else {
++            while ((paddr = ioread32(hdmi_va)) == 0)
++                udelay(100);
++            hdmi_va = (unsigned int)ioremap(paddr, PAGE_SIZE);
++            if (!hdmi_va) panic("%s, error2! \n", __func__);
++        }
++        break;
++
++      case FMEM_PCI_DEV0:
++        if (cpu_id == FMEM_CPU_FA726) {
++            /* provide the memory */
++            vaddr = (void *)kmalloc(PAGE_SIZE, GFP_KERNEL);
++            if (!vaddr) panic("%s, error! \n", __func__);
++            memset(vaddr, 0, PAGE_SIZE);
++            paddr = __pa(vaddr);
++            iowrite32(paddr, hdmi_va + 0x4);
++            /* new hdmi_va */
++            hdmi_va = (unsigned int)vaddr;
++        } else {
++            while ((paddr = ioread32(hdmi_va + 0x4)) == 0)
++                udelay(100);
++            hdmi_va = (unsigned int)ioremap(paddr, PAGE_SIZE);
++            if (!hdmi_va) panic("%s, error2! \n", __func__);
++        }
++        break;
++
++      default:
++        panic("%s, no such pci role! \n", __func__);
++        break;
++    }
++}
++
++void board_bus_lock_init(bus_lock_t bus)
++{
++    volatile int i;
++    volatile u32 base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE) {
++        memset((char *)content, 0, sizeof(lock_content_t));
++        content->lock = UNLOCK_VAL;
++        content->init_done = INIT_DONE;
++    }
++
++    //delay a while prevent from multiple CPUs re-entrant
++    for (i = 0; i < 0x100; i ++)
++        ioread32(hdmi_va);
++}
++EXPORT_SYMBOL(board_bus_lock_init);
++
++void board_bus_lock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setlock = LOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner == LOCK_OWNER) {
++        content->lock_cnt ++;
++        content->statistic ++;
++        return;
++    }
++
++    ptr = base + 4;
++re_try:
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setlock), "r" (ptr)
++                : "memory", "cc");
++    if (retval != UNLOCK_VAL) {
++        if (irqs_disabled() || in_interrupt())
++	    udelay(100);
++	else
++	    msleep(1);
++        content->wait_cnt ++;
++        goto re_try;
++    }
++
++    content->owner = LOCK_OWNER;
++    content->lock_cnt ++;
++    content->statistic ++;
++    content->wait_cnt = 0;
++    content->last_freer = 0;
++}
++EXPORT_SYMBOL(board_bus_lock);
++
++void board_bus_unlock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setunlock = UNLOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner != LOCK_OWNER)
++        panic("the locker:%d has wrong owner:0x%x! \n", bus, content->owner);
++
++    content->lock_cnt --;
++    if (content->lock_cnt)
++        return;
++
++    content->owner = 0;   //no owner
++    content->last_freer = LOCK_OWNER;
++
++    ptr = base + 4;
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setunlock), "r" (ptr)
++                : "memory", "cc");
++
++    if (retval != LOCK_VAL) {
++        int i;
++
++        for (;;) {
++            printk("Error value 0x%x in locker:%d! \n", retval, bus);
++            msleep(990);
++
++            for (i = 0; i < 8; i ++)
++                printk("content[%d] = 0x%x \n", i, ioread32(base + i * 4));
++        }
++    }
++}
++EXPORT_SYMBOL(board_bus_unlock);
++
++/* return value:
++ *  -1 for fail which means the bus was locked by others
++ *  0 for grab the lock success
++ */
++int board_bus_trylock(bus_lock_t bus)
++{
++    volatile unsigned int retval;
++    volatile unsigned int setlock = LOCK_VAL;
++    volatile unsigned int ptr, base = hdmi_va + bus * sizeof(lock_content_t);
++    volatile lock_content_t  *content = (lock_content_t *)base;
++
++    if (content->init_done != INIT_DONE)
++        panic("the locker:%d didn't call init! \n", bus);
++
++    if (content->owner == LOCK_OWNER) {
++        content->lock_cnt ++;
++        content->statistic ++;
++        return 0;
++    }
++
++    ptr = base + 4;
++
++    __asm__ __volatile__("swp %0, %1, [%2]"
++                : "=&r"(retval)
++                : "r" (setlock), "r" (ptr)
++                : "memory", "cc");
++    if (retval != UNLOCK_VAL)
++        return -1;
++
++    content->owner = LOCK_OWNER;
++    content->lock_cnt ++;
++    content->statistic ++;
++    content->wait_cnt = 0;
++    content->last_freer = 0;
++
++    return 0;
++}
++EXPORT_SYMBOL(board_bus_trylock);
++#endif /* CONFIG_GM8312 */
++
++static void __init board_init_irq(void)
++{
++	struct ftintc030_trigger_type master_trigger_type = {
++		.irqmode[0]	= PLATFORM_IRQ_TRIGGER_MODE1,
++		.irqlevel[0]	= ~PLATFORM_IRQ_TRIGGER_LEVEL1,
++		.fiqmode[0]	= PLATFORM_FIQ_TRIGGER_MODE1,
++		.fiqlevel[0]	= ~PLATFORM_FIQ_TRIGGER_LEVEL1,
++
++		.irqmode[1]	= PLATFORM_IRQ_TRIGGER_MODE2,
++		.irqlevel[1]	= ~PLATFORM_IRQ_TRIGGER_LEVEL2 | (1 << (EXT_INT_0_IRQ - 32)),
++		.fiqmode[1]	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel[1]	= ~PLATFORM_FIQ_TRIGGER_LEVEL2 | (1 << (EXT_INT_0_IRQ - 32)),
++
++		.irqmode[2]	= PLATFORM_IRQ_TRIGGER_MODE3,
++		.irqlevel[2]	= ~PLATFORM_IRQ_TRIGGER_LEVEL3,
++		.fiqmode[2]	= PLATFORM_FIQ_TRIGGER_MODE3,
++		.fiqlevel[2]	= ~PLATFORM_FIQ_TRIGGER_LEVEL3,
++
++		.irqmode[3]	= PLATFORM_IRQ_TRIGGER_MODE4,
++		.irqlevel[3]	= ~PLATFORM_IRQ_TRIGGER_LEVEL4,
++		.fiqmode[3]	= PLATFORM_FIQ_TRIGGER_MODE4,
++		.fiqlevel[3]	= ~PLATFORM_FIQ_TRIGGER_LEVEL4,
++
++		.irqmode[4]	= PLATFORM_IRQ_TRIGGER_MODE5,
++		.irqlevel[4]	= ~PLATFORM_IRQ_TRIGGER_LEVEL5,
++		.fiqmode[4]	= PLATFORM_FIQ_TRIGGER_MODE5,
++		.fiqlevel[4]	= ~PLATFORM_FIQ_TRIGGER_LEVEL5,
++
++		.irqmode[5]	= PLATFORM_IRQ_TRIGGER_MODE6,
++		.irqlevel[5]	= ~PLATFORM_IRQ_TRIGGER_LEVEL6,
++		.fiqmode[5]	= PLATFORM_FIQ_TRIGGER_MODE6,
++		.fiqlevel[5]	= ~PLATFORM_FIQ_TRIGGER_LEVEL6,
++
++		.irqmode[6]	= PLATFORM_IRQ_TRIGGER_MODE7,
++		.irqlevel[6]	= ~PLATFORM_IRQ_TRIGGER_LEVEL7,
++		.fiqmode[6]	= PLATFORM_FIQ_TRIGGER_MODE7,
++		.fiqlevel[6]	= ~PLATFORM_FIQ_TRIGGER_LEVEL7,
++
++		.irqmode[7]	= PLATFORM_IRQ_TRIGGER_MODE8,
++		.irqlevel[7]	= ~PLATFORM_IRQ_TRIGGER_LEVEL8,
++		.fiqmode[7]	= PLATFORM_FIQ_TRIGGER_MODE8,
++		.fiqlevel[7]	= ~PLATFORM_FIQ_TRIGGER_LEVEL8,
++	};
++
++#ifdef CONFIG_GM8312
++	struct ftintc010_trigger_type pcie_trigger_type = {
++		.irqmode	= PLATFORM_IRQ_TRIGGER_MODE2 | (0x1 << 8), /* hdmi edge trigger */
++		.irqlevel	= ~PLATFORM_IRQ_TRIGGER_LEVEL2,
++		.fiqmode	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel	= ~PLATFORM_FIQ_TRIGGER_LEVEL2,
++#ifdef CONFIG_FTINTC010EX
++        	.irqmodeex	= PLATFORM_IRQ_TRIGGER_MODEEX2,
++		.irqlevelex	= ~PLATFORM_IRQ_TRIGGER_LEVELEX2,
++		.fiqmodeex	= PLATFORM_FIQ_TRIGGER_MODEEX2,
++		.fiqlevelex	= ~PLATFORM_FIQ_TRIGGER_LEVELEX2,
++#endif
++	};
++#endif
++	/*
++	 * initialize primary interrupt controller
++	 */
++	ftintc030_base_addr = __io(INTC_FTINTC030_VA_BASE);
++    if (get_cpu_id() == 0x726)
++	    ftintc030_base_cpu_0_irq_base = __io(INTC_FTINTC030_VA_BASE + FTINTC030_OFFSET_CPU_0_IRQ);
++    else
++	    ftintc030_base_cpu_1_irq_base = __io(INTC_FTINTC030_VA_BASE + FTINTC030_OFFSET_CPU_1_IRQ);
++
++	ftintc030_init(0, ftintc030_base_addr, 0, &master_trigger_type);
++
++#ifdef CONFIG_GM8312
++    if (((ioread32(PMU_FTPMU010_VA_BASE + 0x04) >> 19) & 0x3) != 0x02) // if role is not PCIe RC
++        return;
++
++    if (get_cpu_id() == 0x726) {
++    	ftintc010_base_addr = __io(INTC_FTINTC010_VA_BASE);
++    	ftintc010_init(0, ftintc010_base_addr, PLATFORM_IRQ_TOTALCOUNT, &pcie_trigger_type);
++    	if (1) {
++    	    /* Enable prefetch for H2XBrg_7 for DMAC.
++    	     * Limitation: If read through AXI-PCIe controller IP�Aread data width < 64 bit,
++    	     * burst length only can be "1". Thus we enable pre-fetech function to solve this issue.
++    	     */
++    	    void *vbase;
++    	    u32 tmp;
++
++    	    vbase = (void *)ioremap_nocache(PCIE_H2XBRG_7_PA_BASE, PCI3_H2SBRG_7_PA_SIZE);
++    	    tmp = ioread32(vbase) & ~(0x7 << 4);    // bit [6:4] (prefetch number)
++    	    tmp |= ((0xA << 16) | (0x2 << 4));  //suggest from Kay, 2013/3/27 10:57AM
++    	    iowrite32(tmp, vbase);
++            __iounmap(vbase);
++    	}
++    }
++#endif
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_0_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_0_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_0_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_0_VA_BASE,
++	.id	= 1,
++};
++
++static struct fttmr010_clockevent fttmr010_2_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_2_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_2_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_2_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_2_VA_BASE,
++	.id	= 1,
++};
++
++static void __init board_sys_timer_init(void)
++{
++    unsigned int pclk = pmu_get_apb0_clk();
++	printk("Timer use APB0 clock\n");
++
++    if (get_cpu_id() == 0x726) {
++    	fttmr010_0_0_clockevent.freq = pclk;
++    	fttmr010_clockevent_init(&fttmr010_0_0_clockevent);
++
++    	fttmr010_0_1_clocksource.freq = pclk;
++    	fttmr010_clocksource_init(&fttmr010_0_1_clocksource);
++    } else {
++    	fttmr010_2_0_clockevent.freq = pclk;
++    	fttmr010_clockevent_init(&fttmr010_2_0_clockevent);
++
++    	fttmr010_2_1_clocksource.freq = pclk;
++    	fttmr010_clocksource_init(&fttmr010_2_1_clocksource);
++    }
++}
++
++struct sys_timer board_sys_timer = {
++	.init	= board_sys_timer_init,
++};
++
++/* board init */
++static void __init board_init_machine(void)
++{
++    int i, vaddr_8210, vaddr_8312;
++
++#ifdef CONFIG_GM8312
++    board_bus_lock_vainit();
++#endif
++
++    platform_devices_init();
++
++    /* dump iotable information
++     */
++    for (i = 0; i < ARRAY_SIZE(board_io_desc); i ++) {
++        printk("iotable: VA: 0x%x, PA: 0x%x, Length: %d \n",
++                (u32)board_io_desc[i].virtual,
++                (u32)board_io_desc[i].pfn << PAGE_SHIFT,
++                (u32)board_io_desc[i].length);
++    }
++
++    /* for debug 8312 purpose */
++    vaddr_8210 = (u32)ioremap(PCIE_PLDA_PA_BASE, PAGE_SIZE);
++    vaddr_8312 = (u32)ioremap(PCIE_PCIE_PLDA_PA_BASE, PAGE_SIZE);
++    printk("8210 PCIE: 0x%x(0x%x), 8312 PCIE: 0x%x(0x%x) \n", vaddr_8210, PCIE_PLDA_PA_BASE,
++                    vaddr_8312, PCIE_PCIE_PLDA_PA_BASE);
++
++#ifdef CONFIG_FTDMAC030
++    ftdmac030_set_platform_chanfilter(board_dmac030_chan_filter);
++#endif
++}
++
++MACHINE_START(GM, BOARD_NAME)
++	.atag_offset	= BOOT_PARAMETER_PA_OFFSET,   //boot command line, after kernel 3.2 change as relative address
++	.map_io		    = board_map_io,
++	.init_irq	    = board_init_irq,
++	.timer		    = &board_sys_timer,
++	.fixup          = board_fixup_memory,
++	.init_machine	= board_init_machine,
++	.restart	= arch_reset,
++MACHINE_END
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210/platform.c b/arch/arm/mach-GM-Duo/platform-GM8210/platform.c
+new file mode 100644
+index 00000000..9ba4ac9a
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210/platform.c
+@@ -0,0 +1,620 @@
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/dma-mapping.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach-types.h>
++#include <mach/platform/board.h>
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++#if defined(CONFIG_I2C0_IP) || defined(CONFIG_GM8210_FPGA)
++/* i2c:0 */
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start  = I2C_FTI2C010_0_PA_BASE,
++		.end    = I2C_FTI2C010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_0_IRQ,
++		.end	= I2C_FTI2C010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		    = 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C1_IP
++/* i2c:1 */
++static struct resource ftiic010_1_resources[] = {
++	{
++		.start  = I2C_FTI2C010_1_PA_BASE,
++		.end    = I2C_FTI2C010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_1_IRQ,
++		.end	= I2C_FTI2C010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_1_device = {
++	.name		= "ftiic010",
++	.id		    = 1,
++	.num_resources	= ARRAY_SIZE(ftiic010_1_resources),
++	.resource	= ftiic010_1_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C2_IP
++/* i2c:2 */
++static struct resource ftiic010_2_resources[] = {
++	{
++		.start  = I2C_FTI2C010_2_PA_BASE,
++		.end    = I2C_FTI2C010_2_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_2_IRQ,
++		.end	= I2C_FTI2C010_2_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_2_device = {
++	.name		= "ftiic010",
++	.id		    = 2,
++	.num_resources	= ARRAY_SIZE(ftiic010_2_resources),
++	.resource	= ftiic010_2_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C3_IP
++/* i2c:3 */
++static struct resource ftiic010_3_resources[] = {
++	{
++		.start  = I2C_FTI2C010_3_PA_BASE,
++		.end    = I2C_FTI2C010_3_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_3_IRQ,
++		.end	= I2C_FTI2C010_3_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_3_device = {
++	.name		= "ftiic010",
++	.id		    = 3,
++	.num_resources	= ARRAY_SIZE(ftiic010_3_resources),
++	.resource	= ftiic010_2_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C4_IP
++/* i2c:4 */
++static struct resource ftiic010_4_resources[] = {
++	{
++		.start  = I2C_FTI2C010_4_PA_BASE,
++		.end    = I2C_FTI2C010_4_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_4_IRQ,
++		.end	= I2C_FTI2C010_4_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_4_device = {
++	.name		= "ftiic010",
++	.id		    = 4,
++	.num_resources	= ARRAY_SIZE(ftiic010_4_resources),
++	.resource	= ftiic010_4_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C5_IP
++/* i2c:5 */
++static struct resource ftiic010_5_resources[] = {
++	{
++		.start  = I2C_FTI2C010_5_PA_BASE,
++		.end    = I2C_FTI2C010_5_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_5_IRQ,
++		.end	= I2C_FTI2C010_5_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_5_device = {
++	.name		= "ftiic010",
++	.id		    = 5,
++	.num_resources	= ARRAY_SIZE(ftiic010_5_resources),
++	.resource	= ftiic010_5_resources,
++};
++#endif
++
++/******************************************************************************
++ * USB hosts
++ *****************************************************************************/
++#ifdef CONFIG_GM_FOTG2XX
++/* OTG:0 */
++static struct resource fotg210_0_resources[] = {
++	{
++		.start  = USB_FOTG2XX_0_PA_BASE,
++		.end    = USB_FOTG2XX_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_0_IRQ,
++		.end    = USB_FOTG2XX_0_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_0_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_0_device = {
++	.name           = "fotg210",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(fotg210_0_resources),
++	.resource       = fotg210_0_resources,
++	.dev = {
++		.dma_mask = &fotg210_0_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++/* OTG:1 */
++struct resource fotg210_1_resources[] = {
++	{
++		.start  = USB_FOTG2XX_1_PA_BASE,
++		.end    = USB_FOTG2XX_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_1_IRQ,
++		.end    = USB_FOTG2XX_1_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_1_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_1_device = {
++	.name           = "fotg210",
++	.id             = 1,
++	.num_resources  = ARRAY_SIZE(fotg210_1_resources),
++	.resource       = fotg210_1_resources,
++	.dev = {
++		.dma_mask = &fotg210_1_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++/* OTG:2 */
++static struct resource fotg210_2_resources[] = {
++	{
++		.start  = USB_FOTG2XX_2_PA_BASE,
++		.end    = USB_FOTG2XX_2_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_2_IRQ,
++		.end    = USB_FOTG2XX_2_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_2_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_2_device = {
++	.name           = "fotg210",
++//    .name           = "usb1.1",
++	.id             = 2,
++	.num_resources  = ARRAY_SIZE(fotg210_2_resources),
++	.resource       = fotg210_2_resources,
++	.dev = {
++		.dma_mask = &fotg210_2_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif
++
++/* FTSDC021 */
++static struct resource ftsdc021_resource[] = {
++	[0] = {
++	       .start = SDC_FTSDC021_PA_BASE,
++	       .end = SDC_FTSDC021_PA_LIMIT,
++	       .flags = IORESOURCE_MEM,
++	       },
++	[1] = {
++	       .start = SDC_FTSDC021_0_IRQ,
++	       .end = SDC_FTSDC021_0_IRQ,
++	       .flags = IORESOURCE_IRQ,
++	       }
++};
++static u64 ftsdc021_dmamask = 0xFFFFFFUL;
++static struct platform_device ftsdc021_device = {
++	.name = "ftsdc021",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(ftsdc021_resource),
++	.resource = ftsdc021_resource,
++	.dev = {
++		.dma_mask = &ftsdc021_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/******************************************************************************
++ * GPIO devices
++ *****************************************************************************/
++#if defined(CONFIG_GPIO_FTGPIO010)
++/* GPIO 0 */
++static struct resource ftgpio010_0_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_0_PA_BASE,
++		.end 	= GPIO_FTGPIO010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_0_IRQ,
++		.end	= GPIO_FTGPIO010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_0_device = {
++	.name	= "ftgpio010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgpio010_0_resource),
++	.resource	= ftgpio010_0_resource
++};
++
++/* GPIO 1 */
++static struct resource ftgpio010_1_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_1_PA_BASE,
++		.end 	= GPIO_FTGPIO010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_1_IRQ,
++		.end	= GPIO_FTGPIO010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_1_device = {
++	.name	= "ftgpio010",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgpio010_1_resource),
++	.resource	= ftgpio010_1_resource
++};
++#endif
++
++/******************************************************************************
++ * SATA devices
++ *****************************************************************************/
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++/* SATA0 */
++static struct resource ftsata100_0_resource[] = {
++    {
++        .start = SATA_FTSATA100_0_PA_BASE,
++        .end   = SATA_FTSATA100_0_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_0_IRQ,
++        .end   = SATA_FTSATA100_0_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_0_dmamask = ~(u32)0;
++static struct platform_device ftsata100_0_device = {
++	.name           = "ftsata100",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(ftsata100_0_resource),
++	.resource       = ftsata100_0_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_0_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/* SATA1 */
++static struct resource ftsata100_1_resource[] = {
++    {
++        .start = SATA_FTSATA100_1_PA_BASE,
++        .end   = SATA_FTSATA100_1_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_1_IRQ,
++        .end   = SATA_FTSATA100_1_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_1_dmamask = ~(u32)0;
++static struct platform_device ftsata100_1_device = {
++	.name           = "ftsata100",
++	.id             = 1,
++	.num_resources  = ARRAY_SIZE(ftsata100_1_resource),
++	.resource       = ftsata100_1_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_1_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/* SATA2 */
++static struct resource ftsata100_2_resource[] = {
++    {
++        .start = SATA_FTSATA100_2_PA_BASE,
++        .end   = SATA_FTSATA100_2_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_2_IRQ,
++        .end   = SATA_FTSATA100_2_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_2_dmamask = ~(u32)0;
++static struct platform_device ftsata100_2_device = {
++	.name           = "ftsata100",
++	.id             = 2,
++	.num_resources  = ARRAY_SIZE(ftsata100_2_resource),
++	.resource       = ftsata100_2_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_2_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/* SATA3 */
++static struct resource ftsata100_3_resource[] = {
++    {
++        .start = SATA_FTSATA100_3_PA_BASE,
++        .end   = SATA_FTSATA100_3_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_3_IRQ,
++        .end   = SATA_FTSATA100_3_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_3_dmamask = ~(u32)0;
++static struct platform_device ftsata100_3_device = {
++	.name           = "ftsata100",
++	.id             = 3,
++	.num_resources  = ARRAY_SIZE(ftsata100_3_resource),
++	.resource       = ftsata100_3_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_3_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif // #ifdef CONFIG_SATA_AHCI_PLATFORM
++
++/******************************************************************************
++ * AHB DMA controllers
++ *****************************************************************************/
++#ifdef CONFIG_FTDMAC020
++static struct resource ftdmac020_0_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_0_PA_BASE,
++		.end	= DMAC_FTDMAC020_0_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_0_IRQ,
++		.end    = DMAC_FTDMAC020_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_0_device = {
++	.name		= "ftdmac020",
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_0_resources),
++	.resource	= ftdmac020_0_resources,
++};
++
++#ifdef CONFIG_GM8312
++static struct resource ftdmac020_1_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_1_PA_BASE,
++		.end	= DMAC_FTDMAC020_1_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_1_IRQ,
++		.end    = DMAC_FTDMAC020_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_1_device = {
++	.name		= "ftdmac020",
++	.id		    = 1,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_1_resources),
++	.resource	= ftdmac020_1_resources,
++};
++#endif /* CONFIG_GM8312 */
++#endif /* CONFIG_FTDMAC020 */
++
++#ifdef CONFIG_FTDMAC030
++static struct resource ftdmac030_resources[] = {
++	{
++		.start	= XDMAC_FTDMAC030_PA_BASE,
++		.end	= XDMAC_FTDMAC030_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= XDMAC_FTDMAC030_IRQ,
++		.end    = XDMAC_FTDMAC030_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++#define DRV_NAME	"ftdmac030"
++static struct platform_device ftdmac030_device = {
++	.name		= DRV_NAME,
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac030_resources),
++	.resource	= ftdmac030_resources,
++};
++#endif /* CONFIG_FTDMAC030 */
++
++/******************************************************************************
++ * SPI020 controllers
++ *****************************************************************************/
++#ifdef CONFIG_SPI_FTSPI020
++static struct resource ftspi020_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,     /* Register Base address */
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static u64 ftspi020_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftspi020_device = {
++    .name = "ftspi020",
++    .id = 0,//must match with bus_num
++    .num_resources = ARRAY_SIZE(ftspi020_resource),
++    .resource = ftspi020_resource,
++    .dev = {
++            .dma_mask = &ftspi020_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            },
++};
++#endif /* CONFIG_SPI_FTSPI020 */
++
++void memory_repair_dis(void)
++{
++	u32 reg = 0, timeout = 0x10000;
++
++	/* enable memory_repair_dis */
++	reg = ioread32(PMU_FTPMU010_VA_BASE + 0xa4);
++	reg = reg & ~(1 << 29);
++	iowrite32(reg, (PMU_FTPMU010_VA_BASE + 0xa4));
++
++	// pull-low rst_l
++	reg = ioread32(PMU_FTPMU010_VA_BASE + 0xa4);
++	reg = reg & ~(1 << 30);
++	iowrite32(reg, (PMU_FTPMU010_VA_BASE + 0xa4));
++
++	// pull-high rst_l
++	reg = ioread32(PMU_FTPMU010_VA_BASE + 0xa4);
++	reg = reg | (1 << 30);
++	iowrite32(reg, (PMU_FTPMU010_VA_BASE + 0xa4));
++
++	// set fen=1
++	reg = ioread32(PMU_FTPMU010_VA_BASE+0xa4);
++	reg = reg | (1 << 28);
++	iowrite32(reg, (PMU_FTPMU010_VA_BASE + 0xa4));
++
++	// wait fuse_ready
++	while(timeout --){
++		if(ioread32(PMU_FTPMU010_VA_BASE + 0x80) & 0x20000)
++			break;
++	}
++	if(timeout)
++	    printk("memory_repair_dis fail, if EVB is FPGA, don't care\n");
++}
++
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/
++static struct platform_device *gm_devices[] __initdata =
++{
++	/* I2C */
++#if defined(CONFIG_I2C0_IP) || defined(CONFIG_GM8210_FPGA)
++	&ftiic010_0_device,
++#endif
++#ifdef CONFIG_I2C1_IP
++	&ftiic010_1_device,
++#endif
++#ifdef CONFIG_I2C2_IP
++	&ftiic010_2_device,
++#endif
++#ifdef CONFIG_I2C3_IP
++	&ftiic010_3_device,
++#endif
++#ifdef CONFIG_I2C4_IP
++	&ftiic010_4_device,
++#endif
++#ifdef CONFIG_I2C5_IP
++    &ftiic010_5_device,
++#endif
++#ifdef CONFIG_GM_FOTG2XX
++	/* OTG */
++	&fotg210_0_device,
++	&fotg210_1_device,
++	&fotg210_2_device,
++#endif
++	&ftsdc021_device,
++#if defined(CONFIG_GPIO_FTGPIO010)
++    &ftgpio010_0_device,
++    &ftgpio010_1_device,
++#endif
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++	&ftsata100_0_device,
++	&ftsata100_1_device,
++	&ftsata100_2_device,
++	&ftsata100_3_device,
++#endif
++#ifdef CONFIG_FTDMAC020
++    &ftdmac020_0_device,
++#ifdef CONFIG_GM8312
++    &ftdmac020_1_device,
++#endif
++#endif /* CONFIG_FTDMAC020 */
++#ifdef CONFIG_SPI_FTSPI020
++    &ftspi020_device,
++#endif
++#ifdef CONFIG_FTDMAC030
++    &ftdmac030_device,
++#endif
++};
++
++void __init platform_devices_init(void)
++{
++    /* add platform devices here
++     */
++
++    /* will invoke platform_device_register() to register all platform devices
++     */
++	platform_add_devices(gm_devices, ARRAY_SIZE(gm_devices));
++	//memory_repair_dis();
++}
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210/pmu.c b/arch/arm/mach-GM-Duo/platform-GM8210/pmu.c
+new file mode 100644
+index 00000000..6bea9a6e
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210/pmu.c
+@@ -0,0 +1,536 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <asm/cputype.h>
++#include <mach/ftpmu010.h>
++#include <mach/fmem.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++static int gpio_fd = -1;
++static int dmac_fd = -1;
++static int cpuintr_fd = -1;
++#ifdef CONFIG_PLATFORM_AXIDMA
++static int xdmac_fd = -1;
++#endif
++static int mcp100_gate_fd = -1;
++
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_H264E_0, 2,     {{0xB0, (0x0 << 25),  (0x1 << 25)}, {0xB0, (0x0 << 3),  (0x1 << 3)}}},
++    {FTPMU_H264E_1, 2,     {{0xB4, (0x0 << 30),  (0x1 << 30)}, {0xB4, (0x0 << 8),  (0x1 << 8)}}},   /* mcp280off */
++    {FTPMU_H264D_0, 2,     {{0xB0, (0x0 << 24),  (0x1 << 24)}, {0xB0, (0x0 << 2),  (0x1 << 2)}}},
++    {FTPMU_H264D_1, 2,     {{0xB4, (0x0 << 29),  (0x1 << 29)}, {0xB4, (0x0 << 3),  (0x1 << 3)}}},   /* mcp300off */
++    {FTPMU_MCP100_0,1,     {{0xB4, (0x0 << 12),  (0x1 << 12)}}},   /* mcp100off */
++    {FTPMU_3DI_0,   2,     {{0xB0, (0x0 << 22),  (0x1 << 22)}, {0xB0, (0x0 << 15), (0x1 << 15)}}},  /* di3d0off */
++  	{FTPMU_SCALER_0,2,     {{0xB0, (0x0 << 26),  (0x1 << 26)}, {0xB0, (0x0 << 4),  (0x1 << 4)}}},  /* scaroff */
++    {FTPMU_NONE,    0,     {{0x0,   0x0,         0x0}}} /* END, this row is necessary */
++};
++
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++
++#ifdef CONFIG_I2C0_IP
++    {0xB8, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // Disable i2c0 gating clock off
++    {0x44, (0x1 << 12), (0x1 << 12), (0x1 << 12), (0x1 << 12)}, // Enable i2c0 schmitt trigger
++#endif
++#ifdef CONFIG_I2C1_IP
++	{0xBC, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)}, // Enable i2c1 gating clock off
++    {0x44, (0x1 << 16), (0x1 << 16), (0x1 << 16), (0x1 << 16)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 22), (0x3 << 22), (0x0 << 22), (0x3 << 22)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C2_IP
++	{0xBC, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)}, // i2c1 gating clock off
++    {0x44, (0x1 << 17), (0x1 << 17), (0x1 << 17), (0x1 << 17)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 24), (0x3 << 24), (0x0 << 24), (0x3 << 24)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C3_IP
++	{0xBC, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // i2c1 gating clock off
++    {0x44, (0x1 << 18), (0x1 << 18), (0x1 << 18), (0x1 << 18)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 26), (0x3 << 26), (0x0 << 26), (0x3 << 26)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C4_IP
++	{0xBC, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, // i2c1 gating clock off
++    {0x44, (0x1 << 19), (0x1 << 19), (0x1 << 19), (0x1 << 19)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 28), (0x3 << 28), (0x0 << 28), (0x3 << 28)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C5_IP
++    {0xBC, (0x1 << 10), (0x1 << 10), (0x0 << 10), (0x1 << 10)}, // i2c5 gating clock off
++    {0x44, (0x1 << 20), (0x1 << 20), (0x1 << 20), (0x1 << 20)}, // i2c5 schmitt trigger
++    {0x4C, (0x3 <<  6), (0x3 <<  6), (0x1 <<  6), (0x3 <<  6)}, // i2c5 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* GPIO
++ */
++static pmuReg_t regGPIOArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x3C, (0x7 << 9), (0x7 << 9), (0x0 << 9), (0x7 << 9)},
++};
++
++static pmuRegInfo_t gpio_clk_info = {
++    "gpio_clk",
++    ARRAY_SIZE(regGPIOArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regGPIOArray
++};
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++/* CPU INTR
++ */
++static pmuReg_t regCPUINTArray[] = {
++ /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++    {0xA8,   0xFFFFFFFF, 0xFFFFFFFF,   0x0,        0x0},
++};
++
++static pmuRegInfo_t cpu_intr_info = {
++    "CPU_INTR",
++    ARRAY_SIZE(regCPUINTArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regCPUINTArray
++};
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++/* AXI DMAC
++ */
++static pmuReg_t regXDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB0, (0x1 << 19), (0x1 << 19), (0x0 << 19), (0x1 << 19)},
++};
++static pmuRegInfo_t xdmac_clk_info = {
++    "AXI_DMAC_CLK",
++    ARRAY_SIZE(regXDMACArray),
++    ATTR_TYPE_AXI,
++    regXDMACArray
++};
++#endif
++
++/* MCP100 gating clock. CPU COMM uses its SRAM to do communication.
++ */
++static pmuReg_t regMCPclkArray[] = {
++ /* reg_off  bit_masks    lock_bits  init_val     init_mask */
++    {0xB4,   (0x1 << 12), 0,         (0x0 << 12), (0x1 << 12)},
++};
++
++static pmuRegInfo_t mcp100_clk_info = {
++    "mcp100_gate",
++    ARRAY_SIZE(regMCPclkArray),
++    ATTR_TYPE_NONE,
++    regMCPclkArray
++};
++
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++/* 0 for system running NAND, -1 for spi, 1 for SMC */
++int platform_check_flash_type(void)
++{
++	static unsigned int data = 0;
++	int ret = 0;
++
++	data = ioread32(pmu_base_addr + 0x4);
++
++    if (data & BIT22) {
++        if (data & BIT23)
++            ret = -1;
++        else
++            ret = 0;
++    } else {
++        ret = 1;
++    }
++
++	return ret;
++}
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	pmuver_t pmuver;
++	unsigned int product;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 *     821011: B version
++	 */
++	if (!version) {
++        product = (ioread32(pmu_base_addr) >> 16) & 0xFFFF;
++	    version = (ioread32(pmu_base_addr) >> 8) & 0xFF;
++
++	    printk("IC: GM%x, version: 0x%x \n", product, version);
++	}
++
++    switch (version) {
++      case 0x10:
++        pmuver = PMUVER_A;
++        break;
++      case 0x11:
++        pmuver = PMUVER_B;
++        break;
++      case 0x12:
++        pmuver = PMUVER_C;
++        break;
++      default:
++        pmuver = PMUVER_UNKNOWN;
++        break;
++    }
++
++	return (unsigned int)pmuver;
++}
++
++//format: xxxx_yyyy. xxxx: 8210, yyyy:IC revision
++unsigned int pmu_get_chipversion(void)
++{
++    unsigned int value = (0x8210 << 16);
++
++    value |= pmu_get_version();
++
++    return value;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return (ioread32(pmu_base_addr + 0x30) >> 16);
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 3) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static unsigned int pmu_read_pll4out(void)
++{
++	u32 value;
++
++    value = (ioread32(pmu_base_addr + 0x38) >> 4 ) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static unsigned int pmu_read_pll3out(void)
++{
++    u32 mul, value = 0;
++
++    if (ioread32(pmu_base_addr + 0x28) & (1 << 15)) {   /* no pll3 */
++        printk("PLL3 not support this mode\n");
++    } else {
++  	    mul = (ioread32(pmu_base_addr + 0x34) >> 4) & 0x7F;
++  	    value = (SYS_CLK * mul) / 2;
++    }
++
++    return value;
++}
++
++static unsigned int pmu_read_pll5out(void)
++{
++    return 100000000;
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 17) & 0x3;
++
++    switch(value){
++      case 0:
++  	    value = (pmu_read_pll1out() * 2) / 5;
++  	    break;
++      case 1:
++  	    value = pmu_read_pll1out() / 3;
++  	    break;
++      case 2:
++  	    value = pmu_read_pll1out() / 4;
++  	    break;
++      case 3:
++        if (pmu_get_version() == PMUVER_A)
++            value = pmu_read_pll1out() / 5;
++        else
++            value = pmu_read_pll4out() / 3;
++      	break;
++      default:
++  	    printk("AHB not support this mode\n");
++  	    break;
++	}
++
++    return value;
++}
++
++static unsigned int pmu_get_axi_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++
++    if(value & (1 << 19))
++  	value = pmu_read_pll1out() / 3;
++    else
++  	value = (pmu_read_pll1out() * 2) / 5;
++
++    return value;
++}
++
++unsigned int pmu_get_apb0_clk(void)
++{
++    return pmu_get_axi_clk() / 8;
++}
++
++unsigned int pmu_get_apb1_clk(void)
++{
++    return pmu_get_axi_clk() / 2;
++}
++
++unsigned int pmu_get_apb2_clk(void)
++{
++    return pmu_get_ahb_clk() / 4;
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    u32 value = 0;
++
++    if (get_cpu_id() == 0x726) {
++        value = ioread32(pmu_base_addr + 0x30);
++        if(value & (1 << 22))
++            if(value & (1 << 24)){
++                value = (ioread32(pmu_base_addr + 0x38) >> 4) & 0x7F;
++      	        value = (SYS_CLK * value);
++      	    }
++      	    else
++      	        value = pmu_read_pll1out() / 3;
++        else
++      	    value = pmu_read_pll1out();
++    } else { /* FA626 */
++        value = pmu_read_pll1out() * 2 / 3;
++    }
++
++    return value;
++}
++
++static unsigned int pmu_get_sys_clk(void)
++{
++    return 30*1000000;  //30Mhz
++}
++
++static unsigned int pmu_get_ep_cnt(void)
++{
++    u32 value;
++
++    value = (ftpmu010_read_reg(0xBC) >> 24) & 0xFF;
++
++    if (value > 1)
++        value = 0;  /* uninit value */
++
++    return value;
++}
++
++static attr_cpu_enum_t pmu_get_cpu_enumator(void)
++{
++    fmem_pci_id_t   pci_id;
++    fmem_cpu_id_t   cpu_id;
++    attr_cpu_enum_t retval;
++
++    if (fmem_get_identifier(&pci_id, &cpu_id))
++        panic("%s, error! \n", __func__);
++
++    if (pci_id == FMEM_PCI_HOST) {
++        retval = (cpu_id == FMEM_CPU_FA726) ? CPU_RC_FA726 : CPU_RC_FA626;
++    } else {
++        retval = (cpu_id == FMEM_CPU_FA726) ? CPU_EP0_FA726 : CPU_EP0_FA626;
++    }
++
++    return retval;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk",   ATTR_TYPE_AXI,    0}, pmu_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb0_clk},
++    {{"pclk1",  ATTR_TYPE_APB1,   0}, pmu_get_apb1_clk},
++    {{"pclk2",  ATTR_TYPE_APB2,   0}, pmu_get_apb2_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"pll4",   ATTR_TYPE_PLL4,   0}, pmu_read_pll4out},
++    {{"pll5",   ATTR_TYPE_PLL5,   0}, pmu_read_pll5out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++    {{"chipver",   ATTR_TYPE_CHIPVER, 0}, pmu_get_chipversion},
++	{{"sysclk",    ATTR_TYPE_SYSCLK,  0}, pmu_get_sys_clk},
++    {{"pci_epcnt", ATTR_TYPE_EPCNT,   0}, pmu_get_ep_cnt},
++    {{"cpu_enum",  ATTR_TYPE_CPUENUM, 0}, pmu_get_cpu_enumator},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(clock_info); tmp ++) {
++            if (clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (clock_info[tmp].clock_fun) {
++                clock_info[tmp].clock.value = clock_info[tmp].clock_fun();
++                ftpmu010_deregister_attr(&clock_info[tmp].clock);
++                ret = ftpmu010_register_attr(&clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++    cpuintr_fd = ftpmu010_register_reg(&cpu_intr_info);
++    if (unlikely(cpuintr_fd < 0)){
++        printk("CPU INTR registers to PMU fail! \n");
++    }
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++    /* register AXI DMAC to pmu core */
++    xdmac_fd = ftpmu010_register_reg(&xdmac_clk_info);
++    if (unlikely(xdmac_fd < 0)){
++        printk("AXI DMAC registers to PMU fail! \n");
++    }
++#endif
++
++    mcp100_gate_fd = ftpmu010_register_reg(&mcp100_clk_info);
++    if (unlikely(mcp100_gate_fd < 0)){
++        printk("MCP100 gate registers to PMU fail! \n");
++    }
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++
++    if (get_cpu_id() == 0x726) {
++        /* clear the memory to zero */
++        iowrite32(0, (void *)pmu_base_addr + 0x6C);
++    }
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210/pmu_fpga.c b/arch/arm/mach-GM-Duo/platform-GM8210/pmu_fpga.c
+new file mode 100644
+index 00000000..f92bd4ca
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210/pmu_fpga.c
+@@ -0,0 +1,548 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <asm/cputype.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#ifdef CONFIG_GM8312
++#include <mach/ftpmu010_pcie.h>
++#endif
++#include <mach/fmem.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++static int gpio_fd = -1;
++static int dmac_fd = -1;
++#ifdef CONFIG_GM8312
++static int gm8312_fd = -1;
++#endif
++static int cpuintr_fd = -1;
++#ifdef CONFIG_PLATFORM_AXIDMA
++static int xdmac_fd = -1;
++#endif
++
++int ftpmu010_h264e_fd = -1;
++int ftpmu010_h264d_fd = -1;
++int ftpmu010_mcp100_fd = -1;
++
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_H264E_0, 2,     {{0xB0, (0x0 << 25),  (0x1 << 25)}, {0xB0, (0x0 << 3),  (0x1 << 3)}}},
++    {FTPMU_H264E_1, 2,     {{0xB4, (0x0 << 30),  (0x1 << 30)}, {0xB4, (0x0 << 8),  (0x1 << 8)}}},   /* mcp280off */
++    {FTPMU_H264D_0, 2,     {{0xB0, (0x0 << 24),  (0x1 << 24)}, {0xB0, (0x0 << 2),  (0x1 << 2)}}},
++    {FTPMU_H264D_1, 2,     {{0xB4, (0x0 << 29),  (0x1 << 29)}, {0xB4, (0x0 << 3),  (0x1 << 3)}}},   /* mcp300off */
++    {FTPMU_MCP100_0,1,     {{0xB4, (0x0 << 12),  (0x1 << 12)}}},   /* mcp100off */
++    {FTPMU_3DI_0,   2,     {{0xB0, (0x0 << 22),  (0x1 << 22)}, {0xB0, (0x0 << 15), (0x1 << 15)}}},  /* di3d0off */
++  	{FTPMU_SCALER_0,2,     {{0xB0, (0x0 << 26),  (0x1 << 26)}, {0xB0, (0x0 << 4),  (0x1 << 4)}}},  /* scaroff */
++    {FTPMU_NONE,    0,     {{0x0,   0x0,         0x0}}} /* END, this row is necessary */
++};
++#ifdef CONFIG_GM8312
++static pmuPcieReg_t reg8312Array[] = {
++ /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++    {0x30, (0x1 << 8), (0x1 << 8), (0x0 << 8), (0x1 << 8)}, // Enable dmac CLK
++    {0x30, (0x1 << 10), (0x1 << 10), (0x0 << 10), (0x1 << 10)}, // Enable ahbc CLK
++    {0x30, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)}, // Enable PCIE_AXI_BRG
++    {0x34, (0x1 << 1), (0x1 << 1), (0x0 << 1), (0x1 << 1)}, // Enable axic CLK
++    {0x34, (0x1 << 2), (0x1 << 2), (0x0 << 2), (0x1 << 2)}, // Enable X2H APB CLK
++    {0x34, (0x1 << 8), (0x1 << 8), (0x0 << 8), (0x1 << 8)}, // Enable INTC CLK
++    {0x34, (0xFF << 9), (0xFF << 9), (0x0 << 9), (0xFF << 9)}, // Enable H2X APB CLK
++    {0x34, (0x3 << 23), (0x3 << 23), (0x0 << 23), (0x3 << 23)}, // Enable PCIE_AXI_BRG
++};
++static pmuPcieRegInfo_t gm8312_clk_info = {
++    "8312_clk",
++    ARRAY_SIZE(reg8312Array),
++    ATTR_TYPE_NONE, /* no clock source */
++    reg8312Array
++};
++#endif
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++
++#ifdef CONFIG_I2C0_IP
++    {0xB8, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // Disable i2c0 gating clock off
++    {0x44, (0x1 << 12), (0x1 << 12), (0x1 << 12), (0x1 << 12)}, // Enable i2c0 schmitt trigger
++#endif
++#ifdef CONFIG_I2C1_IP
++	{0xBC, (0x1 << 16), (0x1 << 16), (0x1 << 16), (0x1 << 16)}, // Enable i2c1 gating clock off
++    {0x44, (0x1 << 16), (0x1 << 16), (0x1 << 16), (0x1 << 16)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 22), (0x3 << 22), (0x0 << 22), (0x3 << 22)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C2_IP
++	{0xBC, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)}, // i2c1 gating clock off
++    {0x44, (0x1 << 17), (0x1 << 17), (0x1 << 17), (0x1 << 17)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 24), (0x3 << 24), (0x0 << 24), (0x3 << 24)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C3_IP
++	{0xBC, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, // i2c1 gating clock off
++    {0x44, (0x1 << 18), (0x1 << 18), (0x1 << 18), (0x1 << 18)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 26), (0x3 << 26), (0x0 << 26), (0x3 << 26)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C4_IP
++	{0xBC, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, // i2c1 gating clock off
++    {0x44, (0x1 << 19), (0x1 << 19), (0x1 << 19), (0x1 << 19)}, // i2c1 schmitt trigger
++    {0x50, (0x3 << 28), (0x3 << 28), (0x0 << 28), (0x3 << 28)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++#ifdef CONFIG_I2C5_IP
++    {0xBC, (0x1 << 10), (0x1 << 10), (0x0 << 10), (0x1 << 10)}, // i2c1 gating clock off
++    {0x44, (0x1 << 20), (0x1 << 19), (0x1 << 20), (0x1 << 20)}, // i2c1 schmitt trigger
++    {0x4C, (0x3 <<  6), (0x3 <<  6), (0x0 <<  6), (0x3 <<  6)}, // i2c1 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* GPIO
++ */
++static pmuReg_t regGPIOArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x3C, (0x7 << 9), (0x7 << 9), (0x0 << 9), (0x7 << 9)},
++};
++
++static pmuRegInfo_t gpio_clk_info = {
++    "gpio_clk",
++    ARRAY_SIZE(regGPIOArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regGPIOArray
++};
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++/* CPU INTR
++ */
++static pmuReg_t regCPUINTArray[] = {
++ /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++    {0xA8,   0xFFFFFFFF, 0xFFFFFFFF,   0x0,        0x0},
++};
++
++static pmuRegInfo_t cpu_intr_info = {
++    "CPU_INTR",
++    ARRAY_SIZE(regCPUINTArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regCPUINTArray
++};
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++/* AXI DMAC
++ */
++static pmuReg_t regXDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB0, (0x1 << 19), (0x1 << 19), (0x0 << 19), (0x1 << 19)},
++};
++static pmuRegInfo_t xdmac_clk_info = {
++    "AXI_DMAC_CLK",
++    ARRAY_SIZE(regXDMACArray),
++    ATTR_TYPE_AXI,
++    regXDMACArray
++};
++#endif
++
++/* H264E
++ */
++static pmuReg_t regH264EArray[] = {
++    /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x28,      (0x1 << 31), (0x1 << 31),  (0x0 << 31), (0x0 << 31)},
++    {0xA0,      (0x3 << 1), (0x3 << 1),  (0x0 << 1), (0x0 << 1)},
++    {0xB0,      (0x1 << 25), (0x1 << 25),  (0x0 << 25), (0x0 << 25)},
++    {0xB0,      (0x1 << 3), (0x1 << 3),  (0x0 << 3), (0x0 << 3)},
++    {0xB4,      (0x1 << 30), (0x1 << 30),  (0x0 << 30), (0x0 << 30)},
++    {0xB4,      (0x1 << 8), (0x1 << 8),  (0x0 << 8), (0x0 << 8)},
++};
++static pmuRegInfo_t h264e_clk_info = {
++    "H264E_CLK",
++    ARRAY_SIZE(regH264EArray),
++    ATTR_TYPE_PLL4,
++    regH264EArray
++};
++
++/* H264D
++ */
++static pmuReg_t regH264DArray[] = {
++    /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x28,      (0x1 << 30), (0x1 << 30),  (0x0 << 30), (0x0 << 30)},
++    {0xA0,      (0x3 << 3), (0x3 << 3),  (0x0 << 3), (0x0 << 3)},
++    {0xB0,      (0x1 << 24), (0x1 << 24),  (0x0 << 24), (0x0 << 24)},
++    {0xB0,      (0x1 << 2), (0x1 << 2),  (0x0 << 2), (0x0 << 2)},
++    {0xB4,      (0x1 << 29), (0x1 << 29),  (0x0 << 29), (0x0 << 29)},
++    {0xB4,      (0x1 << 7), (0x1 << 7),  (0x0 << 7), (0x0 << 7)},
++};
++static pmuRegInfo_t h264d_clk_info = {
++    "H264D_CLK",
++    ARRAY_SIZE(regH264DArray),
++    ATTR_TYPE_PLL4,
++    regH264DArray
++};
++
++/* MCP100
++ */
++static pmuReg_t regMCP100Array[] = {
++    /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x28,      (0x1 << 16), (0x1 << 16),  (0x0 << 16), (0x0 << 16)},
++    {0xA0,      (0x1 << 16), (0x1 << 16),  (0x0 << 16), (0x0 << 16)},
++    {0xB4,      (0x1 << 12), (0x1 << 12),  (0x0 << 12), (0x0 << 12)},
++};
++static pmuRegInfo_t mcp100_clk_info = {
++    "MCP100_CLK",
++    ARRAY_SIZE(regMCP100Array),
++    ATTR_TYPE_PLL1,
++    regMCP100Array
++};
++
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	int inc = 0;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 */
++	if (!version) {
++
++	    version = ioread32(pmu_base_addr) >> 8;
++
++	    switch ((ioread32(pmu_base_addr) >> 5) & 0x7)
++	    {
++			case 0 : inc = 0; break;
++			case 2 : inc = 1; break;
++			case 6 : inc = 2; break;
++			case 7 : inc = 3; break;
++			default: inc = 0; break;
++		}
++		if ((version & 0xf0) == 0x10) {
++			/* 8210 series */
++			printk("IC: GM%04x(%c)\n", ((version >> 8) & 0xffff) + inc, (version & 0xff) + 'A' - 0x10);
++		} else {
++			printk("IC: ID not be found\n");
++		}
++	}
++
++	return version;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return (ioread32(pmu_base_addr + 0x30) >> 16);
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 3) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static inline u32 pmu_read_pll2out(void)
++{
++    printk("GM8210 not use PLL2\n");
++    return 0;
++}
++
++static unsigned int pmu_read_pll4out(void)
++{
++    return 768000000;
++}
++
++static unsigned int pmu_read_pll3out(void)
++{
++    u32 mul, value = 0;
++
++    if (get_cpu_id() == 0x726) {
++        value = 648;
++    } else {
++        if (ioread32(pmu_base_addr + 0x28) & (1 << 15)) {
++            printk("PLL3 not support this mode\n");
++        } else {
++          	mul = (ioread32(pmu_base_addr + 0x34) >> 4) & 0xFF;
++          	value = SYS_CLK * mul / 2;
++        }
++    }
++
++    return value * 1000000;
++}
++
++static unsigned int pmu_read_pll5out(void)
++{
++    return 100000000;
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++    u32 value = 0;
++
++    if (get_cpu_id() == 0x726) {
++        value = 20000000;
++    } else {
++        value = ioread32(pmu_base_addr + 0x30);
++        value = (value >> 17) & 0x3;
++
++        switch(value) {
++            case 0:
++              	value = (pmu_read_pll1out() * 2) / 5;
++              	break;
++            case 1:
++              	value = pmu_read_pll1out() / 3;
++              	break;
++            case 2:
++              	value = pmu_read_pll1out() / 4;
++              	break;
++            case 3:
++              	value = pmu_read_pll1out() / 5;
++              	break;
++            default:
++              	printk("AHB not support this mode\n");
++              	break;
++    	}
++    }
++
++    return value;
++}
++
++static unsigned int pmu_get_axi_clk(void)
++{
++    u32 value = 0;
++
++    if (get_cpu_id() == 0x726) {
++        value = 50000000;
++    } else {
++        value = ioread32(pmu_base_addr + 0x30);
++
++        if (value & (1 << 19))
++      	    value = pmu_read_pll1out() / 3;
++        else
++      	    value = (pmu_read_pll1out() * 2) / 5;
++    }
++
++    return value;
++}
++
++unsigned int pmu_get_apb0_clk(void)
++{
++    return 20000000;//pmu_get_axi_clk() / 2;
++}
++
++unsigned int pmu_get_apb1_clk(void)
++{
++    return 20000000;//pmu_get_axi_clk() / 8;
++}
++
++unsigned int pmu_get_apb2_clk(void)
++{
++    return 20000000;//pmu_get_ahb_clk() / 4;
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    u32 value = 0;
++
++    if (get_cpu_id() == 0x726) {
++        value = ioread32(pmu_base_addr + 0x30);
++
++        if(value & (1 << 22))
++      	    value = pmu_read_pll1out() / 3;
++        else
++      	    value = pmu_read_pll1out();
++    } else {
++        value = pmu_read_pll1out() * 2 / 3;
++    }
++
++    return value;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk",   ATTR_TYPE_AXI,    0}, pmu_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    //{{"pclk",   ATTR_TYPE_APB,    0}, pmu_get_apb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb0_clk},
++    {{"pclk1",  ATTR_TYPE_APB1,   0}, pmu_get_apb1_clk},
++    {{"pclk2",  ATTR_TYPE_APB2,   0}, pmu_get_apb2_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll2",   ATTR_TYPE_PLL2,   0}, pmu_read_pll2out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"pll4",   ATTR_TYPE_PLL4,   0}, pmu_read_pll4out},
++    {{"pll5",   ATTR_TYPE_PLL5,   0}, pmu_read_pll5out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++
++        /* this attribute exists */
++        if (clock_info[attr].clock_fun) {
++            clock_info[attr].clock.value = clock_info[attr].clock_fun();
++            ftpmu010_deregister_attr(&clock_info[attr].clock);
++            ret = ftpmu010_register_attr(&clock_info[attr].clock);
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++    cpuintr_fd = ftpmu010_register_reg(&cpu_intr_info);
++    if (unlikely(cpuintr_fd < 0)){
++        printk("CPU INTR registers to PMU fail! \n");
++    }
++
++#ifdef CONFIG_PLATFORM_AXIDMA
++    /* register AXI DMAC to pmu core */
++    xdmac_fd = ftpmu010_register_reg(&xdmac_clk_info);
++    if (unlikely(xdmac_fd < 0)){
++        printk("AXI DMAC registers to PMU fail! \n");
++    }
++#endif
++
++#ifdef CONFIG_GM8312
++    ftpmu010_pcie_init((void *)PCIPMU_FTPMU010_VA_BASE);
++
++    /* register GM8312 bus to pmu core */
++    gm8312_fd = ftpmu010_pcie_register_reg(&gm8312_clk_info);
++    if (unlikely(gm8312_fd < 0)){
++        printk("GM8312 CLK registers to PMU fail! \n");
++    }
++#endif
++
++    ftpmu010_h264e_fd = ftpmu010_register_reg(&h264e_clk_info);
++    if (unlikely(ftpmu010_h264e_fd < 0)){
++        printk("H264 Enc registers to PMU fail! \n");
++    }
++
++    ftpmu010_h264d_fd = ftpmu010_register_reg(&h264d_clk_info);
++    if (unlikely(ftpmu010_h264d_fd < 0)){
++        printk("H264 Dec registers to PMU fail! \n");
++    }
++
++    ftpmu010_mcp100_fd = ftpmu010_register_reg(&mcp100_clk_info);
++    if (unlikely(ftpmu010_mcp100_fd < 0)){
++        printk("MCP100 registers to PMU fail! \n");
++    }
++
++    return 0;
++}
++
++EXPORT_SYMBOL(ftpmu010_h264e_fd);
++EXPORT_SYMBOL(ftpmu010_h264d_fd);
++EXPORT_SYMBOL(ftpmu010_mcp100_fd);
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210/pmu_pcie.c b/arch/arm/mach-GM-Duo/platform-GM8210/pmu_pcie.c
+new file mode 100644
+index 00000000..880af716
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210/pmu_pcie.c
+@@ -0,0 +1,191 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++#include <mach/ftpmu010_pcie.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int gm8312_fd = -1;
++static int cpuintr_fd = -1;
++
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_pcie_gate_clk_t pcie_gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_PCIE_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++
++    /* reg_off  bit_masks   lock_bits     init_val    init_mask */
++static pmuPcieReg_t reg8312Array[] = {
++    /* Enable dmac CLK, ahbc CLK, PCIE_AXI_BRG */
++    {0x30, (0x1 << 8) | (0x1 << 10) | (0x1 << 13), (0x1 << 8) | (0x1 << 10) | (0x1 << 13), 0x0, (0x1 << 8) | (0x1 << 10) | (0x1 << 13)},
++
++    /* Enable AXIC_APB_CLK, X2H APB CLK, INTC CLK, H2X APB CLK, PCIE_AXI_BRG, H2X7_APB_CLK */
++    {0x34, (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 << 16) | (0x3 << 23), (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 <<16) |  (0x3 << 23), 0x0, (0x3 << 1) | (0x1 << 8) | (0xFF << 9) | (0x1 << 16) | (0x3 << 23)},
++};
++static pmuPcieRegInfo_t gm8312_clk_info = {
++    "8312_clk",
++    ARRAY_SIZE(reg8312Array),
++    ATTR_TYPE_PCIE_NONE, /* no clock source */
++    reg8312Array
++};
++
++static unsigned int pmu_pcie_get_version(void)
++{
++	static unsigned int version = 0;
++
++	/*
++	 * Version ID:
++	 *     821010: A version
++	 */
++	if (!version) {
++
++	    version = ioread32(pmu_base_addr) >> 8;
++		printk("IC: GM%04x(%c)\n", ((version >> 8) & 0xffff), (version & 0xff) + 'A' - 0x10);
++	}
++
++	return version;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_pcie_read_pll1out(void)
++{
++    u32 value = 0, pll_ns, pll_ms;
++
++    value = ioread32(pmu_base_addr + 0x08);
++    pll_ns = (value >> 2) & 0xFF;
++    pll_ms = (value >> 10) & 0x1F;
++
++    return (SYS_CLK * pll_ns / pll_ms);
++}
++
++static unsigned int pmu_pcie_get_axi_clk(void)
++{
++    return pmu_pcie_read_pll1out() / 2;
++}
++
++static unsigned int pmu_pcie_get_ahb_clk(void)
++{
++    return pmu_pcie_read_pll1out() / 2;
++}
++
++unsigned int pmu_pcie_get_apb_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x34);
++    value = (value >> 26) & 0x1F;
++
++    return pmu_pcie_get_ahb_clk() / (value + 1);
++}
++
++struct clock_s
++{
++    attrPcieInfo_t   clock;
++    u32         (*clock_fun)(void);
++} pcie_clock_info[] = {
++    {{"aclk",   ATTR_TYPE_PCIE_AXI,    0}, pmu_pcie_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_PCIE_AHB,    0}, pmu_pcie_get_ahb_clk},
++    {{"pclk",   ATTR_TYPE_PCIE_APB,    0}, pmu_pcie_get_apb_clk},
++    {{"pll1",   ATTR_TYPE_PCIE_PLL1,   0}, pmu_pcie_read_pll1out},
++    {{"pmuver", ATTR_TYPE_PCIE_PMUVER, 0}, pmu_pcie_get_version},
++};
++
++/* this function is callback from ftpmu010.c */
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_PCIE_TYPE_T attr = (ATTR_PCIE_TYPE_T)data1;
++    u32 irq = data1 - CPU_INT_BASE, tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_INTR_FIRE:
++      case FUNC_TYPE_INTR_CLR:
++        if (cpuintr_fd == -1) {
++            printk("%s, cpuintr pmu is not registered yet! \n", __func__);
++            return -1;
++        }
++        if (irq > 15)
++            panic("%s, invalid irq: %d \n", __func__, data1);
++
++        tmp = (cmd == FUNC_TYPE_INTR_CLR) ? 0x1 << (irq + 16) : 0x1 << irq;
++        ftpmu010_write_reg(cpuintr_fd, 0xA8, tmp, 0xFFFFFFFF);
++        break;
++
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(pcie_clock_info); tmp ++) {
++            if (pcie_clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (pcie_clock_info[tmp].clock_fun) {
++                pcie_clock_info[tmp].clock.value = pcie_clock_info[tmp].clock_fun();
++                ftpmu010_pcie_deregister_attr(&pcie_clock_info[tmp].clock);
++                ret = ftpmu010_pcie_register_attr(&pcie_clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_pcie_postinit(void)
++{
++    int i;
++
++    printk("PCIE PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_pcie_init(pmu_base_addr, &pcie_gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(pcie_clock_info); i ++)
++    {
++        if (pcie_clock_info[i].clock_fun)
++            pcie_clock_info[i].clock.value = pcie_clock_info[i].clock_fun();
++
++        ftpmu010_pcie_register_attr(&pcie_clock_info[i].clock);
++    }
++
++    /* register GM8312 bus to pmu core */
++    gm8312_fd = ftpmu010_pcie_register_reg(&gm8312_clk_info);
++    if (unlikely(gm8312_fd < 0)){
++        printk("GM8312 CLK registers to PMU fail! \n");
++    }
++
++    return 0;
++}
++
++arch_initcall(pmu_pcie_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_pcie_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-Duo/platform-GM8210/timer_fixup.c b/arch/arm/mach-GM-Duo/platform-GM8210/timer_fixup.c
+new file mode 100644
+index 00000000..2312c7c4
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/platform-GM8210/timer_fixup.c
+@@ -0,0 +1,160 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <asm/cputype.h>
++#include <linux/delay.h>
++#include <mach/ftpmu010.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/fiq.h>
++#include <mach/platform/board.h>
++
++#define CONFIG_MAX_TICK     0xffffffff
++static int timer_init_ready = 0;
++
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++/*
++ * Get the max ms the this timer
++ */
++unsigned int video_gettime_max_ms(void)
++{
++    return (CONFIG_MAX_TICK / APB0_CLK_IN) * 1000;
++}
++
++/* calculate the max hz in max_ms
++ */
++unsigned int video_gettime_max_hz(void)
++{
++    unsigned int max_hz;
++
++    /* calculate the max hz in max_ms. Actually it is (video_gettime_max_ms() / 1000) * APB0_CLK_IN
++     */
++    max_hz = video_gettime_max_ms() * (APB0_CLK_IN / 1000);
++
++    return max_hz;
++}
++
++unsigned int video_gettime_ms(void)
++{
++    //0~35 sec round
++    unsigned int timer_base;
++
++    if (get_cpu_id() == 0x726)
++        timer_base = TIMER_FTTMR010_0_VA_BASE;
++    else
++        timer_base = TIMER_FTTMR010_2_VA_BASE;
++
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++unsigned int video_gettime_us(void)
++{
++    //0~35 sec round
++    unsigned int timer_base;
++
++    if (get_cpu_id() == 0x726)
++        timer_base = TIMER_FTTMR010_0_VA_BASE;
++    else
++        timer_base = TIMER_FTTMR010_2_VA_BASE;
++
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++
++        return (value - tick_diff) / (ft_apb_clk / 1000000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++/*
++ * Entry Point of this module. It may be declared by arch_initcall section
++ */
++static int __init fixup_timer_init(void)
++{
++    //use timer3, 42s will overflow in AHB clock 200HZ
++    unsigned int ft_apb_clk = APB0_CLK_IN;
++    unsigned int timer_base;
++    unsigned int max_tick;
++
++    if (get_cpu_id() == 0x726)
++        timer_base = TIMER_FTTMR010_0_VA_BASE;
++    else
++        timer_base = TIMER_FTTMR010_2_VA_BASE;
++
++    if (*(unsigned int *)(timer_base + 0x30) & (0x1 << 6))
++    {
++        printk("Timer3 is alredy been used!\n");
++        return 0;
++    }
++
++    max_tick = video_gettime_max_ms() * (ft_apb_clk / 1000);    //the max hz count in TmxCounter
++
++    printk("Video Timer(timer3) Max %dms in 0x%x HZ.\n", video_gettime_max_ms(), max_tick);
++
++    /* the following configuration is for TIMER3 */
++    *(volatile unsigned int *)(timer_base + 0x20) = CONFIG_MAX_TICK - max_tick; //keep the start count in start counter
++    *(volatile unsigned int *)(timer_base + 0x24) = CONFIG_MAX_TICK - max_tick; //reLoad counter
++    *(volatile unsigned int *)(timer_base + 0x38) |= (0x7 << 6);   //IRQ disable
++    *(volatile unsigned int *)(timer_base + 0x30) |= ((0x1 << 6) | (0x1 << 11));    //enable timer3, count up
++    timer_init_ready = 1;
++
++    return 0;
++}
++
++static void fixup_timer_exit(void)
++{
++    if (timer_init_ready == 1)
++    {
++        unsigned int timer_base;
++
++        if (get_cpu_id() == 0x726)
++            timer_base = TIMER_FTTMR010_0_VA_BASE;
++        else
++            timer_base = TIMER_FTTMR010_2_VA_BASE;
++
++        *(volatile unsigned int *)(timer_base + 0x30) &= ~(0x1 << 6);//disable timer2, count up
++        timer_init_ready = 0;
++    }
++	printk("%s: cleaning up\n",__func__);
++}
++
++module_init(fixup_timer_init);
++module_exit(fixup_timer_exit);
++
++EXPORT_SYMBOL(video_gettime_ms);
++EXPORT_SYMBOL(video_gettime_us);
++EXPORT_SYMBOL(video_gettime_max_ms);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("FIXUP timer driver");
+diff --git a/arch/arm/mach-GM-Duo/proc-fmem.c b/arch/arm/mach-GM-Duo/proc-fmem.c
+new file mode 100644
+index 00000000..c805356e
+--- /dev/null
++++ b/arch/arm/mach-GM-Duo/proc-fmem.c
+@@ -0,0 +1,293 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/sort.h>
++#include <linux/mmzone.h>
++#include <linux/memory.h>
++#include <linux/kallsyms.h>
++#include <linux/nodemask.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <asm/cputype.h>
++#include <asm/setup.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include <asm/tlbflush.h>
++#include <asm/glue-cache.h>
++#include <asm/outercache.h>
++
++/* 
++ * cache functions.
++ * The following functions come from arch/arm/include/asm/glue-cache.h
++ */
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++    
++    if (!cpu_id)
++       cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++    
++    return cpu_id;
++}
++void inline fmem_flush_icache_all(void)
++{
++    extern void fa726te_flush_icache_all(void);
++    extern void fa_flush_icache_all(void);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_flush_icache_all();
++    else
++        fa_flush_icache_all();
++}
++
++void inline fmem_flush_kern_cache_all(void)
++{
++    extern void fa726te_flush_kern_cache_all(void);
++    extern void fa_flush_kern_cache_all(void);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_flush_kern_cache_all();
++    else
++        fa_flush_kern_cache_all();
++}
++
++void inline fmem_flush_user_cache_all(void)
++{
++    extern void fa726te_flush_user_cache_all(void);
++    extern void fa_flush_user_cache_all(void);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_flush_user_cache_all();
++    else
++        fa_flush_user_cache_all();
++}
++
++void inline fmem_flush_user_cache_range(unsigned long start, unsigned long end, unsigned int flags)
++{
++    extern void fa726te_flush_user_cache_range(unsigned long, unsigned long, unsigned int);
++    extern void fa_flush_user_cache_range(unsigned long, unsigned long, unsigned int);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_flush_user_cache_range(start, end, flags);
++    else
++        fa_flush_user_cache_range(start, end, flags);
++}
++
++void inline fmem_coherent_kern_range(unsigned long start, unsigned long end)
++{
++    extern void fa726te_coherent_kern_range(unsigned long, unsigned long);
++    extern void fa_coherent_kern_range(unsigned long, unsigned long);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_coherent_kern_range(start, end);
++    else
++        fa_coherent_kern_range(start, end);
++}
++
++void inline fmem_coherent_user_range(unsigned long start, unsigned long end)
++{
++    extern void fa726te_coherent_user_range(unsigned long, unsigned long);
++    extern void fa_coherent_user_range(unsigned long, unsigned long);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_coherent_user_range(start, end);
++    else
++        fa_coherent_user_range(start, end);
++}
++
++void inline fmem_flush_kern_dcache_area(void *addr, size_t size)
++{
++    extern void fa726te_flush_kern_dcache_area(void *, size_t);
++    extern void fa_flush_kern_dcache_area(void *, size_t);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_flush_kern_dcache_area(addr, size);
++    else
++        fa_flush_kern_dcache_area(addr, size);
++}
++
++void inline fmem_dma_map_area(const void *start, size_t size, int dir)
++{
++    extern void fa726te_dma_map_area(const void *, size_t, int);
++    extern void fa_dma_map_area(const void *, size_t, int);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_dma_map_area(start, size, dir);
++    else
++        fa_dma_map_area(start, size, dir);
++}
++
++void inline fmem_dma_unmap_area(const void *start, size_t size, int dir)
++{
++    extern void fa726te_dma_unmap_area(const void *, size_t, int);
++    extern void fa_dma_unmap_area(const void *, size_t, int);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_dma_unmap_area(start, size, dir);
++    else
++        fa_dma_unmap_area(start, size, dir);
++}
++
++void inline fmem_dma_flush_range(const void *start, const void *end)
++{
++    extern void fa726te_dma_flush_range(const void *, const void *);
++    extern void fa_dma_flush_range(const void *, const void *);
++    
++    if (get_cpu_id() == 0x726)
++        fa726te_dma_flush_range(start, end);
++    else
++        fa_dma_flush_range(start, end);
++}
++
++/* ----------------------------------------------------------------------------
++ * processor functions.
++ * The following functions come from arch/arm/include/asm/glue-proc.h
++ * ----------------------------------------------------------------------------
++ */
++ 
++/*
++ * Set up any processor specifics
++ */ 
++void inline cpu_fmem_proc_init(void)
++{
++    extern void cpu_fa726te_proc_init(void);
++    extern void cpu_fa626te_proc_init(void);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_proc_init();
++    else
++        cpu_fa626te_proc_init();         
++}
++
++/*
++ * Disable any processor specifics
++ */
++void inline cpu_fmem_proc_fin(void)
++{
++    extern void cpu_fa726te_proc_fin(void);
++    extern void cpu_fa626te_proc_fin(void);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_proc_fin();
++    else
++        cpu_fa626te_proc_fin();      
++}
++
++/*
++ * Special stuff for a reset
++ */
++void inline cpu_fmem_reset(unsigned long addr)
++{
++    volatile int loop = 100;
++    extern void cpu_fa726te_reset(unsigned long);
++    extern void cpu_fa626te_reset(unsigned long);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_reset(addr);
++    else
++        cpu_fa626te_reset(addr);     
++
++    /* never return */
++    while (loop == 100) {};    
++}
++
++/*
++ * Idle the processor
++ */
++int inline cpu_fmem_do_idle(void)
++{
++    extern int cpu_fa726te_do_idle(void);
++    extern int cpu_fa626te_do_idle(void);
++    
++    if (get_cpu_id() == 0x726)
++        return cpu_fa726te_do_idle();
++    else
++        return cpu_fa626te_do_idle();    
++}
++
++/*
++ * clean a virtual address range from the
++ * D-cache without flushing the cache.
++ */
++void inline cpu_fmem_dcache_clean_area(void *addr, int size)
++{
++    extern void cpu_fa726te_dcache_clean_area(void *addr, int size);
++    extern void cpu_fa626te_dcache_clean_area(void *addr, int size);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_dcache_clean_area(addr, size);
++    else
++        cpu_fa626te_dcache_clean_area(addr, size);         
++}
++
++/*
++ * Set the page table
++ */
++void inline cpu_fmem_switch_mm(unsigned long pgd_phys, struct mm_struct *mm)
++{
++    extern void cpu_fa726te_switch_mm(unsigned long, struct mm_struct *);
++    extern void cpu_fa626te_switch_mm(unsigned long, struct mm_struct *);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_switch_mm(pgd_phys, mm);
++    else
++        cpu_fa626te_switch_mm(pgd_phys, mm);
++}
++
++/*
++ * Set a possibly extended PTE.  Non-extended PTEs should
++ * ignore 'ext'.
++ */
++#ifdef CONFIG_ARM_LPAE 
++void inline cpu_fmem_set_pte_ext(pte_t *ptep, pte_t pte)
++{
++    extern void cpu_fa726te_set_pte_ext(pte_t *ptep, pte_t pte);
++    extern void cpu_fa626te_set_pte_ext(pte_t *ptep, pte_t pte);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_set_pte_ext(ptep, pte);
++    else
++        cpu_fa626te_set_pte_ext(ptep, pte);       
++}
++#else
++void inline cpu_fmem_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext)
++{
++    extern void cpu_fa726te_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
++    extern void cpu_fa626te_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_set_pte_ext(ptep, pte, ext);
++    else
++        cpu_fa626te_set_pte_ext(ptep, pte, ext);
++}
++#endif /* CONFIG_ARM_LPAE */
++
++/* Suspend/resume */
++void inline cpu_fmem_do_suspend(void *ptr)
++{
++#ifdef CONFIG_PM_SLEEP    
++    extern void cpu_fa726te_do_suspend(void *);
++    extern void cpu_fa626te_do_suspend(void *);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_do_suspend(ptr);
++    else
++        cpu_fa626te_do_suspend(ptr);    
++#endif        
++}
++
++/* Suspend/resume */
++void inline cpu_fmem_do_resume(void *ptr)
++{
++#ifdef CONFIG_PM_SLEEP    
++    extern void cpu_fa726te_do_resume(void *);
++    extern void cpu_fa626te_do_resume(void *);
++    
++    if (get_cpu_id() == 0x726)
++        cpu_fa726te_do_resume(ptr);
++    else
++        cpu_fa626te_do_resume(ptr);
++#endif        
++}
+diff --git a/arch/arm/mach-GM-SMP/Kconfig b/arch/arm/mach-GM-SMP/Kconfig
+new file mode 100644
+index 00000000..26b4ac58
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/Kconfig
+@@ -0,0 +1,59 @@
++#
++# arch/arm/mach-GM-SMP/Kconfig
++#
++
++#
++# GM Platform Types Selection
++#
++choice
++	prompt "Platform Selection"
++	default PLATFORM_GM8220
++	depends on ARCH_GM_SMP
++
++config PLATFORM_GM8220
++	bool "GM8220 series platform"
++	select ARM_GIC if CPU_HAS_GIC
++    help
++      GM GM8220 is a platform based on ARM Cortex compatible processor
++
++endchoice
++
++config FORCE_MAX_ZONEORDER
++    int
++    depends on ARCH_GM_SMP
++    default "12"
++
++config FTDMAC020
++    tristate "Supports DMAC020 controller"
++    select DMA_ENGINE
++    default y
++
++config FTDMAC030
++    tristate "Supports DMAC030 controller"
++    select DMA_ENGINE
++    depends on PLATFORM_AXIDMA
++    default y
++
++config FTAPBB020
++    tristate "Supports APB DMA"
++    select DMA_ENGINE
++    default n
++
++config CPU_HAS_GIC
++	bool
++	default y if CPU_FMP626 || CPU_CA9 || CPU_CA7
++	help
++	   Use ARM GIC
++
++#
++# Platform dependent options
++#
++menu "GM Platform Options"
++    depends on ARCH_GM_SMP
++
++source "arch/arm/mach-GM-SMP/platform-GM8220/Kconfig"
++    
++endmenu    
++
++
++
+diff --git a/arch/arm/mach-GM-SMP/Makefile b/arch/arm/mach-GM-SMP/Makefile
+new file mode 100644
+index 00000000..cc19dd03
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/Makefile
+@@ -0,0 +1,47 @@
++#
++# Makefile for the linux kernel.
++
++# obj-y += xxx.o
++obj-y += ftpmu010.o fttmr010.o fmem.o dma_gm.o gm_jiffies.o clock.o
++obj-$(CONFIG_FTDMAC020) += ftdmac020.o
++obj-$(CONFIG_FTDMAC030) += ftdmac030.o
++obj-$(CONFIG_FTAPBB020) += ftapbb020.o
++obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
++obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
++
++GM-platform-$(CONFIG_PLATFORM_GM8220)       := platform-GM8220
++
++ifeq ($(CONFIG_CPU_FREQ),y)
++obj-$(CONFIG_PLATFORM_GM8220)		+= cpufreq.o
++endif
++
++#
++#Default platform directory set to GM8220
++#TODO: Make this an error, should never happen unless the Kconfig or Makefile is wrong
++#
++ifeq ($(GM-platform-y),)
++GM-platform-y := platform-GM8220
++endif
++
++PLATFORM_DIR   := $(GM-platform-y)
++
++core-y      +=  arch/arm/mach-GM-SMP/$(PLATFORM_DIR)/
++
++define create-platform-symlink
++  mkdir -p arch/arm/mach-GM-SMP/include/mach;                 \
++  if [ -L $@ ]; then                              \
++    platformlink=`readlink $@`;                     \
++  fi;												\
++  if [ ! -e $@ ] || [ $$platformlink != $(PLATFORM_DIR) ]; then           \
++	 touch arch/arm/mach-GM-SMP/include/mach/$(PLATFORM_DIR)/*;      \
++  fi;															\
++  echo '  SYMLINK $@ -> arch/arm/mach-GM-SMP/include/mach/$(PLATFORM_DIR)';   \
++  ln -fsn $(PLATFORM_DIR) $@;
++endef
++
++arch/arm/mach-GM-SMP/include/mach/platform: FORCE
++	 $(Q)$(create-platform-symlink)
++
++prepare: arch/arm/mach-GM-SMP/include/mach/platform	 
++
++
+diff --git a/arch/arm/mach-GM-SMP/Makefile.boot b/arch/arm/mach-GM-SMP/Makefile.boot
+new file mode 100644
+index 00000000..4b292e3b
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/Makefile.boot
+@@ -0,0 +1,4 @@
++   zreladdr-y	:= 0x00008000
++params_phys-y	:= 0x00000100
++initrd_phys-y	:= 0x00900000
++
+diff --git a/arch/arm/mach-GM-SMP/clock.c b/arch/arm/mach-GM-SMP/clock.c
+new file mode 100644
+index 00000000..e207d2c5
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/clock.c
+@@ -0,0 +1,111 @@
++/*
++ *  linux/arch/arm/mach-faraday/clock.c
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/clk.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++
++#include <linux/clkdev.h>
++
++#include "clock.h"
++
++static DEFINE_SPINLOCK(clk_lock);
++
++void __clk_enable(struct clk *clk)
++{
++	if (clk->parent)
++		__clk_enable(clk->parent);
++	if (clk->users++ == 0 && clk->mode)
++		clk->mode(clk, 1);
++}
++
++int clk_enable(struct clk *clk)
++{
++	unsigned long	flags;
++
++	spin_lock_irqsave(&clk_lock, flags);
++	__clk_enable(clk);
++	spin_unlock_irqrestore(&clk_lock, flags);
++	return 0;
++}
++EXPORT_SYMBOL(clk_enable);
++
++void __clk_disable(struct clk *clk)
++{
++	BUG_ON(clk->users == 0);
++	if (--clk->users == 0 && clk->mode)
++		clk->mode(clk, 0);
++	if (clk->parent)
++		__clk_disable(clk->parent);
++}
++
++void clk_disable(struct clk *clk)
++{
++	unsigned long	flags;
++
++	spin_lock_irqsave(&clk_lock, flags);
++	__clk_disable(clk);
++	spin_unlock_irqrestore(&clk_lock, flags);
++}
++EXPORT_SYMBOL(clk_disable);
++
++unsigned long __clk_get_rate(struct clk *clk)
++{
++	unsigned long rate;
++
++	rate = clk->rate;
++	if (rate == 0) {
++		if (clk->get_rate)
++			rate = clk->get_rate(clk);
++		else if (clk->parent)
++			rate = __clk_get_rate(clk->parent);
++	}
++
++	return rate;
++}
++
++unsigned long clk_get_rate(struct clk *clk)
++{
++	unsigned long flags;
++	unsigned long rate;
++
++	spin_lock_irqsave(&clk_lock, flags);
++	rate = __clk_get_rate(clk);
++	spin_unlock_irqrestore(&clk_lock, flags);
++	return rate;
++}
++EXPORT_SYMBOL(clk_get_rate);
++
++int clk_set_rate(struct clk *clk, unsigned long rate)
++{
++	unsigned long flags;
++	int ret = -EINVAL;
++
++	if (clk == NULL || clk->set_rate == NULL || rate == 0)
++		return ret;
++
++	spin_lock_irqsave(&clk_lock, flags);
++	ret = clk->set_rate(clk, rate);
++	spin_unlock_irqrestore(&clk_lock, flags);
++
++	return ret;
++}
++EXPORT_SYMBOL(clk_set_rate);
+diff --git a/arch/arm/mach-GM-SMP/clock.h b/arch/arm/mach-GM-SMP/clock.h
+new file mode 100644
+index 00000000..b2167e96
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/clock.h
+@@ -0,0 +1,40 @@
++/*
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __ARCH_ARM_FARADAY_CLOCK_H
++#define __ARCH_ARM_FARADAY_CLOCK_H
++
++struct clk {
++	struct clk	*parent;
++	int		users;
++	unsigned long	rate;
++	void __iomem	*base;	/* base address of controller if any */
++	unsigned long	(*get_rate)(struct clk *clk);
++	int		(*set_rate)(struct clk *clk, unsigned long rate);
++	int		(*mode)(struct clk *, int on);
++	void		*params;
++};
++
++/*
++ * These functions assume that lock is already held.
++ */
++void __clk_enable(struct clk *clk);
++void __clk_disable(struct clk *clk);
++unsigned long __clk_get_rate(struct clk *clk);
++#endif
+diff --git a/arch/arm/mach-GM-SMP/cpufreq.c b/arch/arm/mach-GM-SMP/cpufreq.c
+new file mode 100644
+index 00000000..7594c2fa
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/cpufreq.c
+@@ -0,0 +1,202 @@
++/*
++ * linux/arch/arm/mach-GM/cpufreq.c
++ *
++ * Copyright (C) 2014 Grain Media
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/cpufreq.h>
++#include <linux/slab.h>
++#include <mach/ftpmu010.h>
++
++static int cpu_freq_fd;
++static unsigned int cpu_frequency;
++static unsigned int cpu_max_speed;
++
++struct gm_freq_info {
++	unsigned int cpufreq_mhz;
++	unsigned int membus;
++	unsigned int cccr;
++	unsigned int div2;
++};
++
++static struct cpufreq_frequency_table *gm_freq_table;
++
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x14, (0xFFFFFFFF << 0), (0xFFFFFFFF << 0), (0x0 << 0), (0xFFFFFFFF << 0)},   /* AHB clock gate */
++};
++
++static pmuRegInfo_t	pmu_reg_info = {
++    "CPU_Freq",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++static void update_pwm_freq(unsigned int clk)
++{
++	unsigned int value = 0xFFFF;
++
++    if (clk == gm_freq_table[0].frequency)
++        value = 0xFFFF;
++    else if (clk == gm_freq_table[1].frequency)
++        value = 0xAAAA;
++    else if (clk == gm_freq_table[2].frequency)
++        value = 0x1111;
++    else if (clk == gm_freq_table[3].frequency)
++        value = 0x0101;
++    else
++    	printk("Not this kind of clock definition\n");
++
++#ifdef CONFIG_PLATFORM_GM8220
++ 	ftpmu010_write_reg(cpu_freq_fd, 0x14, (value << 15), (0xFFFF << 15));
++#else
++ 	ftpmu010_write_reg(cpu_freq_fd, 0x14, (value << 16), (0xFFFF << 16));
++#endif 	
++	ftpmu010_write_reg(cpu_freq_fd, 0x14, (0x3 << 0), (0x3 << 0));
++}
++
++static int gm_cpufreq_verify(struct cpufreq_policy *policy)
++{
++    return cpufreq_frequency_table_verify(policy, gm_freq_table);
++}
++
++static unsigned int gm_cpufreq_get(unsigned int cpu)
++{
++	return cpu_frequency;//REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);, clk_ctrl.pll ? 200000 : 6000; ???
++}
++
++static int gm_cpufreq_set(struct cpufreq_policy *policy,
++			      unsigned int target_freq,
++			      unsigned int relation)
++{
++	struct cpufreq_freqs freqs;
++	int idx;
++
++	if (policy->cpu != 0)
++		return -EINVAL;
++
++	/* Lookup the next frequency */
++	if (cpufreq_frequency_table_target(policy, gm_freq_table,
++				target_freq, relation, &idx))
++		return -EINVAL;
++
++	freqs.old = policy->cur;
++	freqs.new = cpu_frequency = gm_freq_table[idx].frequency;
++	freqs.cpu = policy->cpu;
++#if 0
++	printk(KERN_DEBUG "CPU freq %d to %d MHz%s\n",
++			freqs.old, freqs.new,
++			(freqs.old == freqs.new) ? " (skip)" : "");
++#endif
++	if (freqs.old == target_freq)
++		return 0;
++
++	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
++
++	//local_irq_save(flags);
++	update_pwm_freq(cpu_frequency);
++	//local_irq_restore(flags);
++	
++	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
++
++	return 0;
++}
++
++static int gm_cpufreq_init(struct cpufreq_policy *policy)
++{
++	int ret = -EINVAL;
++	int i, j, num, new_speed;
++	
++	printk("GM CPU frequency driver\n");
++
++    cpu_freq_fd = ftpmu010_register_reg(&pmu_reg_info);
++    if (cpu_freq_fd < 0)
++        printk("cpu freq register PMU fail");
++
++	/* set default policy and cpuinfo */
++	cpu_max_speed = ftpmu010_get_attr(ATTR_TYPE_CPU) / 1000000;
++	//printk("cpu_speed = %d\n", cpu_max_speed);
++	cpu_frequency = cpu_max_speed;
++	policy->max = policy->cpuinfo.max_freq = cpu_max_speed;
++	
++	if(cpu_max_speed > 700)
++        num = 4;
++	else
++        num = 3;
++
++    gm_freq_table = kzalloc((num + 1) * sizeof(*gm_freq_table), GFP_KERNEL);
++    if (gm_freq_table == NULL)
++    	return -ENOMEM;
++    
++    for (i = 0; i < num; i++) {
++        new_speed = cpu_max_speed;
++        
++        for(j = 0; j < i; j++)
++            new_speed /= 2;
++            
++    	gm_freq_table[i].index = i;
++    	gm_freq_table[i].frequency = new_speed;
++    	//printk("a%d = %d,%d\n", i, gm_freq_table[i].index, gm_freq_table[i].frequency);
++    }
++    		
++	policy->min = policy->cpuinfo.min_freq = 100000;
++	policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
++	policy->cur = policy->min = policy->max;
++	
++	gm_freq_table[num].index = 0;
++	gm_freq_table[num].frequency = CPUFREQ_TABLE_END;
++    
++	ret = cpufreq_frequency_table_cpuinfo(policy, gm_freq_table);
++
++	if (ret) {
++		pr_err("failed to setup frequency table\n");
++		return ret;
++	}
++    cpufreq_frequency_table_get_attr(gm_freq_table, policy->cpu);
++	pr_info("CPUFREQ support for gm initialized\n");
++	return 0;
++}
++
++static int gm_cpufreq_exit(struct cpufreq_policy *policy)
++{
++    cpufreq_frequency_table_put_attr(policy->cpu);
++    
++    return 0;
++}
++
++static struct freq_attr *gm_cpufreq_attr[] = {
++	&cpufreq_freq_attr_scaling_available_freqs,
++	NULL,
++};
++
++static struct cpufreq_driver gm_cpufreq_driver = {	
++	.flags		= CPUFREQ_STICKY,	
++	.verify		= gm_cpufreq_verify,
++	.target		= gm_cpufreq_set,
++	.init		= gm_cpufreq_init,
++	.exit       = gm_cpufreq_exit,
++	.get		= gm_cpufreq_get,
++	.name		= "GM-cpufreq",
++	.attr		= gm_cpufreq_attr,
++};
++
++static int __init cpufreq_init(void)
++{
++	return cpufreq_register_driver(&gm_cpufreq_driver);
++}
++module_init(cpufreq_init);
++
++static void __exit cpufreq_exit(void)
++{
++	cpufreq_unregister_driver(&gm_cpufreq_driver);
++}
++module_exit(cpufreq_exit);
++
++MODULE_DESCRIPTION("CPU frequency scaling driver for GM");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-SMP/dma_gm.c b/arch/arm/mach-GM-SMP/dma_gm.c
+new file mode 100644
+index 00000000..ece24fee
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/dma_gm.c
+@@ -0,0 +1,252 @@
++/*
++ * GM DMA memory operation (MEM_TO_MEM)
++ *
++ * Copyright (C) 2012 Faraday Technology Corp.
++ *
++ * Author : Shuao-kai Li <easonli@faraday-tech.com>
++ *
++ * 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; version 2 of the License.
++ */
++#include <linux/dmaengine.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/dma-mapping.h>
++#include <linux/hardirq.h>
++#include <linux/export.h>
++#include <mach/ftapbb020.h>
++#include <mach/ftdmac020.h>
++#ifdef CONFIG_FTDMAC030
++#include <mach/ftdmac030.h>
++#endif
++#include <mach/dma_gm.h>
++
++struct dma_gm {
++	struct dma_chan	*chan;
++	struct dma_async_tx_descriptor *desc;
++//	struct dma_slave_config slave; /* It's useless now */
++	enum dma_status dma_st;
++	dma_cap_mask_t mask;
++	dma_cookie_t cookie;
++	wait_queue_head_t dma_wait_queue;
++};
++
++#define err(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ##args)
++
++static void dma_callback(void *param)
++{
++	struct dma_gm *gm = (struct dma_gm *)param;
++	gm->dma_st = DMA_SUCCESS;
++    wake_up(&gm->dma_wait_queue);
++}
++
++static void dma_wait(struct dma_gm *gm)
++{
++	int status;
++
++    status = wait_event_timeout(gm->dma_wait_queue,
++						gm->dma_st == DMA_SUCCESS,
++						60 * HZ);
++	if (status == 0) {
++		err("Timeout in DMA\n");
++	}
++}
++
++int dma_memcpy(enum dma_kind style, dma_addr_t dest, dma_addr_t src, size_t len)
++{
++	struct dma_gm gm_chan;
++	int ret = 0, flag = 0;
++
++	if (in_interrupt())
++		panic("Fatal exception in interrupt");
++
++	memset(&gm_chan, 0, sizeof(gm_chan));
++	init_waitqueue_head(&gm_chan.dma_wait_queue);
++	dma_cap_zero(gm_chan.mask);
++	dma_cap_set(DMA_MEMCPY, gm_chan.mask);
++
++	switch (style) {
++#if defined(CONFIG_FTAPBB020)
++		case APB_DMA:
++		{
++			struct ftapbb020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.common.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			slave.common.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftapbb020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC020)
++		case AHB_DMA:
++		{
++			struct ftdmac020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.handshake = -1;
++
++			/* Use BUS 1 for shared cpu bus loading */
++			slave.src_sel = 1;
++			slave.dst_sel = 1;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC030)
++		case AXI_DMA:
++		{
++			struct ftdmac030_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.handshake = -1;
++
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac030_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++		default:
++			err("No such DMA bus\n");
++			return -ENXIO;
++		break;
++	}
++
++	/* filter fn has already set dma_slave_config. */
++	//dmaengine_slave_config(gm_chan.chan, &gm_chan.slave);
++
++	flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	gm_chan.desc = dmaengine_prep_dma_memcpy(gm_chan.chan, dest, src, len, flag);
++	if (!gm_chan.desc) {
++		err("Set DMA failed!!\n");
++		ret = -EIO;
++		goto fail;
++	}
++	gm_chan.cookie = dmaengine_submit(gm_chan.desc);
++	if (dma_submit_error(gm_chan.cookie)) {
++		err("DMA submit failed\n");
++		dmaengine_terminate_all(gm_chan.chan);
++		ret = -EIO;
++		goto fail;
++	}
++	gm_chan.desc->callback = dma_callback;
++	gm_chan.desc->callback_param = &gm_chan;
++	gm_chan.dma_st = DMA_IN_PROGRESS;
++	dma_async_issue_pending(gm_chan.chan);
++	dma_wait(&gm_chan);
++fail:
++	dma_release_channel(gm_chan.chan);
++	return ret;
++}
++EXPORT_SYMBOL(dma_memcpy);
++
++int dma_memset(enum dma_kind style, dma_addr_t dest, int value, size_t len)
++{
++	struct dma_gm gm_chan;
++	int ret = 0, flag = 0;
++
++	if (in_interrupt())
++		panic("Fatal exception in interrupt");
++
++	memset(&gm_chan, 0, sizeof(gm_chan));
++	init_waitqueue_head(&gm_chan.dma_wait_queue);
++	dma_cap_zero(gm_chan.mask);
++	dma_cap_set(DMA_MEMSET, gm_chan.mask);
++
++	switch (style) {
++#if defined(CONFIG_FTAPBB020)
++		case APB_DMA:
++		{
++			struct ftapbb020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.common.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			slave.common.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftapbb020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC020)
++		case AHB_DMA:
++		{
++			struct ftdmac020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.handshake = -1;
++
++			/* Use BUS 1 for shared cpu bus loading */
++			slave.src_sel = 1;
++			slave.dst_sel = 1;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC030)
++		case AXI_DMA:
++		{
++			struct ftdmac030_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.handshake = -1;
++
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac030_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++		default:
++			err("No such DMA bus\n");
++			return -ENXIO;
++		break;
++	}
++
++	/* filter fn has already set dma_slave_config. */
++	//dmaengine_slave_config(gm_chan.chan, &gm_chan.slave);
++
++flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	gm_chan.desc = dmaengine_prep_dma_memset(gm_chan.chan, dest, value, len, flag);
++	if (!gm_chan.desc) {
++		err("Set DMA failed!!\n");
++		ret = -EIO;
++		goto fail;
++	}
++
++	gm_chan.cookie = dmaengine_submit(gm_chan.desc);
++	if (dma_submit_error(gm_chan.cookie)) {
++		err("DMA submit failed\n");
++		dmaengine_terminate_all(gm_chan.chan);
++		ret = -EIO;
++		goto fail;
++	}
++
++	gm_chan.desc->callback = dma_callback;
++	gm_chan.desc->callback_param = &gm_chan;
++	gm_chan.dma_st = DMA_IN_PROGRESS;
++	dma_async_issue_pending(gm_chan.chan);
++	dma_wait(&gm_chan);
++fail:
++	dma_release_channel(gm_chan.chan);
++	return ret;
++}
++EXPORT_SYMBOL(dma_memset);
+diff --git a/arch/arm/mach-GM-SMP/fmem.c b/arch/arm/mach-GM-SMP/fmem.c
+new file mode 100644
+index 00000000..bad52a11
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/fmem.c
+@@ -0,0 +1,1096 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/sort.h>
++#include <linux/mmzone.h>
++#include <linux/memory.h>
++#include <linux/kallsyms.h>
++#include <linux/nodemask.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <asm/setup.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include <asm/tlbflush.h>
++#include <asm/glue-cache.h>
++#include <asm/outercache.h>
++#include <linux/proc_fs.h>
++#include <linux/platform_device.h>
++#include <mach/fmem.h>
++#include <mach/platform/board.h>
++#include <mach/ftpmu010.h>
++
++void debug_printk(const char *f, ...);
++static int __init sanity_check_memhole(u32 *base);
++
++/* MACROs defintion
++ */
++#define ALLOC_BSZ         SZ_8M
++#define POOL_LIST(x)      g_page_info.list[x]
++#define POOL_NODE_SZ(x)   g_page_info.node_sz[x]
++#define POOL_PHY_START(x) g_page_info.phy_start[x]
++#define MAX_PAGE_NUM      128 /* 1G bytes */
++#define CACHE_ALIGN_MASK  0x1F  //cache line with 32 bytes
++
++/*
++ * Local variables declaration
++ */
++static g_page_info_t    g_page_info;
++static struct meminfo mem_info, gmmem_info;
++u32 page_array[2][MAX_PAGE_NUM] __initdata;
++u32 reserve_blk_cnt[2] __initdata;
++u32 nonlinear_cpuaddr_flush = 0;
++u32 cpuaddr_flush = 0;
++u32 va_not_32align = 0, length_not_32align = 0;
++u32 debug_counter = 0;
++
++#define DEBUG_WRONG_CACHE_API   0x0
++#define DEBUG_WRONG_CACHE_VA    0x1
++#define DEBUG_WRONG_CACHE_LEN   0x2
++
++/* proc function
++ */
++static struct proc_dir_entry *fmem_proc_root = NULL;
++static struct proc_dir_entry *resolve_proc = NULL;
++static struct proc_dir_entry *counter_proc = NULL;
++
++/* counter info
++ */
++static int proc_read_counter(char *page, char **start, off_t off, int count, int *eof,
++                                    void *data)
++{
++    int len = 0;
++
++    len += sprintf(page + len, "linear cpu_addr flush: %d \n", cpuaddr_flush);
++    len += sprintf(page + len, "non-linear cpu_addr flush: %d \n", nonlinear_cpuaddr_flush);
++    len += sprintf(page + len, "vaddr not cache alignment: %d \n", va_not_32align);
++    len += sprintf(page + len, "len not cache alignment: %d \n", length_not_32align);
++    len += sprintf(page + len, "debug_counter = 0x%x \n", debug_counter);
++
++    return len;
++}
++
++/* debug counter */
++int proc_write_debug_counter(struct file *file, const char *buffer, unsigned long count, void *data)
++{
++    unsigned char value[30];
++
++    if (copy_from_user(value, buffer, count))
++        return 0;
++
++    sscanf(value, "%x\n", &debug_counter);
++
++
++    printk("debug counter: 0x%x \n", debug_counter);
++
++    return count;
++}
++
++/* address resolve
++ */
++int proc_resolve_pa(struct file *file, const char *buffer, unsigned long count, void *data)
++{
++    unsigned char value[30];
++    unsigned int vaddr;
++    phys_addr_t  paddr;
++
++    if (copy_from_user(value, buffer, count))
++        return 0;
++
++    sscanf(value, "%x\n", &vaddr);
++    paddr = fmem_lookup_pa(vaddr);
++
++    printk("Resolve vaddr: 0x%x ---> paddr: 0x%x \n", vaddr, paddr);
++
++    return count;
++}
++
++void fmem_proc_init(void)
++{
++    struct proc_dir_entry *p;
++
++    p = create_proc_entry("fmem", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (p == NULL) {
++        printk("%s, fail! \n", __func__);
++        return;
++    }
++
++    fmem_proc_root = p;
++
++    /* resolve, va->pa
++     */
++    resolve_proc = create_proc_entry("resolve", S_IRUGO, fmem_proc_root);
++    if (resolve_proc == NULL)
++        panic("FMEM: Fail to create proc resolve_proc!\n");
++    resolve_proc->read_proc = NULL;
++    resolve_proc->write_proc = proc_resolve_pa;
++
++    /* counter
++     */
++    counter_proc = create_proc_entry("counter", S_IRUGO, fmem_proc_root);
++    if (counter_proc == NULL)
++        panic("FMEM: Fail to create proc counter_proc!\n");
++    counter_proc->read_proc = (read_proc_t *)proc_read_counter;
++    counter_proc->write_proc = proc_write_debug_counter;
++}
++
++/*
++ * PAGE Functions
++ */
++static int __init page_array_cmp(const void *_a, const void *_b)
++{
++    u32 data_a, data_b;
++	int cmp;
++
++	data_a = *(u32 *)_a;    /* the address of page */
++	data_b = *(u32 *)_b;
++
++	cmp = page_to_phys((struct page *)data_a) - page_to_phys((struct page *)data_b);
++
++	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
++}
++
++static int __init meminfo_cmp(const void *_a, const void *_b)
++{
++	const struct membank *a = _a, *b = _b;
++	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
++
++	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
++}
++
++/* Parse early memory
++ */
++static void __init parse_early_mem(char *p)
++{
++	unsigned long size, nr_bank;
++	phys_addr_t start;
++	char *endp;
++
++	start = PHYS_OFFSET;
++	size  = memparse(p, &endp);
++	if (*endp == '@')
++		start = memparse(endp + 1, NULL);
++
++    nr_bank = mem_info.nr_banks;
++    mem_info.bank[nr_bank].start = start;
++    mem_info.bank[nr_bank].size  = size;
++    mem_info.nr_banks ++;
++}
++
++/* Parse early GM memory
++ */
++static void __init parse_early_gmmem(char *p)
++{
++	unsigned long size, nr_bank;
++	char *endp;
++
++	size  = memparse(p, &endp);
++    nr_bank = gmmem_info.nr_banks;
++    gmmem_info.bank[nr_bank].size  = size;
++
++    gmmem_info.nr_banks ++;
++}
++
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++/* This function calculates the max MAX_PHYSMEM_BITS in memory.h
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required to address
++ * the last byte of memory.
++ */
++unsigned int fmem_max_physmem_bits(void)
++{
++    unsigned int max_physmem_bits;
++    unsigned long phyaddr;
++    int nr_banks;
++
++    nr_banks = mem_info.nr_banks;
++	phyaddr = bank_pfn_end(&mem_info.bank[nr_banks - 1]) << PAGE_SHIFT;
++
++	max_physmem_bits = get_order(phyaddr) + PAGE_SHIFT;
++
++
++    return max_physmem_bits;
++}
++#endif /* CONFIG_ARCH_SPARSEMEM_ENABLE */
++
++/* calculate how many blocks in the page array
++ */
++static int __init get_early_memblk_count(u32 *page_array)
++{
++    int i = 0;
++
++    do {
++        if (!page_array[i])
++            break;
++        i ++;
++    } while (1);
++
++    return i;
++}
++
++/* Purpose: to get whole pages from buddy system as possible for the 2nd DDR.
++ * This function is called early once the buddy system is ready.
++ */
++void __init fmem_early_init(void)
++{
++    struct page *page;
++    dma_addr_t  pfn;
++    int i, idx, order, size, ddr0_cnt;
++
++    memset(&reserve_blk_cnt[0], 0, sizeof(reserve_blk_cnt));
++
++    order = get_order(ALLOC_BSZ);
++
++    if (order > MAX_ORDER)
++        panic("%s, max order: %d, alloc order: %d \n", __func__, MAX_ORDER, order);
++
++    /* do nothing for single bank */
++    if (mem_info.nr_banks == 1)
++        goto ddr0_alloc;
++
++    idx = 1;
++    i = 0;
++    do {
++        /* allocate the first page and store all page pointer inside */
++        page = alloc_pages_node(1, GFP_ATOMIC, order);
++        if (!page)
++            panic("%s, get null page for ddr%d! \n", __func__, idx);
++
++        page_array[idx][i] = (u32)page;
++        /* check if the physical of the allocated page is smaller than the 2nd bank */
++        pfn = __phys_to_pfn(page_to_phys(page));
++        if (pfn < bank_pfn_start(&mem_info.bank[1])) {
++            page_array[idx][i] = 0x0;
++            __free_pages(page, order);
++            break;
++        }
++        /* keep page pointer */
++        page_array[idx][i] = (u32)page;
++
++        i ++;
++        if (i >= MAX_PAGE_NUM)
++            panic("%s, MAX_PAGE_NUM: %d is too small for ddr%d! \n", __func__, MAX_PAGE_NUM, idx);
++    } while (1);
++
++    //keep total blocks
++    reserve_blk_cnt[idx] = i;
++
++    /* sort the pages in ascendant order */
++    sort(page_array[idx], i, sizeof(u32), page_array_cmp, NULL);
++
++ddr0_alloc:
++    idx = 0;
++    /* allocate memory for node 0 */
++    size = gmmem_info.bank[0].size ? gmmem_info.bank[0].size : DDR0_FMEM_SIZE;
++    ddr0_cnt = (size + ALLOC_BSZ - 1) >> (order + PAGE_SHIFT);
++    //keep total blocks
++    reserve_blk_cnt[idx] = ddr0_cnt;
++
++    i = 0;
++    do {
++        page = alloc_pages_node(0, GFP_ATOMIC, order);
++        if (page == NULL) {
++            page_array[idx][i] = 0x0;
++            printk("%s, requested memory size: 0x%x is too large! \n", __func__, size);
++            break;
++        }
++
++        page_array[idx][i] = (u32)page;
++        i ++;
++        if (i >= MAX_PAGE_NUM)
++            panic("%s, MAX_PAGE_NUM: %d is too small for ddr%d! \n", __func__, MAX_PAGE_NUM, idx);
++    } while (-- ddr0_cnt);
++
++    /* sort the pages */
++    sort(page_array[idx], i, sizeof(u32), page_array_cmp, NULL);
++
++    return;
++}
++
++/*
++ * Parse the memory tag from command line
++ */
++void __init fmem_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    char key[] = "mem=", *from, *command_line = NULL;
++    struct tag  *t = tag;
++    char gm_key[] = "gmmem=";
++    int  i, tag_found = 0;
++
++    memset(&mem_info, 0, sizeof(mem_info));
++    memset(&gmmem_info, 0, sizeof(gmmem_info));
++
++    if (tag->hdr.tag == ATAG_CORE) {
++        for (; t->hdr.size; t = tag_next(t)) {
++            if (t->hdr.tag == ATAG_CMDLINE) {
++                command_line = &t->u.cmdline.cmdline[0];
++                from = command_line;
++                tag_found = 1;
++                break;
++            }
++        }
++    }
++
++    /* not found the boot argument parameters from UBOOT */
++    if (!tag_found) {
++        command_line = *cmdline;
++        from = *cmdline;
++    }
++
++    for (i = 0; i < strlen(command_line) - strlen(key); i ++) {
++        if (memcmp(from, key, strlen(key)) == 0) {
++			from += strlen(key);
++			parse_early_mem(from);
++		}
++		else if (memcmp(from, gm_key, strlen(gm_key)) == 0)	{
++		    from += strlen(gm_key);
++			parse_early_gmmem(from);
++		}
++		else
++			from ++;
++    }
++
++
++    sort(&mem_info.bank, mem_info.nr_banks, sizeof(mem_info.bank[0]), meminfo_cmp, NULL);
++}
++
++/*
++ * @brief get the page with largest physical address and the page with smallest physical address.
++ * @function void get_first_last_page(struct list_head *glist, page_node_t ** small_page,
++                         page_node_t ** large_page)
++ * @return None.
++ */
++void get_first_last_page(struct list_head *glist, page_node_t ** small_page,
++                         page_node_t ** large_page)
++{
++    struct list_head *list;
++    /* the list was sorted in ascendant sequence.
++     * Get the page node with the smallest physical address
++     */
++    list = glist->next;
++    *small_page = (page_node_t *)list_entry(list, page_node_t, list);
++    /* get the page node with the largest physical address */
++    list = glist->prev;
++    *large_page = (page_node_t *)list_entry(list, page_node_t, list);
++}
++
++/*
++ * @brief return the memory to the kernel from frammap
++ *
++ * @function int fmem_give_pages(int node_id, unsigned int give_sz)
++ * @param node_id is the real node id instead of chunk id
++ * @param node_id is the size you want to return to the kernel
++ * @return the real size that gives to the kernel
++ */
++int fmem_give_pages(int bank, unsigned int give_sz)
++{
++    unsigned int ret_sz, size, tmp_sz;
++    page_node_t *large_page, *small_page;
++    struct page *page;
++    u32 phyaddr;
++
++    if (give_sz == 0)
++        return 0;
++
++    ret_sz = 0;
++
++    do {
++        get_first_last_page(&POOL_LIST(bank), &small_page, &large_page);
++        size = (give_sz > large_page->size) ? large_page->size : give_sz;
++        tmp_sz = size;
++
++        /* calculate the last page. Because the page address is embedded in section. So
++         * I am not sure whether we can get the page address by shift.
++         */
++        phyaddr = page_to_phys(large_page->page) + large_page->size - PAGE_SIZE;
++
++        do {
++            page = phys_to_page(phyaddr);
++            ClearPageReserved(page);
++            __free_page(page);
++
++            /* No matter wether the page is freed, we need to decrease the page size
++             */
++            large_page->size -= PAGE_SIZE;
++            phyaddr -= PAGE_SIZE;
++        } while (tmp_sz -= PAGE_SIZE);
++
++        /* free memory */
++        if (!large_page->size) {
++            list_del(&large_page->list);
++            kfree(large_page);
++        }
++
++        give_sz -= size;
++        POOL_NODE_SZ(bank) -= size;
++        ret_sz += size;
++    } while (give_sz != 0);
++
++    return ret_sz;
++}
++EXPORT_SYMBOL(fmem_give_pages);
++
++/*
++ * @brief This function allocates ahead the memory in advance before fragementation happen
++ *
++ * @function int __init fmem_init(void)
++ * @param none
++ * @return none
++ */
++int __init fmem_init(void)
++{
++    int i, bank, order;
++    struct page *page;
++    page_node_t *page_node;
++    u32 mem_sz[2], size, phyaddr;
++    u32 phys_end;
++
++    if (phys_end)   {}
++    /* sanity check */
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        if (bank_phys_start(&mem_info.bank[bank]) & ((0x1 << SECTION_SIZE_BITS) - 1)) {
++            panic("%s, the start address 0x%x in bank%d is not aligned to section size: 0x%x! \n",
++                __func__, bank_phys_start(&mem_info.bank[bank]), bank, (0x1 << SECTION_SIZE_BITS));
++        }
++    }
++    bank = mem_info.nr_banks - 1;
++    phys_end = bank_phys_end(&mem_info.bank[bank]);
++    if ((get_order(phys_end) + PAGE_SHIFT) != MAX_PHYSMEM_BITS)
++        panic("%s, the memory end address is 0x%x, MAX_PHYSMEM_BITS should be %d(current: %d)! \n",
++            __func__, phys_end, get_order(phys_end) + PAGE_SHIFT, MAX_PHYSMEM_BITS);
++#endif
++
++    /* macro test */
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        phyaddr = bank_phys_start(&mem_info.bank[bank]);
++        if (phyaddr != (__virt_to_phys(__phys_to_virt(phyaddr))))
++            panic("%s, macro porting has bug! \n", __func__);
++    }
++
++    order = get_order(ALLOC_BSZ);
++
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        sanity_check_memhole(page_array[bank]);
++        /* count the active node */
++        g_page_info.nr_node++;
++
++        /*
++         * Note: The arguments from boot command line is higher than the MACRO defintion in memory.h.
++         */
++        mem_sz[bank] = gmmem_info.bank[bank].size ?
++                        gmmem_info.bank[bank].size : bank > 0 ? DDR1_FMEM_SIZE : DDR0_FMEM_SIZE;
++
++        /* update 2nd DDR information.
++         * If DDR1_FMEM_SIZE = -1 which means to allocate whole memory.
++         */
++        if ((bank > 0) && (DDR1_FMEM_SIZE == -1) && (mem_sz[bank] == DDR1_FMEM_SIZE))
++            mem_sz[bank] = get_early_memblk_count(page_array[bank]) * ALLOC_BSZ;
++    }
++
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        INIT_LIST_HEAD(&POOL_LIST(bank));
++        POOL_NODE_SZ(bank) = 0;
++
++        /* allocate page_node for each page
++         */
++        for (i = 0; i < reserve_blk_cnt[bank]; i++) {
++            page_node = (page_node_t *)kzalloc(sizeof(page_node_t), GFP_KERNEL);
++            if (page_node == NULL)
++                panic("%s: No memory for kmalloc! \n", __func__);
++            INIT_LIST_HEAD(&page_node->list);
++            page_node->page = (struct page *)page_array[bank][i];
++            page_node->phy_start = page_to_phys(page_node->page);
++            page_node->size = ALLOC_BSZ;
++
++            /* can't be swap out and mmap issue which can be mapped to reserved pages only */
++            page = page_node->page;
++            size = page_node->size;
++            phyaddr = page_node->phy_start;
++            do {
++                /* seperate the group pages into individual page and do the reservation prevent
++                 * those pages from being swapped out.
++                 */
++                init_page_count(page);
++                SetPageReserved(page);
++                phyaddr += PAGE_SIZE;
++                page = phys_to_page(phyaddr);
++            } while (size -= PAGE_SIZE);
++
++            POOL_NODE_SZ(bank) += page_node->size;
++
++            /* add to the global DDR list */
++            list_add_tail(&page_node->list, &POOL_LIST(bank));
++        }
++
++        /* free the rest memory */
++        if (reserve_blk_cnt[bank]) {
++            int ret;
++            u32 free_sz;
++
++            //record the start address of this pool
++            POOL_PHY_START(bank) = page_to_phys((struct page *)page_array[bank][0]);
++            free_sz = reserve_blk_cnt[bank] * ALLOC_BSZ - mem_sz[bank];
++            if (free_sz != 0) {
++                ret = fmem_give_pages(bank, free_sz);
++                if (ret != free_sz)
++                    panic("%s, bug in bank%d! \n", __func__, bank);
++            }
++            printk("FMEM: %d pages(0x%x bytes) from bank%d are reserved for Frammap. \n",
++                mem_sz[bank] >> PAGE_SHIFT, mem_sz[bank], bank);
++        }
++    }
++
++    printk("FMEM: Logical memory ends up at 0x%x, init_mm:0x%x(0x%x), PAGE_OFFSET:0x%x(0x%x), \n",
++                (u32)high_memory, (u32)init_mm.pgd, (u32)__pa((void *)init_mm.pgd),
++                (u32)PAGE_OFFSET, (u32)__pa((void *)PAGE_OFFSET));
++
++#ifdef __enabled_CONFIG_CPU_FA726TE
++    if (1) {
++        volatile unsigned int val;
++
++        __asm__ __volatile__ ("mrc p15, 0, %0, c15, c0, 0\t\n":"=r"(val));
++        printk("FMEM: FA726 Test and Debug Register: 0x%x \n", val);
++    }
++#endif
++
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++    printk("FMEM: SECTION_SIZE_BITS: %d, MAX_PHYSMEM_BITS: %d \n", SECTION_SIZE_BITS, MAX_PHYSMEM_BITS);
++    if (MAX_PHYSMEM_BITS != fmem_max_physmem_bits())
++        panic("%s, the correct MAX_PHYSMEM_BITS(%d) should be changed to %d! \n", __func__,
++                MAX_PHYSMEM_BITS, fmem_max_physmem_bits());
++#endif
++
++    fmem_proc_init();
++
++    return 0;
++}
++
++#ifndef CONFIG_FPGA
++core_initcall(fmem_init);
++#endif
++
++/*
++ * @brief check if the address contains holes
++ *
++ * @function static sanity_check_memhole
++ *
++ * @param base of the first page
++ * @return 0 on success, !0 on error
++ */
++static int __init sanity_check_memhole(u32 *base)
++{
++    struct page *page;
++    dma_addr_t phy_addr, next_phy_addr;
++    int i = 0;
++
++    /* get first page */
++    page = (struct page *)base[0];
++    phy_addr = page_to_phys(page);
++    next_phy_addr = phy_addr + ALLOC_BSZ;
++
++    do {
++        i ++;
++        page = (struct page *)base[i];
++        if (page == NULL)
++            break;
++
++        phy_addr = page_to_phys(page);
++        if (phy_addr != next_phy_addr) {
++            /* dump the content */
++            printk("%s, the expected physical is 0x%x, but get 0x%x \n", __func__, next_phy_addr,
++                    phy_addr);
++            panic("%s, physical address has holes! \n", __func__);
++        }
++        next_phy_addr = phy_addr + ALLOC_BSZ;
++    } while (1);
++
++    return 0;
++}
++
++/*
++ * @brief allocate the memory from linux kernel.
++ * @function void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id)
++ * @parameter size indicates the memory size going to allocate
++ * @parameter dma_handle indicates the physical address
++ * @parameter flags indicates type of this allocated memory is cachable or non-cacheable or ....
++ * @parameter ddr_id indicates which DDR the users want to allocate.
++ * @return virutal memory if success or NULL for fail.
++ */
++void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id)
++{
++    struct page *page;
++    void *cpu_addr = NULL;
++    struct page *end;
++
++    if (ddr_id >= mem_info.nr_banks)
++        return NULL;
++
++    size = PAGE_ALIGN(size);
++    if (size > ALLOC_BSZ) {
++        printk("The allocated memory size 0x%x exceeds 0x%x bytes! \n", size, ALLOC_BSZ);
++        return NULL;
++    }
++
++    page = alloc_pages_node(ddr_id, GFP_KERNEL, get_order(size));
++    if (!page) {
++        printk("alloc_pages fail! (requested %#x)", size);
++        goto no_page;
++    }
++
++    *dma_handle = page_to_phys(page);
++    if ((*dma_handle < bank_phys_start(&mem_info.bank[ddr_id])) ||
++            (*dma_handle > bank_phys_end(&mem_info.bank[ddr_id]))) {
++        __free_pages(page, get_order(size));
++        goto no_page;
++    }
++
++    if ((flags == PAGE_COPY) || (flags == PAGE_SHARED))
++        //cpu_addr = ioremap_cached(*dma_handle, size);
++        cpu_addr = __va(*dma_handle);
++    else if (flags == pgprot_writecombine(pgprot_kernel))
++        cpu_addr = ioremap_wc(*dma_handle, size);
++    else
++        cpu_addr = ioremap_nocache(*dma_handle, size);
++
++    if (cpu_addr) {
++        end = page + (1 << get_order(size));
++        do {
++            init_page_count(page);
++            SetPageReserved(page);
++            page++;
++            size -= PAGE_SIZE;
++        } while (size != 0);
++
++        /*
++         * Free the otherwise unused pages.
++         */
++        while (page < end) {
++            init_page_count(page);
++            if (!PageReserved(page) && put_page_testzero(page))
++                __free_page(page);
++            page++;
++        }
++    } else {
++        __free_pages(page, get_order(size));
++        printk("__ioremap fail! (phy %#x)", *dma_handle);
++    }
++
++  no_page:
++    return cpu_addr;
++}
++EXPORT_SYMBOL(fmem_alloc_ex);
++
++/*
++ * @brief free the memory which was allocated by fmem_alloc_ex().
++ * @function void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle)
++ * @parameter size indicates the memory size going to free
++ * @parameter cpu_addr indicates the virtual memory going to free
++ * @parameter handle indicates the physical memory going to free
++ * @return None.
++ */
++void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle)
++{
++    struct page *page = pfn_to_page(handle >> PAGE_SHIFT);
++    struct page *pg;
++    unsigned int sz;
++
++    pg = page;
++    sz = size;
++
++    if ((u32)__va(handle) != (u32)cpu_addr)
++        __iounmap(cpu_addr);
++
++    size = PAGE_ALIGN(size);
++
++    do {
++        ClearPageReserved(page);
++        if (!PageReserved(page) && put_page_testzero(page))
++            __free_page(page);
++        page++;
++    } while (size -= PAGE_SIZE);
++}
++EXPORT_SYMBOL(fmem_free_ex);
++
++/**
++ * @brief to resolve the virtual address (including direct mapping, ioremap or user space address to
++ *      its real physical address.
++ *
++ * @parm vaddr indicates any virtual address
++ *
++ * @return  >= 0 for success, 0xFFFFFFFF for fail
++ */
++phys_addr_t fmem_lookup_pa(unsigned int vaddr)
++{
++    pgd_t *pgdp;
++    pmd_t *pmdp;
++    pud_t *pudp;
++    pte_t *ptep;
++    phys_addr_t paddr = 0xFFFFFFFF;
++
++    /* for speed up */
++    if (virt_addr_valid(vaddr))
++        return (phys_addr_t)__pa(vaddr);
++
++    /*
++     * The pgd is never bad, and a pmd always exists(as it's folded into the pgd entry)
++     */
++    if (vaddr >= TASK_SIZE) /* use init_mm as mmu to look up in kernel mode */
++        pgdp = pgd_offset_k(vaddr);
++    else
++        pgdp = pgd_offset(current->mm, vaddr);
++
++    if (unlikely(pgd_none(*pgdp))) {
++        printk("fmem: 0x%x not mapped in pgd table! \n", vaddr);
++        goto err;
++    }
++
++    /* because we don't have 3-level MMU, so pud = pgd. Here we are in order to meet generic Linux
++     * version, pud is listed here.
++     */
++    pudp = pud_offset(pgdp, vaddr);
++    if (unlikely(pud_none(*pudp))) {
++        printk(KERN_INFO"fmem: 0x%x not mapped in pud table! \n", vaddr);
++        goto err;
++    }
++
++    pmdp = pmd_offset(pudp, vaddr);
++    if (unlikely(pmd_none(*pmdp))) {
++        printk(KERN_INFO"fmem: 0x%x not mapped in pmd 0x%x! \n", vaddr, (u32)pmdp);
++        goto err;
++    }
++
++    if (!pmd_bad(*pmdp)) {
++        u32 v_addr;
++
++        /* page mapping */
++        ptep = pte_offset_kernel(pmdp, vaddr);
++        if (pte_none(*ptep)) {
++            printk(KERN_ERR"fmem: 0x%x not mapped in pte! \n", vaddr);
++            goto err;
++        }
++
++        v_addr = (unsigned int)page_address(pte_page(*ptep)) + (vaddr & (PAGE_SIZE - 1));
++        paddr = __pa(v_addr);
++    } else {
++        /* section mapping. The cases are:
++         * 1. DDR direct mapping
++         * 2. ioremap's vaddr, size and paddr all are 2M alignment.
++         */
++        if (vaddr & SECTION_SIZE)
++            pmdp ++; /* move to pmd[1] */
++        paddr = (pmd_val(*pmdp) & SECTION_MASK) | (vaddr & ~SECTION_MASK);
++    }
++err:
++    return paddr;
++}
++EXPORT_SYMBOL(fmem_lookup_pa);
++
++/*
++ * @brief get the memory data information from frammap
++ *
++ * @function fmem_get_pageinfo(g_page_info_t **pg_info)
++ * @param pg_info is the pointer wants to be assigned the info
++ * @return none
++ */
++void fmem_get_pageinfo(g_page_info_t ** pg_info)
++{
++    *pg_info = &g_page_info;
++
++    return;
++}
++EXPORT_SYMBOL(fmem_get_pageinfo);
++
++/* __virt_to_phys macro porting arch/arm/include/mach/memory.h */
++unsigned long fmem_virt_to_phys(unsigned int vaddr)
++{
++    unsigned long phys;
++
++    if (mem_info.nr_banks == 0) {
++        phys = vaddr - PAGE_OFFSET + PHYS_OFFSET;
++
++        printk("%s, someone calls va2pa early............................. \n", __func__);
++
++        return phys;
++    }
++
++    if (mem_info.nr_banks == 1) {
++        phys = vaddr - PAGE_OFFSET + PHYS_OFFSET;
++    } else {
++        u32 end_vaddr;
++
++        end_vaddr = PAGE_OFFSET + bank_phys_size(&mem_info.bank[0]);
++        phys = vaddr >= end_vaddr ? (vaddr - end_vaddr) + bank_phys_start(&mem_info.bank[1]) :
++            (vaddr - PAGE_OFFSET) + bank_phys_start(&mem_info.bank[0]);
++    }
++
++    return phys;
++}
++
++/* __phys_to_virt macro porting in arch/arm/include/mach/memory.h */
++unsigned int fmem_phys_to_virt(unsigned long phys)
++{
++    u32 vaddr;
++
++    if (mem_info.nr_banks == 0) {
++         vaddr = phys - PHYS_OFFSET + PAGE_OFFSET;
++         printk("%s, someone calls pa2va early............................. \n", __func__);
++         return vaddr;
++    }
++
++    if (mem_info.nr_banks == 1) {
++        vaddr = phys - PHYS_OFFSET + PAGE_OFFSET;
++    } else {
++        vaddr = (phys >= bank_phys_start(&mem_info.bank[1])) ?
++            PAGE_OFFSET + bank_phys_size(&mem_info.bank[0]) + (phys - bank_phys_start(&mem_info.bank[1])) :
++            PAGE_OFFSET + (phys - PHYS_OFFSET);
++    }
++
++    return vaddr;
++}
++
++/*
++ * @This function is used to read CPU id and pci id
++ * @Return value: 0 for success, -1 for fail
++ */
++int fmem_get_identifier(fmem_pci_id_t *pci_id, fmem_cpu_id_t *cpu_id)
++{
++    int ret = 0;
++    u32 value;
++
++
++    /* Read CR0-0 Identification Code Register(ID)
++     * [31:24] IMP, [23:16]ARCH, [15:4] PART, [3:0] VER
++     */
++    __asm__ __volatile__ ("mrc p15, 0, %0, c0, c0, 0\t\n": "=r"(value));
++
++    switch ((value >> 0x4) & 0xFFF) {
++      case 0x626:
++        /* the code should be 0x66056261 */
++        *cpu_id = FMEM_CPU_FA626;
++
++#if __enabled_CONFIG_CPU_FA726TE
++        panic("This driver compiled in FA726 environment CANNOT be executed in FA626! \n");
++        ret = -1;
++#endif
++        break;
++      case 0x726:
++        *cpu_id = FMEM_CPU_FA726;
++#if __enabled_CONFIG_CPU_FA626TE
++        panic("This driver compiled in FA626 environment CANNOT be executed in FA726! \n");
++        ret = -1;
++#endif
++        break;
++      default:
++        *cpu_id = FMEM_CPU_UNKNOWN;
++        panic("Unknow cpu id: 0x%x \n", value);
++        break;
++    }
++
++    *pci_id = FMEM_PCI_HOST;
++
++    return ret;
++}
++EXPORT_SYMBOL(fmem_get_identifier);
++
++static void dev_release(struct device *dev) { return; }
++#define DRIVER_NAME "fmem_sync"
++static struct platform_device pseudo_dev = {
++	.name = DRIVER_NAME,
++	.id   = 0,
++	.num_resources = 0,
++	.dev  = {
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++		.release = dev_release,
++	}
++};
++
++/* process outer cache */
++static inline void __fmem_sync_outer_cache(void *vaddr, u32 len, enum dma_data_direction dir)
++{
++#ifdef CONFIG_OUTER_CACHE
++    phys_addr_t  paddr;
++
++    paddr = fmem_lookup_pa((unsigned int)vaddr);
++    if (paddr == 0xFFFFFFFF)
++        return;
++
++    switch (dir) {
++      case DMA_BIDIRECTIONAL:
++        outer_flush_range(paddr, paddr + len);
++        break;
++      case DMA_TO_DEVICE:
++        outer_clean_range(paddr, paddr + len);
++        break;
++      case DMA_FROM_DEVICE:
++        outer_inv_range(paddr, paddr + len);
++        break;
++      case DMA_NONE:
++        break;
++    }
++#endif
++}
++
++/* @this function is a data cache operation function,
++ * @parm: vaddr: any virtual address
++ * @parm: dir will be:
++ * DMA_BIDIRECTIONAL = 0, it means flush operation.
++ * DMA_TO_DEVICE = 1, it means clean operation.
++ * DMA_FROM_DEVICE = 2, it means invalidate operation.
++ * DMA_NONE = 3,
++ */
++void fmem_dcache_sync(void *vaddr, u32 len, enum dma_data_direction dir)
++{
++    struct device *dev = &pseudo_dev.dev;
++
++    if (!valid_dma_direction(dir))
++        panic("%s, invalid direction: %d \n", __func__, dir);
++
++    /* kernel buffer may not cache line alignment, it only can use both clean/inv
++     * for safe. Others we regard them as warning cases in coding.
++     */
++    if (dir != DMA_BIDIRECTIONAL) {
++        if ((u32)vaddr & CACHE_ALIGN_MASK) {
++            va_not_32align ++;
++            if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_VA)) {
++                printk("%s, warning, vaddr: 0x%x not cache alignment! \n", __func__, (u32)vaddr);
++                dump_stack();
++            }
++        }
++
++        if (len & CACHE_ALIGN_MASK) {
++            length_not_32align ++;
++            if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_LEN)) {
++                printk("%s, warning, len: %d not cache alignment! \n", __func__, len);
++                dump_stack();
++            }
++        }
++    }
++
++    if (virt_addr_valid(vaddr) && virt_addr_valid(vaddr + len - 1)) {
++        switch (dir) {
++          case DMA_BIDIRECTIONAL:
++            dma_map_single(dev, vaddr, len, DMA_BIDIRECTIONAL);
++            /* the purpose is for outer cache sync. dma_map_single() only did
++             * outer_clean_range() in arch/arm/mm/dma-mapping.c (#554), why?
++             */
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            //dma_unmap_single(dev, __pa(vaddr), len, DMA_FROM_DEVICE);
++            break;
++          case DMA_TO_DEVICE:
++            dma_map_single(dev, vaddr, len, DMA_TO_DEVICE);
++            /* outer cache will invoke clean function. */
++            break;
++          case DMA_FROM_DEVICE:
++            dma_map_single(dev, vaddr, len, DMA_FROM_DEVICE);
++            /* outer cache will invoke invalidate function. */
++            break;
++          case DMA_NONE:
++            break;
++        }
++        cpuaddr_flush ++;
++    } else {
++        switch (dir) {
++          case DMA_BIDIRECTIONAL:
++            dmac_flush_range(vaddr, vaddr + len);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_TO_DEVICE:
++            dmac_map_area(vaddr, len, DMA_TO_DEVICE);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_FROM_DEVICE:
++            dmac_map_area(vaddr, len, DMA_FROM_DEVICE);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_NONE:
++            break;
++        }
++        nonlinear_cpuaddr_flush ++;
++        if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_API)) {
++            printk("%s, warning, memory addr 0x%x not direct mapped! \n", __func__, (u32)vaddr);
++            dump_stack();
++        }
++    }
++}
++EXPORT_SYMBOL(fmem_dcache_sync);
++
++/* The following functions are valid in GM8210 and adopted by videgraph.
++ */
++int fmem_set_ep_outbound_win(u32 phy_addr, u32 size) { return 0; }
++EXPORT_SYMBOL(fmem_set_ep_outbound_win);
++
++u32 fmem_get_pcie_addr(u32 axi_phy_addr) { return axi_phy_addr; }
++EXPORT_SYMBOL(fmem_get_pcie_addr);
++
++u32 fmem_get_axi_addr(u32 pcie_phy_addr) { return pcie_phy_addr; }
++EXPORT_SYMBOL(fmem_get_axi_addr);
++
++void CheckTxStatus(unsigned int port)
++{
++		// wait until Tx ready
++    while (!(*(volatile unsigned int *)(port + 0x14) & 0x20));
++      udelay(1);
++}
++
++static void _putchar(char Ch)
++{
++    if(Ch != '\0'){
++        CheckTxStatus(UART_FTUART010_0_VA_BASE);
++        *(volatile unsigned int *)(UART_FTUART010_0_VA_BASE) = Ch;
++    }
++
++    if (Ch == '\n'){
++        CheckTxStatus(UART_FTUART010_0_VA_BASE);
++        *(volatile unsigned int *)(UART_FTUART010_0_VA_BASE) = '\r';
++    }
++}
++
++static int debug_init = 0;
++/* If we want to use this API, please enable arch/arm/kernel/head.S
++ * GM_CONSOLE_PRINT definition
++*/
++void debug_printk(const char *f, ...)
++{
++    volatile unsigned int i;
++    va_list arg_ptr;
++    char buffer[256];
++
++    if (0) { //!debug_init) {
++        volatile unsigned int val, ttbr;
++        debug_init = 1;
++
++        __asm__ __volatile__ ("mrc p15, 0, %0, c2, c0, 0\t\n":"=r"(ttbr));
++
++        ttbr = PAGE_OFFSET + (ttbr - PHYS_OFFSET);  //because the __va can't work at this moment (mem_info[] no data yet)
++        val = *(u32 *)(ttbr + (UART_FTUART010_0_VA_BASE >> 18));
++        //uart temp mapping
++        if (!val) {
++            *(u32 *)(ttbr + (UART_FTUART010_0_VA_BASE >> 18)) = (UART_FTUART010_0_PA_BASE | 0xC12);
++
++            //neet to flush dcache and tlb?
++            __asm__ __volatile__ ("mov r0, #0\n"
++                                  "mcr p15, 0, r0, c7, c10, 3\n"    /* Test and Clean DCache */
++                                  "mcr p15, 0, r0, c7, c10, 4\n"    /* drain WB */
++                                  "mcr p15, 0, r0, c8, c7, 0");	    /* invalidate TLB all */
++        }
++    }
++
++    va_start(arg_ptr, f);
++    vsprintf(&buffer[0], f, arg_ptr);
++    va_end(arg_ptr);
++
++      //output the buffer
++    i = 0;
++    while (buffer[i]){
++          _putchar(buffer[i]);
++          i++;
++    }
++}
++
++EXPORT_SYMBOL(debug_printk);
++EXPORT_SYMBOL(fmem_virt_to_phys);
++EXPORT_SYMBOL(fmem_phys_to_virt);
++
+diff --git a/arch/arm/mach-GM-SMP/ftapbb020.c b/arch/arm/mach-GM-SMP/ftapbb020.c
+new file mode 100644
+index 00000000..40e2d641
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/ftapbb020.c
+@@ -0,0 +1,1374 @@
++/*
++ * Faraday FTAPBB020 DMA engine driver
++ *
++ * (C) Copyright 2010 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <asm/io.h>
++
++#include <mach/ftapbb020.h>
++
++#define DRV_NAME	"ftapbb020"
++#define CHANNEL_NR	4
++
++/*
++ * This value must be multiple of 32-bits to prevent from changing the
++ * alignment of child descriptors.
++ */
++#define MAX_CYCLE_PER_BLOCK		0x00800000
++#if (MAX_CYCLE_PER_BLOCK > FTAPBB020_CYC_MASK) || (MAX_CYCLE_PER_BLOCK & 0x3)
++#error invalid MAX_CYCLE_PER_BLOCK
++#endif
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 64;
++module_param(init_nr_desc_per_channel, uint, 0644);
++MODULE_PARM_DESC(init_nr_desc_per_channel,
++		 "initial descriptors per channel (default: 64)");
++
++/**
++ * struct ftapbb020_desc - async transaction descriptor.
++ * @txd: support for the async_tx api
++ * @node: node on the descriptors list
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @cmd: command register content
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @value: buf value for memset usage
++ * @len: length in bytes
++ */
++struct ftapbb020_desc {
++	struct dma_async_tx_descriptor txd;
++	struct list_head node;
++	struct list_head child_list;
++	struct ftapbb020_chan *ftchan;
++	unsigned int cmd;
++	dma_addr_t src;
++	dma_addr_t dst;
++	unsigned int cycle;
++	unsigned int value;
++	size_t len;
++};
++
++/**
++ * struct ftapbb020_chan - internal representation of an ftapbb020 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @pending_list: list of descriptors dmaengine which is wating to run
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftapbb020: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftapbb020_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head pending_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftapbb020 *ftapbb020;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++};
++
++/**
++ * struct ftapbb020 - internal representation of an ftapbb020 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @irq: irq number
++ * @channel: channel table
++ */
++struct ftapbb020 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	unsigned int irq;
++	struct ftapbb020_chan channel[CHANNEL_NR];
++};
++
++static dma_cookie_t ftapbb020_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftapbb020_stop_channel(struct ftapbb020_chan *ftchan)
++{
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	iowrite32(0, base + FTAPBB020_OFFSET_CMD(chan_id));
++}
++
++static void ftapbb020_stop_all_channels(struct ftapbb020 *ftapbb020)
++{
++	void __iomem *base = ftapbb020->base;
++	int i;
++
++	for (i = 0; i < CHANNEL_NR; i++)
++		iowrite32(0, base + FTAPBB020_OFFSET_CMD(i));
++}
++
++static int ftapbb020_chan_is_enabled(struct ftapbb020_chan *ftchan)
++{
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++	unsigned int cmd;
++
++	cmd = ioread32(base + FTAPBB020_OFFSET_CMD(chan_id));
++	return cmd & FTAPBB020_CMD_ENABLE;
++}
++
++/**
++ * ftapbb020_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftapbb020_desc *ftapbb020_alloc_desc(struct ftapbb020_chan
++						   *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = kzalloc(sizeof(*desc), gfp_flags);
++	if (desc) {
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftapbb020_tx_submit;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftapbb020_free_desc(struct ftapbb020_desc *desc)
++{
++	struct dma_chan *chan = &desc->ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	kfree(desc);
++}
++
++/**
++ * ftapbb020_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftapbb020_desc *ftapbb020_desc_get(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc = NULL;
++
++	spin_lock_bh(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++					struct ftapbb020_desc, node);
++
++		list_del(&desc->node);
++	}
++	spin_unlock_bh(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftapbb020_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			spin_lock_bh(&ftchan->lock);
++			ftchan->descs_allocated++;
++			spin_unlock_bh(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftapbb020_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftapbb020_desc_put(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *child;
++
++	spin_lock_bh(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++static void ftapbb020_unmap_desc(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->dst, desc->len,
++					 DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->dst, desc->len,
++				       DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->src, desc->len,
++					 DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->src, desc->len,
++				       DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftapbb020_remove_chain(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *child;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->node, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftapbb020_unmap_desc(child);
++		ftapbb020_desc_put(child);
++	}
++
++	ftapbb020_unmap_desc(desc);
++	ftapbb020_desc_put(desc);
++}
++
++/**
++ * ftapbb020_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * @cmd: command register content
++ */
++static struct ftapbb020_desc *
++ftapbb020_create_chain(struct ftapbb020_chan *ftchan,
++			struct ftapbb020_desc *first,
++			dma_addr_t src,	dma_addr_t dest,
++			size_t len, unsigned int shift,
++			int fixed_src, int fixed_dest, unsigned int cmd)
++{
++	struct dma_chan *chan = &ftchan->common;
++	size_t offset;
++	unsigned int cycle;
++	bool is_memset = false;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, shift %d)\n",
++		__func__, src, dest, len, shift);
++
++	/* Check for memset */
++	if (cmd ==
++	    (FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB |
++	     FTAPBB020_CMD_SRC_MODE_FIXED | FTAPBB020_CMD_WIDTH_WORD |
++	     FTAPBB020_CMD_DST_MODE_WORD_INC)) {
++		is_memset = true;
++	}
++
++	if ((shift == 2 && ((src | dest | len) & 3)) ||
++	    (shift == 1 && ((src | dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	for (offset = 0; offset < len; offset += cycle << shift) {
++		struct ftapbb020_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> shift,
++			      MAX_CYCLE_PER_BLOCK);
++
++		cycle &= FTAPBB020_CYC_MASK;
++
++		desc = ftapbb020_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		if (is_memset) {
++			/* use fixed_dest as value */
++			desc->value = fixed_dest;
++			src = __pa(&(desc->value));
++		}
++
++		if (fixed_src)
++			desc->src = src;
++		else
++			desc->src = src + offset;
++
++		if (fixed_dest && !is_memset)
++			desc->dst = dest;
++		else
++			desc->dst = dest + offset;
++
++		desc->cmd = cmd;
++		desc->len = cycle << shift;
++		desc->cycle = cycle;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++	}
++
++	return first;
++err:
++	if (first)
++		ftapbb020_remove_chain(first);
++	return NULL;
++}
++
++static void ftapbb020_start_desc(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	unsigned int cmd = desc->cmd;
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	cmd |= FTAPBB020_CMD_ENABLE
++	    | FTAPBB020_CMD_FININT_E | FTAPBB020_CMD_ERRINT_E;
++
++	dev_dbg(chan2dev(chan), "\t[SAR %d] = %x\n", chan_id, desc->src);
++	iowrite32(desc->src, base + FTAPBB020_OFFSET_SAR(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DAR %d] = %x\n", chan_id, desc->dst);
++	iowrite32(desc->dst, base + FTAPBB020_OFFSET_DAR(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	iowrite32(desc->cycle, base + FTAPBB020_OFFSET_CYC(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CMD %d] = %x\n", chan_id, cmd);
++	iowrite32(cmd, base + FTAPBB020_OFFSET_CMD(chan_id));
++}
++
++static void ftapbb020_activate_chain(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	/* move new transfer chain to active list */
++	list_add_tail(&desc->node, &ftchan->active_list);
++	list_splice_tail_init(&desc->child_list, &ftchan->active_list);
++
++	/* start first descriptor */
++	ftapbb020_start_desc(desc);
++}
++
++static void ftapbb020_start_next_chain(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *new;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->pending_list))
++		return;
++
++	new = list_first_entry(&ftchan->pending_list, struct ftapbb020_desc,
++			       node);
++	list_del(&new->node);
++
++	ftapbb020_activate_chain(new);
++}
++
++static void ftapbb020_invoke_callback(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	ftchan->completed_cookie = desc->txd.cookie;
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback)
++		desc->txd.callback(desc->txd.callback_param);
++}
++
++static void ftapbb020_finish_all_pending_chains(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->pending_list, node) {
++		list_del(&desc->node);
++		ftapbb020_invoke_callback(desc);
++		ftapbb020_remove_chain(desc);
++	}
++}
++
++static void ftapbb020_finish_active_chain(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftapbb020_desc,
++				node);
++	/* first descriptor in the active list has callback fields */
++	ftapbb020_invoke_callback(desc);
++
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftapbb020_unmap_desc(desc);
++		ftapbb020_desc_put(desc);
++	}
++}
++
++static void ftapbb020_finish_all_chains(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftapbb020_finish_active_chain(ftchan);
++	ftapbb020_finish_all_pending_chains(ftchan);
++}
++
++static dma_cookie_t ftapbb020_new_cookie(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftapbb020_chan_filter(struct dma_chan * chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftapbb020_dma_slave *slave = data;
++
++	if (strncmp(DRV_NAME, drv_name, sizeof(DRV_NAME))) {
++		printk(KERN_DEBUG"driver name: %s wrong!\n", drv_name);
++		return false;
++	}
++
++#if 0 /* Let channels be controlled by dma subsystem, by eason */
++	if ((slave->channels & (1 << chan->chan_id)) == 0) {
++		printk(KERN_WARNING"channel doesn't match!\n");
++		return false;
++	}
++#endif
++
++	chan->private = slave;
++	return true;
++}
++
++EXPORT_SYMBOL_GPL(ftapbb020_chan_filter);
++
++/******************************************************************************
++ * tasklet - called after we finished one chunk
++ *****************************************************************************/
++static void ftapbb020_tasklet(unsigned long data)
++{
++	struct ftapbb020_chan *ftchan = (struct ftapbb020_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	BUG_ON(list_empty(&ftchan->active_list));
++
++	spin_lock_bh(&ftchan->lock);
++
++	/* remove already finished descriptor */
++	desc = list_first_entry(&ftchan->active_list, struct ftapbb020_desc,
++				node);
++	list_del(&desc->node);
++
++	if (list_empty(&ftchan->active_list)) {
++		ftapbb020_invoke_callback(desc);
++		ftapbb020_start_next_chain(ftchan);
++	} else {
++		struct ftapbb020_desc *next;
++
++		/* Do next descriptor in the trasnfer chain */
++		next = list_first_entry(&ftchan->active_list,
++					struct ftapbb020_desc, node);
++
++		/*
++		 * Always keep the txd fields in the first descriptor in the
++		 * active list.
++		 */
++		next->txd.cookie = desc->txd.cookie;
++		next->txd.flags = desc->txd.flags;
++		next->txd.callback = desc->txd.callback;
++		next->txd.callback_param = desc->txd.callback_param;
++
++		ftapbb020_start_desc(next);
++	}
++
++	ftapbb020_unmap_desc(desc);
++	spin_unlock_bh(&ftchan->lock);
++	ftapbb020_desc_put(desc);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftapbb020_interrupt(int irq, void *dev_id)
++{
++	struct ftapbb020 *ftapbb020 = dev_id;
++	struct device *dev = ftapbb020->dma.dev;
++	irqreturn_t ret = IRQ_NONE;
++	unsigned int sr;
++	int i;
++
++	sr = ioread32(ftapbb020->base + FTAPBB020_OFFSET_SR);
++	if (sr & FTAPBB020_SR_BWERRINT) {
++		dev_info(dev, "bufferable write error\n");
++		ret = IRQ_HANDLED;
++	}
++
++	/* clear SR */
++	iowrite32(sr, ftapbb020->base + FTAPBB020_OFFSET_SR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++		void __iomem *base = ftchan->ftapbb020->base;
++		int chan_id = ftchan->common.chan_id;
++		unsigned int cmd;
++
++		/*
++		 * status bits in command register?
++		 * what a brain-damaged design.
++		 */
++		cmd = ioread32(base + FTAPBB020_OFFSET_CMD(chan_id));
++
++		if (cmd & FTAPBB020_CMD_FININT_S) {
++			tasklet_schedule(&ftchan->tasklet);
++			ret = IRQ_HANDLED;
++		} else if (cmd & FTAPBB020_CMD_ERRINT_S) {
++			dev_err(chan2dev(chan), "error happened\n");
++			ret = IRQ_HANDLED;
++		}
++
++		if (cmd & (FTAPBB020_CMD_FININT_S | FTAPBB020_CMD_ERRINT_S)) {
++			/* clear interrupt status */
++			cmd &=
++			    ~(FTAPBB020_CMD_FININT_S | FTAPBB020_CMD_ERRINT_S);
++			iowrite32(cmd, base + FTAPBB020_OFFSET_CMD(chan_id));
++		}
++	}
++
++	return ret;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftapbb020_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftapbb020_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++
++	desc = container_of(txd, struct ftapbb020_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	spin_lock_bh(&ftchan->lock);
++
++	cookie = ftapbb020_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list)) {
++#if 0				/* Just add desc into active_list, not start doing tx */
++		ftapbb020_activate_chain(desc);
++#else
++		list_add_tail(&desc->node, &ftchan->active_list);
++		list_splice_tail_init(&desc->child_list, &ftchan->active_list);
++#endif
++	} else {
++		list_add_tail(&desc->node, &ftchan->pending_list);
++	}
++
++	spin_unlock_bh(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftapbb020_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftapbb020_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftapbb020_desc *desc;
++
++		desc = ftapbb020_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	spin_lock_bh(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list);
++	ftchan->completed_cookie = chan->cookie = 1;
++	spin_unlock_bh(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftapbb020_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftapbb020_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++	struct ftapbb020 *ftapbb020;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++	ftapbb020 = ftchan->ftapbb020;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(!list_empty(&ftchan->pending_list));
++	BUG_ON(ftapbb020_chan_is_enabled(ftchan));
++
++	spin_lock_bh(&ftchan->lock);
++	ftapbb020_stop_channel(ftchan);
++	ftapbb020_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftapbb020_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/**
++ * ftapbb020_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++			dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	unsigned int shift;
++	unsigned int cmd;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	/* Assume RAM is on AHB bus. */
++	cmd = FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB;
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++		cmd |= FTAPBB020_CMD_WIDTH_WORD
++		    | FTAPBB020_CMD_DST_MODE_WORD_INC
++		    | FTAPBB020_CMD_SRC_MODE_WORD_INC;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++		cmd |= FTAPBB020_CMD_WIDTH_HALF
++		    | FTAPBB020_CMD_DST_MODE_HALF_INC
++		    | FTAPBB020_CMD_SRC_MODE_HALF_INC;
++	} else {
++		shift = 0;
++		cmd |= FTAPBB020_CMD_WIDTH_BYTE
++		    | FTAPBB020_CMD_DST_MODE_BYTE_INC
++		    | FTAPBB020_CMD_SRC_MODE_BYTE_INC;
++	}
++
++	desc =
++	    ftapbb020_create_chain(ftchan, NULL, src, dest, len, shift, 0, 0,
++				   cmd);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	desc->cmd = cmd;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftapbb020_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @value: the given value for memset used
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest,
++			int value, size_t len, unsigned long flags)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	unsigned int shift;
++	unsigned int cmd;
++
++	dev_dbg(chan2dev(chan), "%s(dest %x, value %x, len %x)\n",
++		__func__, dest, value, len);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(len & 3)) {
++		dev_info(chan2dev(chan), "%s: length isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(dest & 3)) {
++		dev_info(chan2dev(chan), "%s: dest addr isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	/* Assume RAM is on AHB bus. */
++	cmd = FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB;
++
++	/* src address is from mem buf */
++	cmd |= FTAPBB020_CMD_SRC_MODE_FIXED;
++
++	/* dst address should be word align */
++	shift = 2;
++	cmd |= FTAPBB020_CMD_WIDTH_WORD | FTAPBB020_CMD_DST_MODE_WORD_INC;
++
++	desc =
++	    ftapbb020_create_chain(ftchan, NULL, 0, dest, len, shift, 1, value,
++				   cmd);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	desc->cmd = cmd;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftapbb020_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++			unsigned int sg_len,
++			enum dma_transfer_direction direction,
++			unsigned long flags)
++{
++	struct ftapbb020_dma_slave *slave = chan->private;
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int cmd;
++	unsigned int shift;
++	unsigned int i;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (direction) {
++	case DMA_MEM_TO_DEV:
++		cmd = FTAPBB020_CMD_DST_MODE_FIXED
++		    | FTAPBB020_CMD_DST_HANDSHAKE(slave->handshake);
++
++		/* Assume RAM is on AHB bus. */
++		cmd |= FTAPBB020_CMD_SRC_TYPE_AHB;
++
++		switch (slave->type) {
++		case FTAPBB020_BUS_TYPE_AHB:
++			cmd |= FTAPBB020_CMD_DST_TYPE_AHB;
++			break;
++		case FTAPBB020_BUS_TYPE_APB:
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect bus type\n",
++				__func__);
++			BUG();
++		}
++
++		switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			shift = 0;
++			cmd |= FTAPBB020_CMD_WIDTH_BYTE
++			    | FTAPBB020_CMD_SRC_MODE_BYTE_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			shift = 1;
++			cmd |= FTAPBB020_CMD_WIDTH_HALF
++			    | FTAPBB020_CMD_SRC_MODE_HALF_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			shift = 2;
++			cmd |= FTAPBB020_CMD_WIDTH_WORD
++			    | FTAPBB020_CMD_SRC_MODE_WORD_INC;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++				__func__);
++			BUG();
++		}
++
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftapbb020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftapbb020_create_chain(ftchan, desc,
++						     mem,
++						     slave->common.dst_addr,
++						     len, shift, 0, 1, cmd);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++		break;
++	case DMA_DEV_TO_MEM:
++		cmd = FTAPBB020_CMD_SRC_MODE_FIXED
++		    | FTAPBB020_CMD_SRC_HANDSHAKE(slave->handshake);
++
++		/* Assume RAM is on AHB bus. */
++		cmd |= FTAPBB020_CMD_DST_TYPE_AHB;
++
++		switch (slave->type) {
++		case FTAPBB020_BUS_TYPE_AHB:
++			cmd |= FTAPBB020_CMD_SRC_TYPE_AHB;
++			break;
++		case FTAPBB020_BUS_TYPE_APB:
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect bus type\n",
++				__func__);
++			BUG();
++		}
++
++		switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			shift = 0;
++			cmd |= FTAPBB020_CMD_WIDTH_BYTE
++			    | FTAPBB020_CMD_DST_MODE_BYTE_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			shift = 1;
++			cmd |= FTAPBB020_CMD_WIDTH_HALF
++			    | FTAPBB020_CMD_DST_MODE_HALF_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			shift = 2;
++			cmd |= FTAPBB020_CMD_WIDTH_WORD
++			    | FTAPBB020_CMD_DST_MODE_WORD_INC;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++				__func__);
++			BUG();
++		}
++
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftapbb020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftapbb020_create_chain(ftchan, desc,
++						     slave->common.src_addr,
++						     mem, len, shift, 1, 0,
++						     cmd);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n", __func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftapbb020_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++			     unsigned long arg)
++{
++	struct ftapbb020_chan *ftchan;
++	int ret = -ENXIO;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (cmd == DMA_SLAVE_CONFIG) {
++		struct dma_slave_config *slave_config = (struct dma_slave_config *)arg;
++		struct ftapbb020_dma_slave  *dma_slave;
++
++		dma_slave = container_of(slave_config, struct ftapbb020_dma_slave, common);
++		chan->private = dma_slave;
++		ret = 0;
++	} 
++
++	if (cmd == DMA_TERMINATE_ALL) {
++		/*
++		 * This is only called when something went wrong elsewhere, so
++		 * we don't really care about the data. Just disable the channel.
++		 */
++		spin_lock_bh(&ftchan->lock);
++		ftapbb020_stop_channel(ftchan);
++		ftapbb020_finish_all_chains(ftchan);
++		spin_unlock_bh(&ftchan->lock);
++	}
++
++	return ret;
++}
++
++/**
++ * ftapbb020_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftapbb020_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		    struct dma_tx_state *txstate)
++{
++	struct ftapbb020_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftapbb020_issue_pending - try to finish work
++ * @chan: target DMA channel
++ */
++static void ftapbb020_issue_pending(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (list_empty(&ftchan->active_list)) {
++		spin_lock_bh(&ftchan->lock);
++		ftapbb020_start_next_chain(ftchan);
++		spin_unlock_bh(&ftchan->lock);
++	} else {		/* Disable starting tx in tx_submit, start here */
++		desc =
++		    list_first_entry(&ftchan->active_list,
++				     struct ftapbb020_desc, node);
++		ftapbb020_start_desc(desc);
++	}
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftapbb020_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftapbb020 *ftapbb020;
++	struct dma_device *dma;
++	int irq;
++	int i;
++	int err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftapbb020 = kzalloc(sizeof(*ftapbb020), GFP_KERNEL);
++	if (!ftapbb020) {
++		return -ENOMEM;
++	}
++
++	dma = &ftapbb020->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftapbb020);
++
++	/* map io memory */
++
++	ftapbb020->res =
++	    request_mem_region(res->start, res->end - res->start + 1,
++			       dev_name(&pdev->dev));
++	if (ftapbb020->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftapbb020->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftapbb020->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* force dma off, just in case */
++	ftapbb020_stop_all_channels(ftapbb020);
++
++	/* initialize channels */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->pending_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device = dma;
++		ftchan->common.cookie = DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftapbb020 = ftapbb020;
++		ftchan->completed_cookie = DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftapbb020_tasklet,
++			     (unsigned long)ftchan);
++
++		list_add_tail(&ftchan->common.device_node, &dma->channels);
++	}
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftapbb020_alloc_chan_resources;
++	dma->device_free_chan_resources = ftapbb020_free_chan_resources;
++	dma->device_prep_dma_memcpy = ftapbb020_prep_dma_memcpy;
++	dma->device_prep_dma_memset = ftapbb020_prep_dma_memset;
++	dma->device_prep_slave_sg = ftapbb020_prep_slave_sg;
++	dma->device_control = ftapbb020_control;
++	dma->device_tx_status = ftapbb020_tx_status;
++	dma->device_issue_pending = ftapbb020_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
++	dma_cap_set(DMA_MEMSET, dma->cap_mask);
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);
++
++	err = request_irq(irq, ftapbb020_interrupt, IRQF_SHARED, pdev->name,
++			  ftapbb020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_irq;
++	}
++
++	ftapbb020->irq = irq;
++
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	dev_info(&pdev->dev, "DMA engine driver: irq %d, mapped at %p\n",
++		 irq, ftapbb020->base);
++
++	return 0;
++
++err_register:
++	free_irq(irq, ftapbb020);
++err_irq:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftapbb020->base);
++err_ioremap:
++	release_resource(ftapbb020->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftapbb020);
++	return err;
++}
++
++static int __exit ftapbb020_remove(struct platform_device *pdev)
++{
++	struct ftapbb020 *ftapbb020;
++	int i;
++
++	ftapbb020 = platform_get_drvdata(pdev);
++
++	dma_async_device_unregister(&ftapbb020->dma);
++
++	free_irq(ftapbb020->irq, ftapbb020);
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftapbb020->base);
++	release_resource(ftapbb020->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftapbb020);
++	return 0;
++}
++
++/*
++ * FTAPBB020
++ */
++static struct resource ftapbb020_resources[] = {
++	{
++	 .start = APBBRG_FTAPBBRG020S_PA_BASE,
++	 .end = APBBRG_FTAPBBRG020S_PA_LIMIT,
++	 .flags = IORESOURCE_MEM,
++	 }, {
++	     .start = APBBRG_FTAPBBRG020S_IRQ,
++	     .end = APBBRG_FTAPBBRG020S_IRQ,
++	     .flags = IORESOURCE_IRQ,
++	     }
++};
++
++static struct platform_device ftapbb020_device = {
++	.name = "ftapbb020",
++	.id = 0,
++	.dev = {
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++		},
++	.num_resources = ARRAY_SIZE(ftapbb020_resources),
++	.resource = ftapbb020_resources,
++};
++
++static struct platform_driver ftapbb020_driver = {
++	.probe = ftapbb020_probe,
++	.remove = __exit_p(ftapbb020_remove),
++	.driver = {
++		   .name = DRV_NAME,
++		   .owner = THIS_MODULE,
++		   },
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftapbb020_init(void)
++{
++	/* add platform device */
++	if (platform_device_register(&ftapbb020_device)) {
++		printk("failed to register FTAPBB020 device\n");
++		return -ENODEV;
++	}
++	return platform_driver_register(&ftapbb020_driver);
++}
++
++static void __exit ftapbb020_exit(void)
++{
++	platform_driver_unregister(&ftapbb020_driver);
++	platform_device_unregister(&ftapbb020_device);
++}
++
++module_init(ftapbb020_init);
++module_exit(ftapbb020_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTAPBB020 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-SMP/ftdmac020.c b/arch/arm/mach-GM-SMP/ftdmac020.c
+new file mode 100644
+index 00000000..4164f0a1
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/ftdmac020.c
+@@ -0,0 +1,1815 @@
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/dmapool.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++//#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/ftdmac020.h>
++
++#define CHANNEL_NR	8
++#define MAX_CYCLE_PER_BLOCK	0x3FF000    //3.xM, TOT_SIZE[21:0]
++//#define DEBUG
++//#define REG_DUMP
++
++#define USE_IRQ_LOCK    /* SSP ALSA will call these functions while disabling irq */
++
++#ifdef USE_IRQ_LOCK
++#define DMAC020_LOCK(x)     spin_lock_irqsave(x, flags)
++#define DMAC020_UNLOCK(x)   spin_unlock_irqrestore(x, flags)
++#else
++#define DMAC020_LOCK(x)     spin_lock_bh(x)
++#define DMAC020_UNLOCK(x)   spin_unlock_bh(x)
++#endif
++
++/* platform dependent */
++static int (*platform_chan_filter)(int chan_id) = NULL;
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 24;
++
++/*
++ * driver/dma/at_hdmac.c can be the template
++ */
++/**
++ * struct ftdmac020_desc - async transaction descriptor.
++ * @lld: hardware descriptor, MUST be the first member
++ * @value: value for MEMSET (Must be fixed here)
++ * @ccr: value for channel control register
++ * @cfg: value for channel configuration register
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the first link list descriptor (2nd block)
++ * @cycle: transfer size
++ * @txd: support for the async_tx api
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @node: node on the descriptors list
++ * @len: length in bytes
++ *
++ * For a chained transfer, software has to set channel-specific hardware
++ * registers to describe the first block and link list descriptors to describe
++ * other blocks. Because of this unbelievable brain-damaged design, the
++ * software descriptor and driver became unnecessarily complex.
++ *
++ * Sure, we can reuse src, dst, next and cycle in lld to save some space.
++ * The reason I do not do that is not to make you confused.
++ */
++struct ftdmac020_desc {
++	/* not used by the first block */
++	struct ftdmac020_lld lld;
++
++	/* used only by the first block. This is per channel configuration */
++	unsigned int value; /* for MEMSET */
++	unsigned int ccr;   /* Cn_CSR */
++	unsigned int cfg;   /* Cn_CFG */
++	dma_addr_t src;     /* Cn_SrcAddr */
++	dma_addr_t dst;     /* Cn_DstAddr */
++	dma_addr_t next;    /* Cn_LLP */
++	unsigned int cycle; /* Cn_SIZE */
++
++	struct dma_async_tx_descriptor txd;
++	struct list_head child_list;
++
++	/* used by all blocks */
++	struct ftdmac020_chan *ftchan;
++	struct list_head node;
++	size_t len;
++};
++
++/**
++ * struct ftdmac020_chan - internal representation of an ftdmac020 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftdmac020: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftdmac020_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftdmac020 *ftdmac020;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++	enum dma_transaction_type transaction_type;
++};
++
++/**
++ * struct ftdmac020 - internal representation of an ftdmac020 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @id: id for each device
++ * @tc_irq: terminal count irq number
++ * @ea_irq: error and abort irq number
++ * @channel: channel table
++ */
++struct ftdmac020 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	int id;
++	unsigned int irq;
++	struct dma_pool *dma_desc_pool;
++	struct ftdmac020_chan channel[CHANNEL_NR];
++};
++
++static const char *ftdmac020_name[] = {"ftdmac020", "ftdmac020"};
++static dma_cookie_t ftdmac020_tx_submit(struct dma_async_tx_descriptor *);
++static int dmac020_fd;
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++#ifdef CONFIG_PLATFORM_GM8220
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x68, (0x1 << 6), (0x1 << 6), (0x0 << 6), (0x1 << 6)},   /* AHB clock gate */
++};
++#endif
++
++static pmuRegInfo_t pmu_reg_info = {
++    "DMAC020",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftdmac020_enable(struct ftdmac020 *ftdmac020)
++{
++	void __iomem *base = ftdmac020->base;
++
++	iowrite32(FTDMAC020_CR_ENABLE, base + FTDMAC020_OFFSET_CR);
++}
++
++static void ftdmac020_disable(struct ftdmac020 *ftdmac020)
++{
++	void __iomem *base = ftdmac020->base;
++
++	iowrite32(0, base + FTDMAC020_OFFSET_CR);
++}
++
++static int ftdmac020_chan_is_enabled(struct ftdmac020_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++	unsigned int enabled;
++
++	enabled = ioread32(base + FTDMAC020_OFFSET_CH_ENABLED);
++	return enabled & (1 << chan_id);
++}
++
++static void ftdmac020_abort_channel(struct ftdmac020_chan *ftchan)
++{
++    unsigned long flags;
++    int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++	volatile u32 value, i;
++
++    if (ftchan->transaction_type != DMA_CYCLIC)
++        return;
++
++    spin_lock_irqsave(&ftchan->lock, flags);
++    /* 1. set ABT */
++    value = ioread32(base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++    value |= (0x1 << 15);   /* ABT */
++    iowrite32(value, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++
++    /* 2. wait dmaint INT_ABT to assert */
++    i = 0;
++    do {
++        udelay(1);
++        value = ioread32(base + FTDMAC020_OFFSET_EAISR);    /* 0xC */
++        i ++;
++        if (i > 1000000) {
++            printk("%s, error 1 ################################# \n", __func__);
++            break;
++        }
++    } while (!(value & (0x1 << (16 + chan_id))));
++
++    /* 3. wait ABT to confirm which channel has been aborted */
++    i = 0;
++    do {
++        udelay(1);
++        value = ioread32(base + FTDMAC020_OFFSET_EARAW);    /* 0x18 */
++        i ++;
++        if (i > 1000000) {
++            printk("%s, error 2 ################################# \n", __func__);
++            break;
++        }
++    } while (!(value & (0x1 << (16 + chan_id))));
++
++    /* 4. Set ABT_CLR to clear ABT. The channel ca be reuse again */
++    iowrite32(0x1 << (16 + chan_id), base + FTDMAC020_OFFSET_EAICR);
++
++    spin_unlock_irqrestore(&ftchan->lock, flags);
++}
++
++static void ftdmac020_stop_channel(struct ftdmac020_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++    volatile u32 i = 0;
++
++    if (ftchan->transaction_type == DMA_CYCLIC) {
++        /* ring DMA needs to use ABT to stop the DMA. CANNOT disable channel directly, it may cause DMAC die */
++        ftdmac020_abort_channel(ftchan);
++    } else {
++        /* Normal path. Wait DMA to finish a complete transaction.
++         */
++        while (ftdmac020_chan_is_enabled(ftchan)) {
++            /* someone may call terminate all to force exit. In this case we must wait dma to complete */
++            udelay(50);
++            i ++;
++            if (i > 1000)
++                break;
++        }
++        if (i > 1000)
++            printk("%s, error in dmac020 ch%d enabled! \n", __func__, chan_id);
++
++        /* disable dmach in IDLE state. */
++	    iowrite32(0, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++    }
++}
++
++/**
++ * ftdmac020_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftdmac020_desc *ftdmac020_alloc_desc(
++		struct ftdmac020_chan *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020 *ftdmac020 = ftchan->ftdmac020;
++	struct ftdmac020_desc *desc;
++	dma_addr_t phys;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = dma_pool_alloc(ftdmac020->dma_desc_pool, gfp_flags, &phys);
++	if (desc) {
++		memset(desc, 0, sizeof(*desc));
++
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftdmac020_tx_submit;
++		desc->txd.phys = phys;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftdmac020_free_desc(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &desc->ftchan->common;
++	struct ftdmac020 *ftdmac020 = ftchan->ftdmac020;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	dma_pool_free(ftdmac020->dma_desc_pool, desc, desc->txd.phys);
++}
++
++/**
++ * ftdmac020_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftdmac020_desc *ftdmac020_desc_get(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc = NULL;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	DMAC020_LOCK(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++			struct ftdmac020_desc, node);
++
++		list_del(&desc->node);
++	}
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftdmac020_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			DMAC020_LOCK(&ftchan->lock);
++			ftchan->descs_allocated++;
++			DMAC020_UNLOCK(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftdmac020_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftdmac020_desc_put(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *child;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	DMAC020_LOCK(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++static void ftdmac020_unmap_desc(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftdmac020_remove_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *child;
++	struct ftdmac020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->child_list, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftdmac020_unmap_desc(child);
++		ftdmac020_desc_put(child);
++	}
++
++	ftdmac020_unmap_desc(desc);
++	ftdmac020_desc_put(desc);
++}
++
++/**
++ * ftdmac020_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @src_shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @dst_shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * 		when MEMSET, it's the set value
++ */
++static struct ftdmac020_desc *ftdmac020_create_chain(
++		struct ftdmac020_chan *ftchan,
++		struct ftdmac020_desc *first,
++		dma_addr_t src, dma_addr_t dest, size_t len,
++		unsigned int src_shift, unsigned int dst_shift, int fixed_src, int fixed_dest)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_dma_slave *slave = chan->private;
++	struct ftdmac020_desc *prev = NULL;
++	unsigned int ccr;
++	unsigned int lld_ctrl;
++	size_t offset;
++	unsigned int cycle;
++	bool is_memset = false;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, src_shift %d, dst_shift %d)\n",
++		__func__, src, dest, len, src_shift, dst_shift);
++	if ((src_shift == 2 && ((src | len) & 3)) ||
++	    (src_shift == 1 && ((src | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or src data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++    if ((dst_shift == 2 && ((dest | len) & 3)) ||
++	    (dst_shift == 1 && ((dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or dst data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	/* When using memset, src is set to zero */
++	if (src == 0 && fixed_src)
++		is_memset = true;
++
++	if (first) {
++		if (list_empty(&first->child_list))
++			prev = first;
++		else
++			prev = list_entry(first->child_list.prev,
++				struct ftdmac020_desc, node);
++	}
++
++	ccr = FTDMAC020_CCR_ENABLE
++	    | ((slave->src_size & 0x7) << 16)
++	    | FTDMAC020_CCR_PRIO_0
++	    | FTDMAC020_CCR_FIFOTH_1;
++
++	lld_ctrl = FTDMAC020_LLD_CTRL_FIFOTH_1;
++
++    switch (src_shift) {
++	case 2:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_32;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_32;
++		break;
++	case 1:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_16;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_16;
++		break;
++	case 0:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_8;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	switch (dst_shift) {
++	case 2:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_32;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_32;
++		break;
++	case 1:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_16;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_16;
++		break;
++	case 0:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_8;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	if (slave && slave->handshake >= 0)
++		ccr |= FTDMAC020_CCR_HANDSHAKE;
++
++	if (fixed_src) {
++		ccr |= FTDMAC020_CCR_SRC_FIXED;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_FIXED;
++	} else {
++		ccr |= FTDMAC020_CCR_SRC_INC;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_INC;
++	}
++
++	if (fixed_dest && !is_memset) {
++		ccr |= FTDMAC020_CCR_DST_FIXED;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_FIXED;
++	} else {
++		ccr |= FTDMAC020_CCR_DST_INC;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_INC;
++	}
++
++	ccr |= ((slave->src_sel & 0x1) << 2);  /* SRC_SEL */
++	ccr |= ((slave->dst_sel & 0x1) << 1);  /* DST_SEL */
++	lld_ctrl |= ((slave->src_sel & 0x1) << 17);  /* SRC_SEL */
++	lld_ctrl |= ((slave->dst_sel & 0x1) << 16);  /* DST_SEL */
++
++	/* we must seperate the len into multiple descriptors. Because len may be a bigger one */
++	for (offset = 0; offset < len; offset += cycle << src_shift) {
++		struct ftdmac020_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> src_shift,
++				MAX_CYCLE_PER_BLOCK);
++
++		desc = ftdmac020_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		/*
++		 * Importatnt: 1. fixed_dest is viewed as memset value
++		 *             2. src is defined as the place of "int value" in ftdmac020_desc
++		 */
++		if (is_memset) {
++			desc->value = fixed_dest;
++			src = desc->txd.phys + sizeof(struct ftdmac020_lld);
++		}
++
++		if (fixed_src) {
++			desc->src = desc->lld.src = src;
++		} else {
++			desc->src = desc->lld.src = src + offset;
++		}
++
++		if (fixed_dest && !is_memset) {
++			desc->dst = desc->lld.dst = dest;
++		} else {
++			desc->dst = desc->lld.dst = dest + offset;
++		}
++
++		desc->next	= 0;
++		desc->cycle	= cycle & FTDMAC020_CYC_MASK;
++		desc->ccr	= ccr;
++		desc->cfg	= 0;
++		desc->len	= cycle << src_shift;
++
++		desc->lld.next	= 0;
++		desc->lld.cycle	= cycle & FTDMAC020_LLD_CYCLE_MASK;
++		desc->lld.ctrl	= lld_ctrl;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/*
++			 * Mask terminal count interrupt for this descriptor.
++			 * What an inconvenient stupid design.
++			 */
++            if (ftchan->transaction_type != DMA_CYCLIC) {
++                prev->ccr	|= FTDMAC020_CCR_MASK_TC;
++                prev->lld.ctrl	|= FTDMAC020_LLD_CTRL_MASK_TC;
++            }
++
++			/* hardware link list pointer */
++			prev->next	= FTDMAC020_LLP_ADDR(desc->txd.phys);
++			prev->lld.next	= desc->txd.phys;
++#if defined (CONFIG_PLATFORM_GM8287) || defined (CONFIG_PLATFORM_GM8139) || defined (CONFIG_PLATFORM_GM8136) || defined (CONFIG_PLATFORM_GM8220)
++			prev->next |= 0x1; // load next LLP from AHB MASTER1
++			prev->lld.next |= 0x1;
++#endif
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++		prev = desc;
++	}
++
++	/*
++	 * Here just create the chain only. When submit function is called, this desc will be added to
++	 * ftchan->active_list.
++	 */
++	return first;
++err:
++	if (first)
++		ftdmac020_remove_chain(first);
++	return NULL;
++}
++
++static void ftdmac020_start_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	void __iomem *base = ftchan->ftdmac020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++
++#ifdef REG_DUMP
++	printk("\t[SRC %d] = %x\n", chan_id, desc->src);
++	printk("\t[DST %d] = %x\n", chan_id, desc->dst);
++	printk("\t[LLP %d] = %x\n", chan_id, desc->next);
++	printk("\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	printk("\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	printk("\t[CCR %d] = %x\n", chan_id, desc->ccr);
++#endif
++	/*
++	 * The first transfer block is not described by hardware lld.
++	 * Instead, we should fill some hardware registers.
++	 * What a stupid weird design.
++	 */
++	dev_dbg(chan2dev(chan), "\t[SRC %d] = %x\n", chan_id, desc->src);
++	iowrite32(desc->src, base + FTDMAC020_OFFSET_SRC_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DST %d] = %x\n", chan_id, desc->dst);
++	iowrite32(desc->dst, base + FTDMAC020_OFFSET_DST_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[LLP %d] = %x\n", chan_id, desc->next);
++	iowrite32(desc->next, base + FTDMAC020_OFFSET_LLP_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	iowrite32(desc->cycle, base + FTDMAC020_OFFSET_CYC_CH(chan_id));
++
++	/* go */
++	dev_dbg(chan2dev(chan), "\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	iowrite32(desc->cfg, base + FTDMAC020_OFFSET_CFG_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CCR %d] = %x\n", chan_id, desc->ccr);
++	iowrite32(desc->ccr, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++
++}
++
++static void ftdmac020_start_new_chain(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++	ftdmac020_start_chain(desc);
++}
++
++static void ftdmac020_finish_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	DMAC020_LOCK(&ftchan->lock);
++	ftchan->completed_cookie = desc->txd.cookie;
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback) {
++	    /* If this channel is terminated by manual, we dont need to callback */
++	    if (ftchan->transaction_type != DMA_TX_TYPE_END)
++		    desc->txd.callback(desc->txd.callback_param);
++    }
++
++	ftdmac020_remove_chain(desc);
++}
++
++static void ftdmac020_finish_all_chains(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftdmac020_finish_chain(desc);
++	}
++}
++
++static dma_cookie_t ftdmac020_new_cookie(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftdmac020_chan_filter(struct dma_chan *chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftdmac020_dma_slave *slave = data;
++	const char *ftdmac020_drv_name = *(ftdmac020_name + slave->id);
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020 *ftdmac020;
++
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++	ftdmac020 = ftchan->ftdmac020;
++
++	if (strncmp(ftdmac020_drv_name, drv_name, sizeof("ftdmac020")))
++		return false;
++
++	/* When you have more than 2 dma controller's, it checks id */
++	if (slave->id >= 0 && slave->id != ftdmac020->id)
++		return false;
++
++    /* this is platform dependent. Some platform only can use some channels instead of all. */
++    if (platform_chan_filter && platform_chan_filter((int)chan->chan_id))
++        return false;
++
++	chan->private = slave;
++	return true;
++}
++EXPORT_SYMBOL_GPL(ftdmac020_chan_filter);
++
++/**
++ * atc_handle_cyclic - at the end of a period, run callback function
++ * @atchan: channel used for cyclic operations
++ *
++ * Called with atchan->lock held and bh disabled
++ */
++static void ftdmac020_handle_cyclic(struct ftdmac020_chan *ftchan)
++{
++    struct ftdmac020_desc	*first = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++	struct dma_async_tx_descriptor	*txd = &first->txd;
++	dma_async_tx_callback   callback = txd->callback;
++	void			*param = txd->callback_param;
++    struct dma_chan *chan = &ftchan->common;
++
++    dev_dbg(chan2dev(chan), "%s\n", __func__);
++
++	if (callback)
++		callback(param);
++}
++
++/******************************************************************************
++ * tasklet - called after we finished one chain
++ *****************************************************************************/
++static void ftdmac020_tasklet(unsigned long data)
++{
++	struct ftdmac020_chan *ftchan = (struct ftdmac020_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++    if (ftchan->transaction_type == DMA_TX_TYPE_END) {
++        if (!list_empty(&ftchan->active_list))
++            panic("%s, active_list should be empty due to terminate_all! \n", __func__);
++
++        return;
++    }
++
++    if (ftchan->transaction_type == DMA_CYCLIC) {
++        dev_dbg(chan2dev(chan), "%s, DMA_CYCLIC \n", __func__);
++
++        DMAC020_LOCK(&ftchan->lock);
++	    if (list_empty(&ftchan->active_list))
++            printk("%s, active_list is empty in DMA_CYCLIC! \n", __func__);
++        BUG_ON(list_empty(&ftchan->active_list));
++        ftdmac020_handle_cyclic(ftchan);
++        DMAC020_UNLOCK(&ftchan->lock);
++    } else {
++        /*
++         * DMA_SLAVE, DMA_MEMCPY
++         */
++        dev_dbg(chan2dev(chan), "%s, DMA_SLAVE / MEMCPY\n", __func__);
++
++	    DMAC020_LOCK(&ftchan->lock);
++	    if (list_empty(&ftchan->active_list))
++            panic("%s, active_list is empty in DMA_SLAVE / MEMCPY! \n", __func__);
++
++    	/* remove already finished descriptor */
++    	desc = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++    	list_del(&desc->node);
++
++    	/* check if there were another transfer to do */
++    	ftdmac020_start_new_chain(ftchan);
++
++    	DMAC020_UNLOCK(&ftchan->lock);
++    	ftdmac020_finish_chain(desc);
++    }
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftdmac020_interrupt(int irq, void *dev_id)
++{
++	struct ftdmac020 *ftdmac020 = dev_id;
++	unsigned int status;
++	int i;
++
++	status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_TCISR);
++	if (!status) {
++	    /* read error status */
++	    status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_EAISR);    /* 0xC */
++    	if (!status)
++    		return IRQ_NONE;
++
++        /* clear status */
++	    iowrite32(status, ftdmac020->base + FTDMAC020_OFFSET_EAICR);
++
++	    for (i = 0; i < CHANNEL_NR; i++) {
++    		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++    		struct dma_chan *chan = &ftchan->common;
++
++    		if (status & FTDMAC020_EA_ERR_CH(i))
++    			dev_info(chan2dev(chan), "error happened\n");
++
++    		if (status & FTDMAC020_EA_ABT_CH(i))
++    			dev_dbg(chan2dev(chan), "transfer aborted\n");
++	    }
++
++	    return IRQ_HANDLED;
++	}
++
++	/* clear status */
++	iowrite32(status, ftdmac020->base + FTDMAC020_OFFSET_TCICR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (status & (1 << i)) {
++			dev_dbg(chan2dev(chan), "terminal count\n");
++			tasklet_schedule(&ftchan->tasklet);
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftdmac020_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftdmac020_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++	bool busy;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	desc = container_of(txd, struct ftdmac020_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	DMAC020_LOCK(&ftchan->lock);
++
++	cookie = ftdmac020_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list))
++		busy = false;
++	else
++		busy = true;
++
++	list_add_tail(&desc->node, &ftchan->active_list);
++
++#if 0   /* Harry, move to issue pending. If we start the transaction here, it will have potential
++         * chance to lose the LLP due to race condition between CPU and hardware.
++         */
++	/* start ASAP */
++	if (!busy)
++		ftdmac020_start_chain(desc);
++#endif
++
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftdmac020_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftdmac020_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++	unsigned long       flags;
++
++    if (flags)  {}
++
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftdmac020_desc *desc;
++
++		desc = ftdmac020_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	DMAC020_LOCK(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list); /* add tmp_list to free_list */
++	ftchan->completed_cookie = chan->cookie = 1;
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftdmac020_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftdmac020_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_desc *tmp;
++	struct ftdmac020 *ftdmac020;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++	ftdmac020 = ftchan->ftdmac020;
++
++	/* channel must be idle */
++        if (ftdmac020_chan_is_enabled(ftchan)) {
++	    dump_stack();
++	    panic("%s, chan is enabled! \n", __func__);
++   	}
++
++	if (!list_empty(&ftchan->active_list)) {
++	    dump_stack();
++	    panic("%s, ftchan->active_list is not empty! \n", __func__);
++	}
++
++	DMAC020_LOCK(&ftchan->lock);
++	ftdmac020_stop_channel(ftchan);
++	ftdmac020_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftdmac020_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++/**
++ * ftdmac020_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++		dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((src >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect src physical address 0x%x \n", __func__, src);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++	} else {
++		shift = 0;
++	}
++
++	desc = ftdmac020_create_chain(ftchan, NULL, src, dest, len,
++		shift, shift, 0, 0);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMCPY;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac020_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @value: the given value for memset used
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest,
++		int value, size_t len, unsigned long flags)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(dest %x, value %x, len %x)\n",
++		__func__, dest, value, len);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(len & 3)) {
++		dev_info(chan2dev(chan), "%s: length isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(dest & 3)) {
++		dev_info(chan2dev(chan), "%s: dest addr isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	shift = 2;
++
++	desc = ftdmac020_create_chain(ftchan, NULL, 0, dest, len,
++		shift, shift, 1, value);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMSET;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * atc_prep_dma_cyclic - prepare the cyclic DMA transfer
++ * @chan: the DMA channel to prepare
++ * @buf_addr: physical DMA address where the buffer starts
++ * @buf_len: total number of bytes for the entire buffer
++ * @period_len: number of bytes for each period
++ * @direction: transfer direction, to or from device
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
++		size_t period_len, enum dma_transfer_direction direction)
++{
++	struct ftdmac020_dma_slave  *slave = chan->private;
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc = NULL, *child, *last;
++	dma_addr_t  src_addr, dst_addr;
++	int i, src_shift, dst_shift, periods = buf_len / period_len;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s, please call dmaengine_slave_config() first! \n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!list_empty(&ftchan->active_list))) {
++		dev_err(chan2dev(chan), "%s, chan%d, active list is not empty! \n", __func__, ftchan->common.chan_id);
++		return NULL;
++	}
++
++	if (unlikely(!buf_len || !period_len)) {
++		dev_dbg(chan2dev(chan), "prep_dma_cyclic: length is zero!\n");
++		return NULL;
++	}
++
++	if ((direction != DMA_MEM_TO_DEV) && (direction != DMA_DEV_TO_MEM)) {
++		dev_err(chan2dev(chan), "%s: incorrect direction %d \n", __func__, direction);
++		return NULL;
++	}
++
++	if (buf_len % period_len) {
++		dev_err(chan2dev(chan), "%s: incorrect length %d \n", __func__, buf_len);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			src_shift = 0;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			src_shift = 1;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			src_shift = 2;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++					__func__);
++			return NULL;
++	}
++
++    switch (slave->common.dst_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			dst_shift = 0;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			dst_shift = 1;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			dst_shift = 2;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++					__func__);
++			return NULL;
++	}
++
++#ifdef REG_DUMP
++    printk("%s, src_shift: %d, dst_shift: %d, slave->src_size: %d\n", __func__,
++                    src_shift, dst_shift, slave->src_size);
++#endif
++
++	if (slave->src_size > FTDMAC020_BURST_SZ_256 || slave->src_size < FTDMAC020_BURST_SZ_1) {
++		dev_err(chan2dev(chan), "%s: incorrect src_size %d\n", __func__, slave->src_size);
++		return NULL;
++	}
++
++    if (direction == DMA_MEM_TO_DEV) {
++        if (buf_addr != slave->common.src_addr) {
++            dev_err(chan2dev(chan), "%s: inconsistent src address %x \n", __func__, buf_addr);
++                      return NULL;
++        }
++    } else {
++        if (buf_addr != slave->common.dst_addr) {
++            dev_err(chan2dev(chan), "%s: inconsistent dst address %x \n", __func__, buf_addr);
++                      return NULL;
++        }
++    }
++
++	if (unlikely(!pfn_valid((buf_addr >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, buf_addr);
++		return NULL;
++	}
++
++	if (direction != slave->common.direction) {
++		dev_err(chan2dev(chan), "%s: inconsistent direction %d\n", __func__, direction);
++		return NULL;
++	}
++
++	src_addr = slave->common.src_addr;
++	dst_addr = slave->common.dst_addr;
++
++    /* tell ftdmac020_create_chain() that LLP is used for DMA_CYCLIC */
++	ftchan->transaction_type = DMA_CYCLIC;
++
++	/* create chain */
++	for (i = 0; i < periods; i ++) {
++		struct ftdmac020_desc *tmp;
++		int fixed_src, fixed_dst;
++
++		if (direction == DMA_MEM_TO_DEV) {
++			fixed_src = 0;  /* INC */
++			fixed_dst = 1;
++		} else {
++			fixed_src = 1;
++			fixed_dst = 0;
++		}
++
++		tmp = ftdmac020_create_chain(ftchan, desc,
++				src_addr, dst_addr, period_len,
++				src_shift, dst_shift, fixed_src, fixed_dst);
++
++		/* increase the address */
++		if (fixed_src == 0)
++			src_addr += period_len;
++		if (fixed_dst == 0)
++			dst_addr += period_len;
++
++		if (!tmp)
++			return NULL;
++		if (!desc)  /* all childs are chained to the first active node */
++			desc = tmp;
++
++		if (direction == DMA_MEM_TO_DEV) {
++			if (slave->handshake >= 0)
++				tmp->cfg = FTDMAC020_CFG_DST_HANDSHAKE_EN
++					| FTDMAC020_CFG_DST_HANDSHAKE(slave->handshake);
++		} else {
++			if (slave->handshake >= 0)
++				tmp->cfg = FTDMAC020_CFG_SRC_HANDSHAKE_EN
++					| FTDMAC020_CFG_SRC_HANDSHAKE(slave->handshake);
++		}
++	}
++
++	/* walk through the whole list and update TC_MASK to issue interrupt
++	*/
++	list_for_each_entry(child, &desc->child_list, node) {
++		child->ccr &= ~FTDMAC020_CCR_MASK_TC;
++		child->ccr |= FTDMAC020_CCR_PRIO_3; /* audio needs high priority */
++		child->lld.ctrl &= ~FTDMAC020_LLD_CTRL_MASK_TC;
++	}
++
++	/* form hardware link list pointer ring */
++	last = list_entry(desc->child_list.prev, struct ftdmac020_desc, node);
++    last->next	= FTDMAC020_LLP_ADDR(desc->txd.phys);
++	last->lld.next	= desc->txd.phys;
++#if defined (CONFIG_PLATFORM_GM8287) || defined (CONFIG_PLATFORM_GM8139) || defined (CONFIG_PLATFORM_GM8136) || defined (CONFIG_PLATFORM_GM8220)
++	last->next |= 0x1; // load next LLP from AHB MASTER1
++	last->lld.next |= 0x1;
++#endif
++
++#ifdef REG_DUMP   //dump register
++	child = desc;
++	printk("(0x%x)child->ccr: 0x%x, cfg: 0x%x, src:0x%x, dst:0x%x, lld.src:0x%x, lld.dst:0x%x, lld.next:0x%x, lld.cycle:0x%x, lld.ctrl:0x%x \n",
++			child->txd.phys, child->ccr, child->cfg, child->src, child->dst,
++			child->lld.src, child->lld.dst, child->lld.next, child->lld.cycle, child->lld.ctrl);
++
++	list_for_each_entry(child, &desc->child_list, node) {
++		printk("(0x%x)child->ccr:0x%x, cfg:0x%x, src:0x%x, dst:0x%x, lld.src:0x%x, lld.dst:0x%x, lld.next:0x%x, lld.cycle:0x%x, lld.ctrl:0x%x \n",
++				child->txd.phys, child->ccr, child->cfg, child->src, child->dst,
++				child->lld.src, child->lld.dst, child->lld.next, child->lld.cycle, child->lld.ctrl);
++	}
++#endif
++
++	/* Update the tc_mask to issue interrupt per element in the chain */
++	desc->txd.cookie = -EBUSY;
++	desc->txd.flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	chan->private = NULL;   /* got the parameter already, so free it */
++
++	return &desc->txd;
++}
++
++
++/**
++ * ftdmac020_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++		unsigned int sg_len, enum dma_transfer_direction direction,
++		unsigned long flags)
++{
++	struct ftdmac020_dma_slave *slave = chan->private;
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int src_shift, dst_shift;
++	unsigned int i;
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s, please call dmaengine_slave_config() first! \n", __func__);
++		return NULL;
++	}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		src_shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		src_shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		src_shift = 2;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++    switch (slave->common.dst_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		dst_shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		dst_shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		dst_shift = 2;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++	if (slave->src_size > FTDMAC020_BURST_SZ_256 || slave->src_size < FTDMAC020_BURST_SZ_1) {
++		dev_err(chan2dev(chan), "%s: incorrect src_size %d\n", __func__, slave->src_size);
++		BUG();
++	}
++
++	switch (direction) {
++	case DMA_MEM_TO_DEV:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++            if (unlikely(!pfn_valid((mem >> PAGE_SHIFT)))) {
++                dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, mem);
++                goto err;
++            }
++			tmp = ftdmac020_create_chain(ftchan, desc,
++				mem, slave->common.dst_addr, len,
++				src_shift, dst_shift, 0, 1);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC020_CFG_DST_HANDSHAKE_EN
++				| FTDMAC020_CFG_DST_HANDSHAKE(slave->handshake);
++		break;
++	case DMA_DEV_TO_MEM:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++            if (unlikely(!pfn_valid((mem >> PAGE_SHIFT)))) {
++                dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, mem);
++                goto err;
++            }
++
++			tmp = ftdmac020_create_chain(ftchan, desc,
++				slave->common.src_addr, mem, len,
++				src_shift, dst_shift, 1, 0);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC020_CFG_SRC_HANDSHAKE_EN
++				| FTDMAC020_CFG_SRC_HANDSHAKE(slave->handshake);
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n",
++			__func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++	chan->private = NULL;   /* got the parameter already, so free it */
++	ftchan->transaction_type = DMA_SLAVE;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftdmac020_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++		unsigned long arg)
++{
++	struct ftdmac020_chan *ftchan;
++	unsigned long       flags;
++	int ret = -ENXIO;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (cmd == DMA_SLAVE_CONFIG) {
++		struct dma_slave_config *slave_config = (struct dma_slave_config *)arg;
++		struct ftdmac020_dma_slave  *dma_slave;
++
++		dma_slave = container_of(slave_config, struct ftdmac020_dma_slave, common);
++		chan->private = dma_slave;
++		ret = 0;
++	}
++
++	if (cmd == DMA_TERMINATE_ALL) {
++		/*
++		 * This is only called when something went wrong elsewhere, so
++		 * we don't really care about the data. Just disable the channel.
++		 */
++		DMAC020_LOCK(&ftchan->lock);
++		ftdmac020_stop_channel(ftchan);
++		ftchan->transaction_type = DMA_TX_TYPE_END;
++		ftdmac020_finish_all_chains(ftchan);
++        /* self test again */
++		if (!list_empty(&ftchan->active_list))
++	        panic("%s, ftchan->active_list is not empty2! \n", __func__);
++        DMAC020_UNLOCK(&ftchan->lock);
++	}
++
++	return ret;
++}
++
++/**
++ * ftdmac020_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftdmac020_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		struct dma_tx_state *txstate)
++{
++	struct ftdmac020_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftdmac020_issue_pending - try to active work
++ * @chan: target DMA channel
++ */
++static void ftdmac020_issue_pending(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	DMAC020_LOCK(&ftchan->lock);
++	if (list_empty(&ftchan->active_list))
++	    printk("%s, ftchan->active_list is empty! \n", __func__);
++    BUG_ON(list_empty(&ftchan->active_list));
++	/* get first descriptor and go */
++	ftdmac020_start_new_chain(ftchan);
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftdmac020_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftdmac020 *ftdmac020;
++	struct dma_device *dma;
++	int irq, i , err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftdmac020 = kzalloc(sizeof(*ftdmac020), GFP_KERNEL);
++	if (!ftdmac020) {
++		return -ENOMEM;
++	}
++
++	dma = &ftdmac020->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftdmac020);
++	ftdmac020->id = pdev->id;
++
++	/* map io memory */
++	ftdmac020->res = request_mem_region(res->start, res->end - res->start + 1,
++			dev_name(&pdev->dev));
++	if (ftdmac020->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftdmac020->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftdmac020->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* create a pool of consistent memory blocks for hardware descriptors */
++	ftdmac020->dma_desc_pool = dma_pool_create("ftdmac020_desc_pool",
++			&pdev->dev, sizeof(struct ftdmac020_desc),
++			8 /* double word alignment */, 0);
++	if (!ftdmac020->dma_desc_pool) {
++		dev_err(&pdev->dev, "No memory for descriptor pool\n");
++		err = -ENOMEM;
++		goto err_pool_create;
++	}
++
++	/* force dma off, just in case */
++	ftdmac020_disable(ftdmac020);
++
++	/* initialize channels and create tasklet per channel */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device	= dma;
++		ftchan->common.cookie	= DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftdmac020		= ftdmac020;
++		ftchan->completed_cookie	= DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftdmac020_tasklet, (unsigned long)ftchan);
++		list_add_tail(&ftchan->common.device_node /*new*/, &dma->channels /*head*/);
++	}
++
++	/* clear all pending interrupts */
++	iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_TCICR);
++	iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_EAICR);
++
++    /* sync dma_req */
++    iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_SYNC);	
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftdmac020_alloc_chan_resources;
++	dma->device_free_chan_resources	= ftdmac020_free_chan_resources;
++	dma->device_prep_dma_memcpy	= ftdmac020_prep_dma_memcpy;
++	dma->device_prep_dma_memset 	= ftdmac020_prep_dma_memset;
++	dma->device_prep_slave_sg	= ftdmac020_prep_slave_sg;
++	dma->device_prep_dma_cyclic = ftdmac020_prep_dma_cyclic;
++	dma->device_control		    = ftdmac020_control;
++	dma->device_tx_status		= ftdmac020_tx_status;
++	dma->device_issue_pending	= ftdmac020_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask); //for replacing memcpy by DMA
++	dma_cap_set(DMA_MEMSET, dma->cap_mask); //for replacing memset by DMA
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);  //for normal DMA IO
++	dma_cap_set(DMA_CYCLIC, dma->cap_mask); //for audio
++
++	err = request_irq(irq, ftdmac020_interrupt, 0, pdev->name, ftdmac020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_irq;
++	}
++
++	ftdmac020->irq = irq;
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	ftdmac020_enable(ftdmac020);
++	dev_info(&pdev->dev,
++		"DMA engine driver: irq %d, mapped at 0x%p\n",
++		irq, ftdmac020->base);
++
++	return 0;
++
++err_register:
++	free_irq(irq, ftdmac020);
++err_irq:
++	dma_pool_destroy(ftdmac020->dma_desc_pool);
++err_pool_create:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftdmac020->base);
++err_ioremap:
++	release_resource(ftdmac020->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac020);
++	return err;
++}
++
++static int __exit ftdmac020_remove(struct platform_device *pdev)
++{
++	struct ftdmac020 *ftdmac020;
++	int i;
++
++	ftdmac020 = platform_get_drvdata(pdev);
++
++	ftdmac020_disable(ftdmac020);
++	dma_async_device_unregister(&ftdmac020->dma);
++
++	free_irq(ftdmac020->irq, ftdmac020);
++	dma_pool_destroy(ftdmac020->dma_desc_pool);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftdmac020->base);
++	release_resource(ftdmac020->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac020);
++
++	return 0;
++}
++
++/**
++ * ftdmac020_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac020_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac020_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id))
++{
++    if (platform_chan_filter != NULL) {
++        printk("%s, platform_chan_filter was registered already! \n", __func__);
++        return -1;
++    }
++
++    platform_chan_filter = chan_filter_fn;
++
++    return 0;
++}
++
++static struct platform_driver ftdmac020_driver = {
++	.probe		= ftdmac020_probe,
++	.remove		= __exit_p(ftdmac020_remove),
++	.driver		= {
++		.name	= "ftdmac020",
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftdmac020_init(void)
++{
++	int ret = 0;
++	if (MAX_CYCLE_PER_BLOCK & ~FTDMAC020_CYC_MASK)
++		panic("%s, invalid MAX_CYCLE_PER_BLOCK: 0x%x \n", __func__, MAX_CYCLE_PER_BLOCK);
++
++    /* Register PMU and turn on gate clock
++     */
++    dmac020_fd = ftpmu010_register_reg(&pmu_reg_info);
++    if (dmac020_fd < 0) {
++        printk("Warning............DMAC020: register PMU fail");
++        return 0;
++    }
++
++	if ((ret = platform_driver_register(&ftdmac020_driver))) {
++		printk("failed to register DMAC020 driver\n");
++		return ret;
++	}
++	return ret;
++}
++
++static void __exit ftdmac020_exit(void)
++{
++	platform_driver_unregister(&ftdmac020_driver);
++    /* Deregister PMU
++     */
++    ftpmu010_deregister_reg(dmac020_fd);
++}
++
++module_init(ftdmac020_init);
++module_exit(ftdmac020_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTDMAC020 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-SMP/ftdmac030.c b/arch/arm/mach-GM-SMP/ftdmac030.c
+new file mode 100644
+index 00000000..fffe2776
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/ftdmac030.c
+@@ -0,0 +1,1448 @@
++/*
++ * Faraday FTDMAC030 DMA engine driver
++ *
++ * (C) Copyright 2011 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/dmapool.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <asm/io.h>
++#include <asm/cputype.h>
++#include <mach/ftdmac030.h>
++#include <mach/ftpmu010.h>
++
++#define DRV_NAME	"ftdmac030"
++#define CHANNEL_NR	8
++unsigned int dmac030_sw_intr[5] = {0, 0, 0, 0, 0};
++EXPORT_SYMBOL(dmac030_sw_intr);
++
++/*
++ * This value must be multiple of 32-bits to prevent from changing the
++ * alignment of child descriptors.
++ */
++#define MAX_CYCLE_PER_BLOCK	0x200000
++#if (MAX_CYCLE_PER_BLOCK > FTDMAC030_CYC_MASK) || \
++	(MAX_CYCLE_PER_BLOCK & 0x3)
++#error invalid MAX_CYCLE_PER_BLOCK
++#endif
++
++#define GRANT_WINDOW	64
++
++/* platform dependent */
++static int (*platform_chan_filter)(int chan_id) = NULL;
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 64;
++module_param(init_nr_desc_per_channel, uint, 0644);
++MODULE_PARM_DESC(init_nr_desc_per_channel,
++		 "initial descriptors per channel (default: 64)");
++
++/**
++ * struct ftdmac030_desc - async transaction descriptor.
++ * @lld: hardware descriptor, MUST be the first member
++ * @ctrl: value for channel control register
++ * @cfg: value for channel configuration register
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the first link list descriptor (2nd block)
++ * @cycle: transfer size
++ * @txd: support for the async_tx api
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @node: node on the descriptors list
++ * @len: length in bytes
++ */
++struct ftdmac030_desc {
++	struct ftdmac030_lld lld;
++
++	/* used only by the first block */
++	unsigned int value; /* for MEMSET */
++	unsigned int cfg;
++
++	struct dma_async_tx_descriptor txd;
++	struct list_head child_list;
++
++	/* used by all blocks */
++	struct ftdmac030_chan *ftchan;
++	struct list_head node;
++	size_t len;
++};
++
++/**
++ * struct ftdmac030_chan - internal representation of an ftdmac030 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftdmac030: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftdmac030_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftdmac030 *ftdmac030;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++	enum dma_transaction_type transaction_type;
++};
++
++/**
++ * struct ftdmac030 - internal representation of an ftdmac030 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @id: id for each device
++ * @irq: irq number
++ * @channel: channel table
++ */
++struct ftdmac030 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	int id;
++	unsigned int irq;
++	struct dma_pool *dma_desc_pool;
++	struct ftdmac030_chan channel[CHANNEL_NR];
++};
++
++static dma_cookie_t ftdmac030_tx_submit(struct dma_async_tx_descriptor *);
++static int dmac030_fd;
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++#ifdef CONFIG_PLATFORM_GM8220
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    //{0x64, (0x1 << 19), (0x1 << 19), (0x0 << 19), (0x1 << 19)},   /* DMAC030 AHB clock gate */
++    {0x64, (0x1 << 20), (0x1 << 20), (0x0 << 20), (0x1 << 20)},   /* DMAC030_1 AHB clock gate */
++};
++#endif
++
++static pmuRegInfo_t pmu_reg_info = {
++    "DMAC030",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftdmac030_stop_channel(struct ftdmac030_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac030->base;
++
++	iowrite32(0, base + FTDMAC030_OFFSET_CTRL_CH(chan_id));
++}
++
++static int ftdmac030_chan_is_enabled(struct ftdmac030_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac030->base;
++	unsigned int enabled;
++
++	enabled = ioread32(base + FTDMAC030_OFFSET_CH_ENABLED);
++	return enabled & (1 << chan_id);
++}
++
++/**
++ * ftdmac030_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftdmac030_desc *ftdmac030_alloc_desc(
++		struct ftdmac030_chan *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030 *ftdmac030 = ftchan->ftdmac030;
++	struct ftdmac030_desc *desc;
++	dma_addr_t phys;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = dma_pool_alloc(ftdmac030->dma_desc_pool, gfp_flags, &phys);
++	if (desc) {
++		memset(desc, 0, sizeof(*desc));
++
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftdmac030_tx_submit;
++		desc->txd.phys = phys;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftdmac030_free_desc(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &desc->ftchan->common;
++	struct ftdmac030 *ftdmac030 = ftchan->ftdmac030;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	dma_pool_free(ftdmac030->dma_desc_pool, desc, desc->txd.phys);
++}
++
++/**
++ * ftdmac030_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftdmac030_desc *ftdmac030_desc_get(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc = NULL;
++
++	spin_lock_bh(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++			struct ftdmac030_desc, node);
++
++		list_del(&desc->node);
++	}
++	spin_unlock_bh(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftdmac030_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			spin_lock_bh(&ftchan->lock);
++			ftchan->descs_allocated++;
++			spin_unlock_bh(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftdmac030_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftdmac030_desc_put(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *child;
++
++	spin_lock_bh(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++static void ftdmac030_unmap_desc(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftdmac030_remove_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *child;
++	struct ftdmac030_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->child_list, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftdmac030_unmap_desc(child);
++		ftdmac030_desc_put(child);
++	}
++
++	ftdmac030_unmap_desc(desc);
++	ftdmac030_desc_put(desc);
++}
++
++/**
++ * ftdmac030_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * 		when MEMSET, it's the set value
++ */
++static struct ftdmac030_desc *ftdmac030_create_chain(
++		struct ftdmac030_chan *ftchan,
++		struct ftdmac030_desc *first,
++		dma_addr_t src, dma_addr_t dest, size_t len,
++		unsigned int shift, int fixed_src, int fixed_dest)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *prev = NULL;
++	struct ftdmac030_dma_slave *slave = chan->private;
++	unsigned int ctrl;
++	size_t offset;
++	unsigned int cycle, SrcTcnt;
++	bool is_memset = false;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, shift %d)\n",
++		__func__, src, dest, len, shift);
++	if ((shift == 3 && ((src | dest | len) & 7)) ||
++	    (shift == 2 && ((src | dest | len) & 3)) ||
++	    (shift == 1 && ((src | dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	/* When using memset, src is set to zero */
++	if (src == 0 && fixed_src)
++		is_memset = true;
++
++	if (first) {
++		if (list_empty(&first->child_list))
++			prev = first;
++		else
++			prev = list_entry(first->child_list.prev,
++				struct ftdmac030_desc, node);
++	}
++
++	switch (slave->common.src_maxburst) {
++	case 128:
++		SrcTcnt = FTDMAC030_CTRL_128BEATS;
++		break;
++	case 64:
++		SrcTcnt = FTDMAC030_CTRL_64BEATS;
++		break;
++	case 32:
++		SrcTcnt = FTDMAC030_CTRL_32BEATS;
++		break;
++	case 16:
++		SrcTcnt = FTDMAC030_CTRL_16BEATS;
++		break;
++	case 8:
++		SrcTcnt = FTDMAC030_CTRL_8BEATS;
++		break;
++	case 4:
++		SrcTcnt = FTDMAC030_CTRL_4BEATS;
++		break;
++	case 2:
++		SrcTcnt = FTDMAC030_CTRL_2BEATS;
++		break;
++	default:
++		SrcTcnt = FTDMAC030_CTRL_1BEAT;
++		break;
++	}
++
++    /* According to CTD/Jerry,
++     * If WSync is disable, tc is asserted when last write command push into command queue.
++     * If WSync is enable, tc is asserted after completing transfer on AXI.
++     * In order to prevent commands not issue to AXI bus, turn on WSync on ctrl register.
++     */
++	ctrl = FTDMAC030_CTRL_ENABLE | SrcTcnt | FTDMAC030_CTRL_WSYNC | FTDMAC030_CTRL_EXP;
++
++	switch (shift) {
++	case 3:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_64
++		     |  FTDMAC030_CTRL_SRC_WIDTH_64;
++		break;
++	case 2:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_32
++		     |  FTDMAC030_CTRL_SRC_WIDTH_32;
++		break;
++	case 1:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_16
++		     |  FTDMAC030_CTRL_SRC_WIDTH_16;
++		break;
++	case 0:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_8
++		     |  FTDMAC030_CTRL_SRC_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	if (fixed_src)
++		ctrl |= FTDMAC030_CTRL_SRC_FIXED;
++	else
++		ctrl |= FTDMAC030_CTRL_SRC_INC;
++
++	if (fixed_dest && !is_memset)
++		ctrl |= FTDMAC030_CTRL_DST_FIXED;
++	else
++		ctrl |= FTDMAC030_CTRL_DST_INC;
++
++	for (offset = 0; offset < len; offset += cycle << shift) {
++		struct ftdmac030_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> shift,
++				MAX_CYCLE_PER_BLOCK);
++
++		desc = ftdmac030_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		/*
++		 * Importatnt: 1. fixed_dest is viewed as memset value
++		 *             2. src is defined as the place of "int value" in ftdmac020_desc
++		 */
++		if (is_memset) {
++			desc->value = fixed_dest;
++			src = desc->txd.phys + sizeof(struct ftdmac030_lld);
++		}
++
++		if (fixed_src)
++			desc->lld.src = src;
++		else
++			desc->lld.src = src + offset;
++
++		if (fixed_dest && !is_memset)
++			desc->lld.dst = dest;
++		else
++			desc->lld.dst = dest + offset;
++
++		desc->cfg = FTDMAC030_CFG_GW(GRANT_WINDOW)
++			  | FTDMAC030_CFG_HIGH_PRIO;
++		desc->len = cycle << shift;
++
++		desc->lld.next	= 0;
++		desc->lld.cycle	= FTDMAC030_CYC_TOTAL(cycle);
++		desc->lld.ctrl	= ctrl;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/*
++			 * Mask terminal count interrupt for this descriptor.
++			 * What an inconvenient stupid design.
++			 */
++			prev->lld.ctrl |= FTDMAC030_CTRL_MASK_TC;
++
++			/* hardware link list pointer */
++			prev->lld.next = desc->txd.phys;
++
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++
++		prev = desc;
++	}
++
++	return first;
++err:
++	if (first)
++		ftdmac030_remove_chain(first);
++	return NULL;
++}
++
++static void ftdmac030_start_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	void __iomem *base = ftchan->ftdmac030->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++
++	/*
++	 * The first transfer block is not described by hardware lld.
++	 * Instead, we should fill some hardware registers.
++	 * What a stupid weird design.
++	 */
++	dev_dbg(chan2dev(chan), "\t[SRC %d] = %x\n", chan_id, desc->lld.src);
++	iowrite32(desc->lld.src, base + FTDMAC030_OFFSET_SRC_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DST %d] = %x\n", chan_id, desc->lld.dst);
++	iowrite32(desc->lld.dst, base + FTDMAC030_OFFSET_DST_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[LLP %d] = %x\n", chan_id, desc->lld.next);
++	iowrite32(desc->lld.next, base + FTDMAC030_OFFSET_LLP_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->lld.cycle);
++	iowrite32(desc->lld.cycle, base + FTDMAC030_OFFSET_CYC_CH(chan_id));
++
++	/* go */
++	dev_dbg(chan2dev(chan), "\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	iowrite32(desc->cfg, base + FTDMAC030_OFFSET_CFG_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CTRL %d] = %x\n", chan_id, desc->lld.ctrl);
++	iowrite32(desc->lld.ctrl, base + FTDMAC030_OFFSET_CTRL_CH(chan_id));
++}
++
++static void ftdmac030_start_new_chain(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac030_desc, node);
++	ftdmac030_start_chain(desc);
++}
++
++static void ftdmac030_finish_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	spin_lock_bh(&ftchan->lock);
++	ftchan->completed_cookie = desc->txd.cookie;
++	spin_unlock_bh(&ftchan->lock);
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback) {
++		/* If this channel is terminated by manual, we dont need to callback */
++		if (ftchan->transaction_type != DMA_TX_TYPE_END)
++			desc->txd.callback(desc->txd.callback_param);
++	}
++
++	ftdmac030_remove_chain(desc);
++}
++
++static void ftdmac030_finish_all_chains(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftdmac030_finish_chain(desc);
++	}
++}
++
++static dma_cookie_t ftdmac030_new_cookie(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftdmac030_chan_filter(struct dma_chan *chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftdmac030_dma_slave *slave = data;
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030 *ftdmac030;
++
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++	ftdmac030 = ftchan->ftdmac030;
++
++	if (strncmp(DRV_NAME, drv_name, sizeof(DRV_NAME)))
++		return false;
++
++	if (slave->id >= 0 && slave->id != ftdmac030->id)
++		return false;
++
++    /* this is platform dependent. Some platform only can use some channels instead of all. */
++    if (platform_chan_filter && platform_chan_filter((int)chan->chan_id))
++        return false;
++
++#if 0 // Let kernel to choose channel
++	if ((slave->channels & (1 << chan->chan_id)) == 0)
++		return false;
++#endif
++
++	chan->private = slave;
++	return true;
++}
++EXPORT_SYMBOL_GPL(ftdmac030_chan_filter);
++
++/******************************************************************************
++ * tasklet - called after we finished one chain
++ *****************************************************************************/
++static void ftdmac030_tasklet(unsigned long data)
++{
++	struct ftdmac030_chan *ftchan = (struct ftdmac030_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++
++	if (ftchan->transaction_type == DMA_TX_TYPE_END) {
++		if (!list_empty(&ftchan->active_list))
++			panic("%s, active_list should be empty due to terminate_all! \n", __func__);
++
++		return;
++	}
++
++	BUG_ON(list_empty(&ftchan->active_list));
++
++	spin_lock_bh(&ftchan->lock);
++
++	/* remove already finished descriptor */
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac030_desc,
++		node);
++	list_del(&desc->node);
++
++	/* check if there were another transfer to do */
++	ftdmac030_start_new_chain(ftchan);
++
++	spin_unlock_bh(&ftchan->lock);
++	ftdmac030_finish_chain(desc);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftdmac030_interrupt(int irq, void *dev_id)
++{
++	struct ftdmac030 *ftdmac030 = dev_id;
++	unsigned int tcs;
++	unsigned int eas;
++	int i;
++
++	tcs = ioread32(ftdmac030->base + FTDMAC030_OFFSET_TCISR);
++	eas = ioread32(ftdmac030->base + FTDMAC030_OFFSET_EAISR);
++	if (!tcs && !eas)
++		return IRQ_NONE;
++
++	/* clear status */
++	if (tcs)
++		iowrite32(tcs, ftdmac030->base + FTDMAC030_OFFSET_TCICR);
++	if (eas)
++		iowrite32(eas, ftdmac030->base + FTDMAC030_OFFSET_EAICR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (eas & FTDMAC030_EA_ERR_CH(i)) {
++			dev_info(chan2dev(chan), "error happened\n");
++			/* dump register to know the direction */
++			printk("ftdmac030_interrupt: srcAddr:0x%x, dstAddr:0x%x, LLP:0x%x \n",
++			    ioread32(ftdmac030->base + 0x108 + 0x20*i), ioread32(ftdmac030->base + 0x10C + 0x20*i),
++			    ioread32(ftdmac030->base + 0x110 + 0x20*i));
++		}
++
++		if (eas & FTDMAC030_EA_ABT_CH(i))
++			dev_info(chan2dev(chan), "transfer aborted\n");
++
++		if (tcs & (1 << i)) {
++			dev_dbg(chan2dev(chan), "terminal count\n");
++			tasklet_schedule(&ftchan->tasklet);
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftdmac030_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftdmac030_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++	bool busy;
++
++	desc = container_of(txd, struct ftdmac030_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	spin_lock_bh(&ftchan->lock);
++
++	cookie = ftdmac030_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list))
++		busy = false;
++	else
++		busy = true;
++
++	list_add_tail(&desc->node, &ftchan->active_list);
++
++#if 0   /* Harry, move to issue pending. If we start the transaction here, it will have potential
++         * chance to lose the LLP due to race condition between CPU and hardware.
++         */
++	/* start ASAP */
++	if (!busy)
++		ftdmac030_start_chain(desc);
++#endif
++
++	spin_unlock_bh(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftdmac030_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftdmac030_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac030_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftdmac030_desc *desc;
++
++		desc = ftdmac030_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	spin_lock_bh(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list);
++	ftchan->completed_cookie = chan->cookie = 1;
++	spin_unlock_bh(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftdmac030_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftdmac030_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_desc *tmp;
++	struct ftdmac030 *ftdmac030;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++	ftdmac030 = ftchan->ftdmac030;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(ftdmac030_chan_is_enabled(ftchan));
++
++	spin_lock_bh(&ftchan->lock);
++	ftdmac030_stop_channel(ftchan);
++	ftdmac030_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftdmac030_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/**
++ * ftdmac030_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac030_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++		dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((src >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect src physical address 0x%x \n", __func__, src);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 7)) {
++		shift = 3;
++	} else if (!((src | dest | len) & 3)) {
++		shift = 2;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++	} else {
++		shift = 0;
++	}
++
++	desc = ftdmac030_create_chain(ftchan, NULL, src, dest, len,
++		shift, 0, 0);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMCPY;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac030_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @value: the given value for memset used
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac030_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest,
++		int value, size_t len, unsigned long flags)
++{
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s(dest %x, value %x, len %x)\n",
++		__func__, dest, value, len);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(len & 3)) {
++		dev_info(chan2dev(chan), "%s: length isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(dest & 3)) {
++		dev_info(chan2dev(chan), "%s: dest addr isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	desc = ftdmac030_create_chain(ftchan, NULL, 0, dest, len,
++		2, 1, value);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMSET;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac030_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac030_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++		unsigned int sg_len, enum dma_transfer_direction direction,
++		unsigned long flags)
++{
++	struct ftdmac030_dma_slave *slave = chan->private;
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int shift;
++	unsigned int i;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		shift = 2;
++		break;
++	case DMA_SLAVE_BUSWIDTH_8_BYTES:
++		shift = 3;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++	switch (direction) {
++	case DMA_TO_DEVICE:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac030_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftdmac030_create_chain(ftchan, desc,
++				mem, slave->common.dst_addr, len,
++				shift, 0, 1);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC030_CFG_DST_HANDSHAKE_EN
++				| FTDMAC030_CFG_DST_HANDSHAKE(slave->handshake);
++		break;
++	case DMA_FROM_DEVICE:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac030_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftdmac030_create_chain(ftchan, desc,
++				slave->common.src_addr, mem, len,
++				shift, 1, 0);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC030_CFG_SRC_HANDSHAKE_EN
++				| FTDMAC030_CFG_SRC_HANDSHAKE(slave->handshake);
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n",
++			__func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_SLAVE;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftdmac030_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++		unsigned long arg)
++{
++	int ret = -ENXIO;
++	struct ftdmac030_chan *ftchan;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++#if 0
++	/* Only supports DMA_TERMINATE_ALL */
++	if (cmd != DMA_TERMINATE_ALL)
++		return -ENXIO;
++#endif
++
++	if (cmd == DMA_SLAVE_CONFIG) {
++		struct dma_slave_config *slave_config = (struct dma_slave_config *)arg;
++		struct ftdmac030_dma_slave  *dma_slave;
++
++		dma_slave = container_of(slave_config, struct ftdmac030_dma_slave, common);
++		chan->private = dma_slave;
++		ret = 0;
++	}
++
++	if (cmd == DMA_TERMINATE_ALL) {
++		/*
++		 * This is only called when something went wrong elsewhere, so
++		 * we don't really care about the data. Just disable the channel.
++		 */
++		spin_lock_bh(&ftchan->lock);
++		ftdmac030_stop_channel(ftchan);
++		ftdmac030_finish_all_chains(ftchan);
++		ftchan->transaction_type = DMA_TX_TYPE_END;
++		spin_unlock_bh(&ftchan->lock);
++	}
++	return ret;
++}
++
++/**
++ * ftdmac030_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftdmac030_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		struct dma_tx_state *txstate)
++{
++	struct ftdmac030_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftdmac030_issue_pending - try to finish work
++ * @chan: target DMA channel
++ */
++static void ftdmac030_issue_pending(struct dma_chan *chan)
++{
++	struct ftdmac030_chan *ftchan;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	spin_lock_bh(&ftchan->lock);
++	BUG_ON(list_empty(&ftchan->active_list));
++	/* get first descriptor and go */
++	ftdmac030_start_new_chain(ftchan);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftdmac030_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftdmac030 *ftdmac030;
++	struct dma_device *dma;
++	int irq;
++	int i;
++	int err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftdmac030 = kzalloc(sizeof(*ftdmac030), GFP_KERNEL);
++	if (!ftdmac030) {
++		return -ENOMEM;
++	}
++
++	dma = &ftdmac030->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftdmac030);
++	ftdmac030->id = pdev->id;
++
++	/* map io memory */
++
++	ftdmac030->res = request_mem_region(res->start, res->end - res->start + 1,
++			dev_name(&pdev->dev));
++	if (ftdmac030->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftdmac030->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftdmac030->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* create a pool of consistent memory blocks for hardware descriptors */
++	ftdmac030->dma_desc_pool = dma_pool_create("ftdmac030_desc_pool",
++			&pdev->dev, sizeof(struct ftdmac030_desc),
++			8 /* double word alignment */, 0);
++	if (!ftdmac030->dma_desc_pool) {
++		dev_err(&pdev->dev, "No memory for descriptor pool\n");
++		err = -ENOMEM;
++		goto err_pool_create;
++	}
++
++	/* initialize channels */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device	= dma;
++		ftchan->common.cookie	= DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftdmac030		= ftdmac030;
++		ftchan->completed_cookie	= DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftdmac030_tasklet,
++				(unsigned long)ftchan);
++		list_add_tail(&ftchan->common.device_node, &dma->channels);
++	}
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftdmac030_alloc_chan_resources;
++	dma->device_free_chan_resources	= ftdmac030_free_chan_resources;
++	dma->device_prep_dma_memcpy	= ftdmac030_prep_dma_memcpy;
++	dma->device_prep_dma_memset	= ftdmac030_prep_dma_memset;
++	dma->device_prep_slave_sg	= ftdmac030_prep_slave_sg;
++	dma->device_control		= ftdmac030_control;
++	dma->device_tx_status		= ftdmac030_tx_status;
++	dma->device_issue_pending	= ftdmac030_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
++	dma_cap_set(DMA_MEMSET, dma->cap_mask);
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);
++
++	err = request_irq(irq, ftdmac030_interrupt, IRQF_SHARED, pdev->name, ftdmac030);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_req_irq;
++	}
++	ftdmac030->irq = irq;
++
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	dev_info(&pdev->dev,
++		"DMA engine driver: irq %d, mapped at %p\n",
++		irq, ftdmac030->base);
++	
++    /* sync dma_req */
++    iowrite32(0xFF, ftdmac030->base + FTDMAC030_OFFSET_SYNC);
++    
++	return 0;
++
++err_register:
++	free_irq(irq, ftdmac030);
++err_req_irq:
++	dma_pool_destroy(ftdmac030->dma_desc_pool);
++err_pool_create:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftdmac030->base);
++err_ioremap:
++	release_resource(ftdmac030->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac030);
++	return err;
++}
++
++static int __exit ftdmac030_remove(struct platform_device *pdev)
++{
++	struct ftdmac030 *ftdmac030;
++	int i;
++
++	ftdmac030 = platform_get_drvdata(pdev);
++
++	dma_async_device_unregister(&ftdmac030->dma);
++
++	free_irq(ftdmac030->irq, ftdmac030);
++	dma_pool_destroy(ftdmac030->dma_desc_pool);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftdmac030->base);
++	release_resource(ftdmac030->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac030);
++	return 0;
++}
++
++/**
++ * ftdmac030_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac030_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac030_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id))
++{
++    if (platform_chan_filter != NULL) {
++        printk("%s, platform_chan_filter was registered already! \n", __func__);
++        return -1;
++    }
++
++    platform_chan_filter = chan_filter_fn;
++
++    return 0;
++}
++
++/* proc function
++ */
++static struct proc_dir_entry *sw_int_proc = NULL;
++
++ /* sw interrupt info
++  */
++static int proc_read_swint_stats(char *page, char **start, off_t off, int count, int *eof,
++                                    void *data)
++{
++    int i, len = 0;
++
++    for (i = 0; i < ARRAY_SIZE(dmac030_sw_intr); i ++)
++        len += sprintf(page + len, "sw_int[%d] = %d \n", i, dmac030_sw_intr[i]);
++
++    return len;
++}
++
++static void ftdmac030_proc_init(void)
++{
++    struct proc_dir_entry *p;
++
++    p = create_proc_entry("dmac030", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (p == NULL) {
++        panic("error in %s \n", __func__);
++    }
++
++    /*
++     * sw interruupt counter
++     */
++    sw_int_proc = create_proc_entry("sw_int", S_IRUGO, p);
++    if (sw_int_proc == NULL)
++        panic("DMAC030: Fail to create proc sw_int!\n");
++
++    sw_int_proc->read_proc = (read_proc_t *) proc_read_swint_stats;
++}
++
++/* driver
++ */
++static struct platform_driver ftdmac030_driver = {
++	.probe		= ftdmac030_probe,
++	.remove		= __exit_p(ftdmac030_remove),
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftdmac030_init(void)
++{
++    ftdmac030_proc_init();
++
++    /* Register PMU and turn on gate clock
++     */
++    dmac030_fd = ftpmu010_register_reg(&pmu_reg_info);
++    if (dmac030_fd < 0) {
++        printk("Warning............DMAC030: register PMU fail");
++        return 0;
++    }
++
++	return platform_driver_register(&ftdmac030_driver);
++}
++
++static void __exit ftdmac030_exit(void)
++{
++	platform_driver_unregister(&ftdmac030_driver);
++    /* Deregister PMU
++     */
++    ftpmu010_deregister_reg(dmac030_fd);
++}
++
++module_init(ftdmac030_init);
++module_exit(ftdmac030_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTDMAC030 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-SMP/ftpmu010.c b/arch/arm/mach-GM-SMP/ftpmu010.c
+new file mode 100644
+index 00000000..0351df84
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/ftpmu010.c
+@@ -0,0 +1,1115 @@
++/*
++ *  Copyright (C) 2010 Grain-Media Technology.
++ *
++ * 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 <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/hardirq.h>
++#include <linux/semaphore.h>
++#include <linux/sched.h>
++#include <asm/io.h>
++#include <linux/proc_fs.h>
++#include <mach/ftpmu010.h>
++
++#define  REG_ARRAY_SZ   30      //Max value for register array
++
++/* Local Variables
++ */
++static u32 fd = 1;
++static struct proc_dir_entry *pmu_proc_root = NULL;
++static struct proc_dir_entry *attribute_proc = NULL;
++static struct proc_dir_entry *regInfo_proc = NULL;
++static struct proc_dir_entry *chipver_proc = NULL;
++
++static ftpmu010_gate_clk_t *pmu_clkgate_tbl = NULL;
++static int (*pmu_ctrl_handler) (u32 cmd, u32 data1, u32 data2) = NULL;
++
++/* Local Functions
++ */
++static int ftpmu010_proc_init(void);
++
++/* MACROs
++ */
++#define ATTR_LIST               ftpmu10.attr_list
++#define REGINFO_LIST            ftpmu10.reginfo_list
++#define LIST_LOCK               spin_lock_irqsave(&ftpmu10.spinlock, flags)
++#define LIST_UNLOCK             spin_unlock_irqrestore(&ftpmu10.spinlock, flags)
++#define REGINFO_OFFSET(x,y)     (x)->pmuReg_info.pRegArray[(y)].reg_off
++#define REGINFO_BITSMASK(x,y)   (x)->pmuReg_info.pRegArray[(y)].bits_mask
++#define REGINFO_LOCKBITS(x,y)   (x)->pmuReg_info.pRegArray[(y)].lock_bits
++#define REGINFO_NAME(x)         (x)->pmuReg_info.name
++#define REGINFO_REGCNT(x)       (x)->pmuReg_info.num
++#define REGINFO_CLKSRC          (x)->pmuReg_info.clock_src
++
++typedef struct {
++    attrInfo_t attr_info;
++    struct list_head list;
++} attrInfo_node_t;
++
++typedef struct {
++    u32 fd;                     /* unique number */
++    pmuRegInfo_t pmuReg_info;
++    struct list_head list;
++    wait_queue_head_t wait_queue;       /* wait queue */
++    int waiting;
++    int ref_cnt;
++} pmuRegInfo_node_t;
++
++/* main structure
++ */
++static struct ftpmu10_s {
++    void __iomem *base;
++#ifdef USE_SEMA
++    struct semaphore sema;
++#else
++    spinlock_t spinlock;
++#endif
++    /* attribute list */
++    struct list_head attr_list;
++    /* register list */
++    struct list_head reginfo_list;
++} ftpmu10;
++
++/* Register a clok node.
++ * return value: 0 for success, < 0 for fail.
++ */
++int ftpmu010_register_attr(attrInfo_t * attr)
++{
++    unsigned long flags;
++    attrInfo_node_t *node;
++    int ret = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        //printk("PMU: %s \n", node->attr_info.name);
++
++        if (node->attr_info.attr_type == attr->attr_type) {
++            ret = -1;
++            break;
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    if (ret < 0)
++        return ret;
++
++    ret = -1;
++    node = kzalloc(sizeof(attrInfo_node_t), GFP_ATOMIC);
++    if (node) {
++        memcpy(&node->attr_info, attr, sizeof(attrInfo_t));
++        INIT_LIST_HEAD(&node->list);
++        list_add_tail(&node->list, &ATTR_LIST);
++        try_module_get(THIS_MODULE);
++        ret = 0;
++    }
++
++    return ret;
++}
++
++/* DeRegister a clok node.
++ * return value: 0 for success, < 0 for fail.
++ */
++int ftpmu010_deregister_attr(attrInfo_t * attr)
++{
++    unsigned long flags;
++    attrInfo_node_t *node, *ne;
++    int ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry_safe(node, ne, &ATTR_LIST, list) {
++        if (node->attr_info.attr_type == attr->attr_type) {
++            list_del_init(&node->list);
++            kfree(node);
++            module_put(THIS_MODULE);
++            ret = 0;
++            break;
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return ret;
++}
++
++/* get the content of the attribute
++ * return value: 0 for fail, > 0 for success
++ */
++unsigned int ftpmu010_get_attr(ATTR_TYPE_T attr_type)
++{
++    attrInfo_node_t *node;
++    unsigned int value = -1;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        if (node->attr_info.attr_type == attr_type) {
++            value = node->attr_info.value;
++            break;
++        }
++    }
++
++    return value;
++}
++
++/* register/de-register the register table
++ * return value:
++ *  give an unique fd if return value >= 0, otherwise < 0 if fail.
++ */
++int ftpmu010_register_reg(pmuRegInfo_t * info)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node, *new_node;
++    int i, j, ret = -1;
++    u32 reg_off;
++
++    /* sanity check */
++    if (unlikely(!strlen(info->name)))
++        return -1;
++
++    /* check if the register offset is duplicated */
++    for (i = 0; i < info->num; i++) {
++        reg_off = info->pRegArray[i].reg_off;
++
++        for (j = 0; j < info->num; j++) {
++            if (i == j)
++                continue;
++
++#if 1                           /* allow gather the mask, lock_bit .... */
++            if (reg_off == info->pRegArray[j].reg_off) {
++                info->pRegArray[i].bits_mask |= info->pRegArray[j].bits_mask;
++                info->pRegArray[i].lock_bits |= info->pRegArray[j].lock_bits;
++                info->pRegArray[i].init_val |= info->pRegArray[j].init_val;
++                info->pRegArray[i].init_mask |= info->pRegArray[j].init_mask;
++            }
++#else
++            if (reg_off == info->pRegArray[j].reg_off) {
++                printk("PMU: reg_offset 0x%x is duplicated! \n", reg_off);
++                return -1;
++            }
++#endif
++        }
++    }
++
++    /* self-test, bits_mask must cover lock_bits and init_val */
++    for (i = 0; i < info->num; i++) {
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].lock_bits) {
++            printk("PMU: %s wrong lock_bits 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].lock_bits, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].init_val) {
++            printk("PMU: %s wrong init_val 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_val, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].init_mask) {
++            printk("PMU: %s wrong init_mask 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_mask, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].init_mask) & info->pRegArray[i].init_val) {
++            printk("PMU: %s wrong init_val 0x%x or init_mask 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_val, info->pRegArray[i].init_mask,
++                   info->pRegArray[i].reg_off);
++            return -1;
++        }
++    }
++
++    if (info->clock_src != ATTR_TYPE_NONE) {
++        if (ftpmu010_get_attr(info->clock_src) < 0) {
++            printk("PMU: %s registers non-existence clock source! \n", info->name);
++            return -1;
++        }
++    }
++
++    /* lock */
++    LIST_LOCK;
++
++    /* 1. check if duplicate registeration
++     */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (!strcmp(REGINFO_NAME(node), info->name)) {
++            /* allow the same node is multiple registered */
++            if ((info->num == REGINFO_REGCNT(node))
++                && !memcmp(info->pRegArray, node->pmuReg_info.pRegArray,
++                           info->num * sizeof(pmuReg_t))) {
++                node->ref_cnt++;
++                /* unlock */
++                LIST_UNLOCK;
++                return node->fd;
++            }
++            printk("PMU: %s was registed already! \n", info->name);
++            goto exit;
++        }
++    }
++
++    /* 2. check if the lockbits is overlap.
++     */
++    for (i = 0; i < info->num; i++) {
++        /* check the registers in each node */
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            for (j = 0; j < REGINFO_REGCNT(node); j++) {
++                if (info->pRegArray[i].reg_off != REGINFO_OFFSET(node, j))
++                    continue;
++
++                if (info->pRegArray[i].lock_bits & REGINFO_LOCKBITS(node, j)) {
++                    printk("PMU: lock_bits of %s is overlapped with %s in offset 0x%x! \n",
++                           info->name, REGINFO_NAME(node), info->pRegArray[i].reg_off);
++                    goto exit;
++                }
++            }                   /* loop j */
++        }
++    }                           /* loop i */
++
++    /* 3. sanity check is ok, create new node and chan it to the list
++     */
++    new_node = kzalloc(sizeof(pmuRegInfo_node_t), GFP_ATOMIC);
++    if (unlikely(!new_node)) {
++        ret = -ENOMEM;
++        goto exit;
++    }
++    new_node->fd = fd++;
++    new_node->ref_cnt = 1;
++    INIT_LIST_HEAD(&new_node->list);
++    memcpy(&new_node->pmuReg_info, info, sizeof(pmuRegInfo_t));
++    if (info->num >= REG_ARRAY_SZ)
++        panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++    new_node->pmuReg_info.pRegArray = kzalloc(REG_ARRAY_SZ * sizeof(pmuReg_t), GFP_ATOMIC);
++    if (unlikely(!new_node->pmuReg_info.pRegArray)) {
++        kfree(new_node);
++        ret = -ENOMEM;
++        goto exit;
++    }
++
++    /* init waitQ */
++    init_waitqueue_head(&new_node->wait_queue);
++
++    /* copy register array body */
++    if (info->num)
++        memcpy(new_node->pmuReg_info.pRegArray, info->pRegArray, info->num * sizeof(pmuReg_t));
++
++    list_add_tail(&new_node->list, &REGINFO_LIST);
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    ret = new_node->fd;
++    try_module_get(THIS_MODULE);
++
++    /* update to hardware */
++    for (i = 0; i < info->num; i++)
++        ftpmu010_write_reg(new_node->fd, info->pRegArray[i].reg_off, info->pRegArray[i].init_val,
++                           info->pRegArray[i].init_mask);
++
++    return ret;
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_deregister_reg(int fd)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node, *ne;
++    int ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry_safe(node, ne, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            if (--node->ref_cnt) {
++                ret = 0;
++                goto exit;
++            }
++            //printk("PMU: %s is deregistered. \n", node->pmuReg_info.name);
++            list_del_init(&node->list);
++            if (node->pmuReg_info.pRegArray)
++                kfree(node->pmuReg_info.pRegArray);
++            kfree(node);
++            module_put(THIS_MODULE);
++            ret = 0;
++            break;
++        }
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* lock/unlock/replace the bits in lock_bits field
++ * return value:
++ *  0 for success, < 0 for fail
++ */
++int ftpmu010_add_lockbits(int fd, unsigned int reg_off, unsigned int lock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    u32 *pLock_bits = NULL;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* do overlap check */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {   /* self check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                pLock_bits = &REGINFO_LOCKBITS(node, i);
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & lock_bits) {
++                    printk("PMU: %s new %#x is out of bits_mask %#x!\n", REGINFO_NAME(node),
++                           lock_bits, REGINFO_BITSMASK(node, i));
++                    goto exit;
++                }
++                ret = 0;
++                break;
++            }                   /* for i */
++        } else {
++            /* conflict check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                if (REGINFO_LOCKBITS(node, i) & lock_bits) {
++                    printk("PMU: %#x conflicts with lock_bits %#x of %s in off: %#x\n", lock_bits,
++                           REGINFO_LOCKBITS(node, i), REGINFO_NAME(node), reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }                       /* fd */
++    }
++
++    if (!ret)
++        *pLock_bits |= lock_bits;
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_del_lockbits(int fd, unsigned int reg_off, unsigned int unlock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            REGINFO_LOCKBITS(node, i) &= ~unlock_bits;
++            ret = 0;
++            break;
++        }
++        break;
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_update_lockbits(int fd, unsigned int reg_off, unsigned int new_lock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    u32 *pLock_bits = NULL;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                pLock_bits = &REGINFO_LOCKBITS(node, i);
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & new_lock_bits) {
++                    printk("PMU: %s new 0x%x is out of bits_mask 0x%x!\n", REGINFO_NAME(node),
++                           new_lock_bits, REGINFO_BITSMASK(node, i));
++                    goto exit;
++                }
++                ret = 0;
++                break;
++            }                   /* for i */
++        } else {
++            /* conflict check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                if (REGINFO_LOCKBITS(node, i) & new_lock_bits) {
++                    printk("PMU: new 0x%x conflicts with lock_bits 0x%x of %s\n", new_lock_bits,
++                           REGINFO_LOCKBITS(node, i), REGINFO_NAME(node));
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }
++    }
++
++    if (!ret)
++        *pLock_bits = new_lock_bits;
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* @int ftpmu010_bits_is_locked(int fd, int reg_off, unsigned int bits)
++ * @Purpose: This function is used to check if the bits are locked by any module or not.
++ * @Parameter:
++ *   reg_off: register offset
++ *   bits: the checked bits
++ * @Return:
++ *      If the any bit in bits is locked, then the returned value will be 0
++ *      otherwise, -1 is returned to indicates all bits are available.
++ *
++ */
++int ftpmu010_bits_is_locked(int fd, unsigned int reg_off, unsigned int bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        /* conflict check */
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            if (REGINFO_LOCKBITS(node, i) & bits) {
++                ret = 0;
++                goto exit;
++            }
++            break;
++        }
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* PMU register read/write
++ */
++unsigned int ftpmu010_read_reg(unsigned int reg_off)
++{
++    return ioread32(ftpmu10.base + reg_off);
++}
++
++/* return value < 0 for fail */
++int ftpmu010_write_reg(int fd, unsigned int reg_off, unsigned int val, unsigned int mask)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* sanity check */
++    if (unlikely(val & (~mask))) {
++        printk("%s: wrong mask:%#x or value:%#x in offset:%#x! \n", __func__, mask, val, reg_off);
++        goto exit;
++    }
++
++    if (unlikely(!mask)) {
++        ret = 0;
++        goto exit;              /* do nothing */
++    }
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            ret = -1;
++            /* check if reg_off had been registered already */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & mask) {
++                    printk("PMU: %s writes with wrong mask 0x%x in off:%#x! \n",
++                           REGINFO_NAME(node), mask, reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                ret = 0;
++            }
++        }
++#if 0                           /* Bug fix, 2011/12/20 11:10�W��
++                                 * We don't need to check if my operation mask conflicts with the lockbits of others
++                                 */
++        else {
++            /* check if the bits is on lock_bits of others */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                /* is lock_bits conflicts with the input mask ? */
++                if (REGINFO_LOCKBITS(node, i) & mask) {
++                    printk("PMU: Wrong mask 0x%x conflicts with %s in off:%#x! \n", mask,
++                           REGINFO_NAME(node), reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }
++#endif
++    }
++
++    if (!ret) {
++        u32 tmp;
++
++        tmp = (ftpmu010_read_reg(reg_off) & (~mask));
++        tmp |= (val & mask);
++        iowrite32(tmp, ftpmu10.base + reg_off);
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++
++    if (ret < 0) {
++        dump_stack();
++        panic("Configure PMU fail! \n");
++    }
++
++    return ret;
++}
++
++/* PMU init function
++ * Input parameters: virtual address of PMU
++ *  tbl: clock gating table for IPs
++ *  pmu_handler: the callback from pmu to reload/reconfigure pmu. NULL if unecessary
++ * Return: 0 for success, < 0 for fail
++ */
++int __init ftpmu010_init(void __iomem * base, ftpmu010_gate_clk_t * tbl, void *pmu_handler)
++{
++    int i = 0;
++    ftpmu010_gate_clk_t *table = tbl;
++
++    ftpmu10.base = base;
++    spin_lock_init(&ftpmu10.spinlock);
++    INIT_LIST_HEAD(&ftpmu10.attr_list);
++    INIT_LIST_HEAD(&ftpmu10.reginfo_list);
++    /* proc function */
++    ftpmu010_proc_init();
++
++    /* self test */
++    while (table->midx != FTPMU_NONE) {
++        for (i = 0; i < table->num; i++) {
++            if (table->reg[i].bit_val & ~table->reg[i].bit_mask)
++                panic("%s, error gating clock table in ofs 0x%x of midx:%d! \n", __func__,
++                      table->reg[i].ofs, table->midx);
++        }
++        table++;
++    }
++
++    pmu_clkgate_tbl = tbl;
++    /* register the callback from pmu */
++    pmu_ctrl_handler = pmu_handler;
++
++    return 0;
++}
++
++/* Purpose: calculate the divisor by input clock
++ * Input: fd, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor(int fd, unsigned int in_clock, int near)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    unsigned int clock = 0;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        clock = ftpmu010_get_attr(node->pmuReg_info.clock_src);
++        if (clock == (u32) - 1)
++            return 0;
++
++        if (near)
++            clock += (in_clock >> 1);
++        /* n = n / base; return rem; */
++        do_div(clock, in_clock);
++        break;
++    }
++
++    LIST_UNLOCK;
++
++    return clock;
++}
++
++/* Purpose: calculate the divisor by input clock attribute
++ * Input: clock_src, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor2(ATTR_TYPE_T clock_src, unsigned int in_clock, int near)
++{
++    unsigned int clock = 0;
++
++    clock = ftpmu010_get_attr(clock_src);
++    if (clock == (u32) - 1)
++        return 0;
++    if (near)
++        clock += (in_clock >> 1);
++    /* n = n / base; return rem; */
++    do_div(clock, in_clock);
++
++    return clock;
++}
++
++/* @Purpose: request the pmu PIN
++ * @Parameter:
++ *      fd: unique identifier
++ *      reg_off: register offset
++ *      req_bits: request registers
++ *      b_wait: 1 for blocking until the resource is available
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_request_pins(int fd, unsigned int reg_off, unsigned int req_bits, int b_wait)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ofs, is_new, ret = 0;
++
++    if (b_wait) {
++        if (in_interrupt() || in_atomic())
++            panic("%s, wrong context in interrupt or atomic \n", __func__);
++    }
++
++    /* lock */
++    LIST_LOCK;
++    if (ftpmu010_bits_is_locked(fd, reg_off, req_bits) == -1) {
++        /* the bits are available */
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            if (node->fd != fd)
++                continue;
++
++            /* check if the offset exists ? */
++            is_new = 1;
++            for (i = 0; i < REGINFO_REGCNT(node); i ++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                REGINFO_BITSMASK(node, i) |= req_bits;
++                REGINFO_LOCKBITS(node, i) |= req_bits;
++                is_new = 0; /* this is not a new offset */
++                break;
++            }
++
++            if (is_new) { /* new node */
++                ofs = REGINFO_REGCNT(node);
++                if (ofs >= REG_ARRAY_SZ)
++                    panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++
++                REGINFO_OFFSET(node, ofs) = reg_off;
++                REGINFO_BITSMASK(node, ofs) = req_bits;
++                REGINFO_LOCKBITS(node, ofs) = req_bits;
++
++                REGINFO_REGCNT(node) ++;
++            }
++            break;
++        }
++    } else {
++        /* the bits are locked by others */
++        if (!b_wait) {
++            ret = -1;
++            goto exit;
++        }
++
++        ret = -1;
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            if (node->fd != fd)
++                continue;
++            ret = 0;
++            break;
++        }
++
++        if (ret == -1)
++            panic("%s, can't find fd in pmu module! \n", __func__);
++
++        node->waiting = 0;
++
++keep_wait:
++        LIST_UNLOCK;
++        wait_event_interruptible(node->wait_queue, node->waiting);
++        if (signal_pending(current))
++			return -ERESTARTSYS;
++        node->waiting = 0;
++
++        LIST_LOCK;
++
++        /* bits are freed */
++        if (ftpmu010_bits_is_locked(fd, reg_off, req_bits) == -1) {
++            ret = -1;
++            /* find the existed offset */
++            for (i = 0; i < REGINFO_REGCNT(node); i ++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                REGINFO_BITSMASK(node, i) |= req_bits;
++                REGINFO_LOCKBITS(node, i) |= req_bits;
++                ret = 0;
++                break;
++            }
++
++            if (ret == -1) {
++                /* new offset */
++                ofs = REGINFO_REGCNT(node);
++                if (ofs >= REG_ARRAY_SZ)
++                    panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++                REGINFO_OFFSET(node, ofs) = reg_off;
++                REGINFO_BITSMASK(node, ofs) = req_bits;
++                REGINFO_LOCKBITS(node, ofs) = req_bits;
++                REGINFO_REGCNT(node) ++;
++                ret = 0;
++            }
++        } else {
++            goto keep_wait;
++        }
++    }
++
++exit:
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* Purpose: release the pmu PIN
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_release_pins(int fd, unsigned int reg_off, unsigned int req_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            if (REGINFO_LOCKBITS(node, i) & req_bits) {
++                REGINFO_BITSMASK(node, i) &= ~req_bits;
++                REGINFO_LOCKBITS(node, i) &= ~req_bits;
++                ret = 0;
++            }
++            break;
++        }
++
++        break;
++    }
++
++    /* wake up the ones who are waiting for the pins */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        node->waiting = 1;
++        wake_up(&node->wait_queue);
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    return ret;
++}
++
++/* Purpose: check if the PINs was requested by others except myself.
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: those pins occupied by others. zero indicates the pin are available.
++ */
++unsigned int ftpmu010_pins_is_requested(int fd, unsigned int reg_off, unsigned int req_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            req_bits &= REGINFO_LOCKBITS(node, i);
++            break;
++        }
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    return req_bits;
++}
++
++/*
++ * This function is used to call pmu handler to reconfigure/reload the pmu setting
++ */
++int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2)
++{
++    int ret = -1;
++
++    if (pmu_ctrl_handler)
++        ret = (*pmu_ctrl_handler) (cmd, data1, data2);
++    else
++        printk("%s, pmu_ctrl_handler is not registered yet! \n", __func__);
++
++    return ret;
++}
++
++/* ------------------------------------------------------------------------------------
++ *  Proc function
++ * ------------------------------------------------------------------------------------
++ */
++
++ /* Attribute info
++  */
++static int proc_read_attribute_info(char *page, char **start, off_t off, int count, int *eof,
++                                    void *data)
++{
++    unsigned long flags;
++    attrInfo_node_t *node;
++    int len = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        len += sprintf(page + len, "Attribute name : %s \n", node->attr_info.name);
++        len += sprintf(page + len, "Attribute type : %d \n", node->attr_info.attr_type);
++        if (node->attr_info.attr_type == ATTR_TYPE_CHIPVER) {
++            len += sprintf(page + len, "Attribute value: 0x%x \n\n", node->attr_info.value);
++        } else {
++            len += sprintf(page + len, "Attribute value: %d \n\n", node->attr_info.value);
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return len;
++}
++
++/* Register info
++ */
++static int proc_read_reginfo(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, len = 0, pos, begin = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        pos = begin + len;
++        if (pos < off) {
++            len = 0;
++            begin = pos;
++        }
++
++        if (pos > off + count)
++            goto exit;
++
++        len +=
++            sprintf(page + len, "name: %s, fd = %d, attribute type = %d \n", REGINFO_NAME(node),
++                    node->fd, node->pmuReg_info.clock_src);
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            len += sprintf(page + len, "    reg_off: 0x%x, bits_mask: 0x%x, lock_bits: 0x%x\n",
++                           REGINFO_OFFSET(node, i), REGINFO_BITSMASK(node, i),
++                           REGINFO_LOCKBITS(node, i));
++        }
++
++        len += sprintf(page + len, "\n");
++    }
++    *eof = 1;
++    /* unlock */
++    LIST_UNLOCK;
++
++    return len;
++
++exit:
++    /* unlock */
++    LIST_UNLOCK;
++
++    *start = page + (off - begin);
++    len -= (off - begin);
++
++    if (len > count)
++        len = count;
++    else if (len < 0)
++        len = 0;
++
++    return len;
++}
++
++/* chip version info
++ */
++static int proc_read_chip_version(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned int value;
++    int len = 0;
++
++    value = ftpmu010_get_attr(ATTR_TYPE_CHIPVER);
++
++    len += sprintf(page + len, "%x\n", value);
++
++    return len;
++}
++
++static int ftpmu010_proc_init(void)
++{
++    int ret = 0;
++    struct proc_dir_entry *p;
++
++    p = create_proc_entry("pmu", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (p == NULL) {
++        return -ENOMEM;
++    }
++    pmu_proc_root = p;
++    /* pmu_proc_root->data = ;  */
++    /*
++     * attribute
++     */
++    attribute_proc = create_proc_entry("attribute", S_IRUGO, pmu_proc_root);
++    if (attribute_proc == NULL) {
++        printk("PMU: Fail to create proc attribute!\n");
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    attribute_proc->read_proc = (read_proc_t *) proc_read_attribute_info;
++    attribute_proc->write_proc = NULL;
++
++    /*
++     * regInfo
++     */
++    regInfo_proc = create_proc_entry("reginfo", S_IRUGO, pmu_proc_root);
++    if (regInfo_proc == NULL) {
++        printk("PMU: Fail to create proc regInfo!\n");
++        remove_proc_entry(attribute_proc->name, pmu_proc_root);
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    regInfo_proc->read_proc = (read_proc_t *) proc_read_reginfo;
++    regInfo_proc->write_proc = NULL;
++
++    /* IC version, for some AP easy to read */
++    chipver_proc = create_proc_entry("chipver", S_IRUGO, pmu_proc_root);
++    if (chipver_proc == NULL) {
++        printk("PMU: Fail to create proc regInfo!\n");
++        remove_proc_entry(attribute_proc->name, pmu_proc_root);
++        remove_proc_entry(regInfo_proc->name, pmu_proc_root);
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    chipver_proc->read_proc = (read_proc_t *) proc_read_chip_version;
++    chipver_proc->write_proc = NULL;
++
++  end:
++    return ret;
++}
++
++EXPORT_SYMBOL(ftpmu010_register_attr);
++EXPORT_SYMBOL(ftpmu010_deregister_attr);
++EXPORT_SYMBOL(ftpmu010_get_attr);
++EXPORT_SYMBOL(ftpmu010_register_reg);
++EXPORT_SYMBOL(ftpmu010_deregister_reg);
++EXPORT_SYMBOL(ftpmu010_add_lockbits);
++EXPORT_SYMBOL(ftpmu010_del_lockbits);
++EXPORT_SYMBOL(ftpmu010_bits_is_locked);
++EXPORT_SYMBOL(ftpmu010_update_lockbits);
++EXPORT_SYMBOL(ftpmu010_read_reg);
++EXPORT_SYMBOL(ftpmu010_write_reg);
++EXPORT_SYMBOL(ftpmu010_clock_divisor);
++EXPORT_SYMBOL(ftpmu010_request_pins);
++EXPORT_SYMBOL(ftpmu010_release_pins);
++EXPORT_SYMBOL(ftpmu010_pins_is_requested);
++EXPORT_SYMBOL(ftpmu010_pmu_doaction);
++EXPORT_SYMBOL(ftpmu010_clock_divisor2);
++
++MODULE_AUTHOR("Grain-Media");
++MODULE_DESCRIPTION("FTPMU010 core");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-SMP/fttmr010.c b/arch/arm/mach-GM-SMP/fttmr010.c
+new file mode 100644
+index 00000000..0276a870
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/fttmr010.c
+@@ -0,0 +1,275 @@
++/*
++ *  Faraday FTTMR010 Timer
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <asm/io.h>
++#include <asm/mach/irq.h>
++#include <mach/fttmr010.h>
++
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static const unsigned int fttmr010_cr_mask[3] = {
++	FTTMR010_TM1_ENABLE | FTTMR010_TM1_CLOCK |
++	FTTMR010_TM1_OFENABLE | FTTMR010_TM1_UPDOWN,
++
++	FTTMR010_TM2_ENABLE | FTTMR010_TM2_CLOCK |
++	FTTMR010_TM2_OFENABLE | FTTMR010_TM2_UPDOWN,
++
++	FTTMR010_TM3_ENABLE | FTTMR010_TM3_CLOCK |
++	FTTMR010_TM3_OFENABLE | FTTMR010_TM3_UPDOWN,
++};
++
++/* we always use down counter */
++static const unsigned int fttmr010_cr_enable_flag[3] = {
++	FTTMR010_TM1_ENABLE | FTTMR010_TM1_OFENABLE,
++	FTTMR010_TM2_ENABLE | FTTMR010_TM2_OFENABLE,
++	FTTMR010_TM3_ENABLE | FTTMR010_TM3_OFENABLE,
++};
++
++static const unsigned int fttmr010_cr_enable_noirq_flag[3] = {
++	FTTMR010_TM1_ENABLE,
++	FTTMR010_TM2_ENABLE,
++	FTTMR010_TM3_ENABLE,
++};
++
++/* TmxEnable + overflow interrupt enable
++ */
++static void fttmr010_enable(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];    /* maskout the mask, all setting goes to zero. */
++	cr |= fttmr010_cr_enable_flag[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++/* Just no overflow interrupt enable bit
++ */
++static void fttmr010_enable_noirq(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	cr |= fttmr010_cr_enable_noirq_flag[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static void fttmr010_disable(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static inline void fttmr010_write_timer(void __iomem *base, unsigned int id,
++		unsigned int reg, unsigned int value)
++{
++	void __iomem *addr = base + FTTMR010_OFFSET_TIMER(id) + reg;
++	writel (value, addr);
++}
++
++static inline unsigned int fttmr010_read_timer(void __iomem *base,
++		unsigned int id, unsigned int reg)
++{
++	void __iomem *addr = base + FTTMR010_OFFSET_TIMER(id) + reg;
++	return readl(addr);
++}
++
++static void fttmr010_set_counter(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_COUNTER, value);
++}
++
++static inline unsigned int fttmr010_get_counter(void __iomem *base, unsigned int id)
++{
++	return fttmr010_read_timer(base, id, FTTMR010_OFFSET_COUNTER);
++}
++
++static void fttmr010_set_reload(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_LOAD, value);
++}
++
++static void fttmr010_set_match1(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_MATCH1, value);
++}
++
++static void fttmr010_set_match2(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_MATCH2, value);
++}
++
++/******************************************************************************
++ * clockevent functions. Set the next trigger event
++ *****************************************************************************/
++static int fttmr010_set_next_event(unsigned long clc, struct clock_event_device *ce)
++{
++	struct fttmr010_clockevent *fttmr010;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++	fttmr010_set_counter(fttmr010->base, fttmr010->id, clc);
++
++	return 0;
++}
++
++static void fttmr010_set_mode(enum clock_event_mode mode, struct clock_event_device *ce)
++{
++	struct fttmr010_clockevent *fttmr010;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++
++	switch (mode) {
++	case CLOCK_EVT_MODE_PERIODIC:
++		fttmr010_set_reload(fttmr010->base, fttmr010->id, fttmr010->reload);
++		fttmr010_set_counter(fttmr010->base, fttmr010->id, fttmr010->reload);
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_RESUME:
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_ONESHOT:
++		fttmr010_set_reload(fttmr010->base, fttmr010->id, 0);
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_UNUSED:
++	case CLOCK_EVT_MODE_SHUTDOWN:
++	default:
++		fttmr010_disable(fttmr010->base, fttmr010->id);
++		break;
++	}
++}
++
++static irqreturn_t fttmr010_clockevent_interrupt(int irq, void *dev_id)
++{
++	struct clock_event_device *ce = dev_id;
++	struct fttmr010_clockevent *fttmr010;
++    unsigned int tmp;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++
++    /* Level Trigger needs this fix */
++	tmp = readl(fttmr010->base + FTTMR010_OFFSET_INTR_STATE);
++	writel(tmp, fttmr010->base + FTTMR010_OFFSET_INTR_STATE);
++
++	ce->event_handler(ce);
++	return IRQ_HANDLED;
++}
++
++void __init fttmr010_clockevent_init(struct fttmr010_clockevent *fttmr010)
++{
++	struct clock_event_device *ce = &fttmr010->clockevent;
++	struct irqaction *action = &fttmr010->irqaction;
++
++	if (!fttmr010->base || fttmr010->id >= 3)
++		BUG();
++
++	/* initialize to a known state */
++	fttmr010_disable(fttmr010->base, fttmr010->id);
++	fttmr010_set_match1(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_match2(fttmr010->base, fttmr010->id, 0);
++
++	/* setup reload value for periodic clockevents */
++	fttmr010->reload	= (fttmr010->freq / HZ) - 1;    /* FIX */
++
++	/* Make irqs happen for the system timer */
++	action->name		= ce->name;
++	action->handler		= fttmr010_clockevent_interrupt;
++	action->flags		= IRQF_DISABLED | IRQF_TIMER;
++	action->dev_id		= ce;
++
++	setup_irq(ce->irq, action);
++
++	/* setup struct clock_event_device */
++	ce->features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
++	ce->shift		= 32;
++	ce->rating		= 200;
++	ce->cpumask		= cpumask_of(0);    //CPU_MASK_ALL,
++
++	ce->mult		= div_sc(fttmr010->freq, NSEC_PER_SEC, ce->shift);
++	ce->max_delta_ns	= clockevent_delta2ns(0xffffffff, ce);
++	ce->min_delta_ns	= clockevent_delta2ns(0xff, ce);
++
++	ce->set_next_event	= fttmr010_set_next_event;
++	ce->set_mode		= fttmr010_set_mode;
++
++	clockevents_register_device(ce);
++}
++
++/******************************************************************************
++ * clocksource functions
++ *****************************************************************************/
++
++/*
++ * We support only one instance now.
++ *
++ * After 2.6.30, clocksource->read() has a parameter, and we can use it with
++ * container_of() to get the private data for each instance.
++ */
++static cycle_t fttmr010_clocksource_read(struct clocksource *cs)
++{
++    struct fttmr010_clocksource *fttmr010;
++	cycle_t counter;
++
++    fttmr010 = container_of(cs, struct fttmr010_clocksource, clocksource);
++	counter = fttmr010_get_counter(fttmr010->base, fttmr010->id);
++	return ~counter;
++}
++
++void __init fttmr010_clocksource_init(struct fttmr010_clocksource *fttmr010)
++{
++	struct clocksource *cs = &fttmr010->clocksource;
++
++	if (!fttmr010->base || fttmr010->id >= 3)
++		BUG();
++
++	cs->rating	= 300;
++	cs->read	= fttmr010_clocksource_read;
++	cs->mask	= CLOCKSOURCE_MASK(32);
++	cs->shift	= 20;
++	cs->flags	= CLOCK_SOURCE_IS_CONTINUOUS;
++	cs->mult	= clocksource_hz2mult(fttmr010->freq, cs->shift);
++
++	/* setup as free-running clocksource */
++	fttmr010_disable(fttmr010->base, fttmr010->id);
++	fttmr010_set_match1(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_match2(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_reload(fttmr010->base, fttmr010->id, 0xffffffff);
++	fttmr010_set_counter(fttmr010->base, fttmr010->id, 0xffffffff);
++	fttmr010_enable_noirq(fttmr010->base, fttmr010->id);
++
++	clocksource_register(cs);
++
++    if (1) {
++        extern int gm_jiffies_init(void *);
++	    gm_jiffies_init((void *)fttmr010);
++	}
++}
++
++
+diff --git a/arch/arm/mach-GM-SMP/gm_jiffies.c b/arch/arm/mach-GM-SMP/gm_jiffies.c
+new file mode 100644
+index 00000000..f0962b36
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/gm_jiffies.c
+@@ -0,0 +1,141 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <linux/proc_fs.h>
++#include <linux/timer.h>
++#include <mach/fttmr010.h>
++#include <mach/gm_jiffies.h>
++
++/*
++ * Macro definitions
++ */
++#define HEART_BEAT_INTVAL   (10 * HZ)
++#define time_disance(a, b)  ((long)(b) - (long)(a))
++
++/*
++ * Local variables
++ */
++static unsigned long __gm_jiffies = 0;  /* 1ms granularity */
++static u64  __gm_jiffies_u64 = 0;       /* 1ms granularity */
++static unsigned long clk_khz = 0;
++static struct timer_list  gm_jiffies_tmr;
++static spinlock_t spinlock;
++static unsigned int refer_cnt = 0;
++static struct fttmr010_clocksource *pGmClkSrc = NULL;
++static struct proc_dir_entry *gm_jiffies_proc = NULL;
++
++/*
++ * Local functions
++ */
++static int proc_read_gm_jiffies(char *page, char **start, off_t off, int count, int *eof, void *data);
++
++static unsigned int distance = 0;
++
++/* get 1m jiffies */
++unsigned long get_gm_jiffies(void)
++{
++    static unsigned long keep_clk_val = 0;
++    unsigned long flags, new_clk_val;
++
++    if (pGmClkSrc == NULL)
++        return 0;
++
++    /* lock */
++    spin_lock_irqsave(&spinlock, flags);
++    new_clk_val = pGmClkSrc->clocksource.read(&pGmClkSrc->clocksource);
++    if (!keep_clk_val && !new_clk_val) {  /* not start yet */
++        spin_unlock_irqrestore(&spinlock, flags);
++        return 0;
++    }
++
++    distance += time_disance(keep_clk_val, new_clk_val);
++    keep_clk_val = new_clk_val;
++
++    if (distance >= clk_khz) {
++        unsigned long value = distance / clk_khz;
++
++        __gm_jiffies += value;
++        __gm_jiffies_u64 += value;
++        distance = distance % clk_khz;
++    }
++
++    /* unlock */
++    spin_unlock_irqrestore(&spinlock, flags);
++
++    refer_cnt ++;
++
++    return __gm_jiffies;
++}
++EXPORT_SYMBOL(get_gm_jiffies);
++
++/* get 1m jiffies */
++u64 get_gm_jiffies_u64(void)
++{
++    get_gm_jiffies();
++
++    return __gm_jiffies_u64;
++}
++EXPORT_SYMBOL(get_gm_jiffies_u64);
++
++/*
++ * A function to update __gm_jiffies periodically if there is no caller to call get_gm_jiffies()
++ *   in a long interval.
++ */
++void gm_heatbeat_handler(unsigned long data)
++{
++    struct fttmr010_clocksource *pGmClkSrc = (struct fttmr010_clocksource *)data;
++
++
++    /* in order to prevent __gm_jiffies not update in a long time */
++    get_gm_jiffies();
++
++    gm_jiffies_tmr.function = gm_heatbeat_handler;
++    gm_jiffies_tmr.data = (unsigned long)pGmClkSrc;
++    mod_timer(&gm_jiffies_tmr, jiffies + HEART_BEAT_INTVAL);
++
++    if (gm_jiffies_proc == NULL) {
++        gm_jiffies_proc = create_proc_entry("gm_jiffies", S_IRUGO, NULL);
++        if (gm_jiffies_proc == NULL)
++            panic("%s, error in create proc! \n", __func__);
++
++        gm_jiffies_proc->read_proc = (read_proc_t *) proc_read_gm_jiffies;
++        gm_jiffies_proc->write_proc = NULL;
++    }
++}
++
++int __init gm_jiffies_init(void *data)
++{
++    pGmClkSrc = (struct fttmr010_clocksource *)data;
++    if (pGmClkSrc == NULL)
++        panic("%s, data is NULL! \n", __func__);
++
++    clk_khz = pGmClkSrc->freq / 1000;
++
++    /* sanity check */
++    if ((HEART_BEAT_INTVAL / HZ) >= (0xffffffff / pGmClkSrc->freq))
++        panic("%s, HEART_BEAT_INTVAL = %d out of range! \n", __func__, HEART_BEAT_INTVAL / HZ);
++
++    spin_lock_init(&spinlock);
++    init_timer(&gm_jiffies_tmr);
++    gm_jiffies_tmr.function = gm_heatbeat_handler;
++    gm_jiffies_tmr.data = (unsigned long)pGmClkSrc;
++    mod_timer(&gm_jiffies_tmr, jiffies + HZ);
++    printk("%s, system HZ: %d, pClk: %d \n", __func__, HZ, pGmClkSrc->freq);
++
++    return 0;
++}
++
++static int proc_read_gm_jiffies(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    int len = 0;
++
++    len += sprintf(page + len, "gm jiffies: 0x%x, HZ = %d \n", (u32)gm_jiffies, HZ);
++    len += sprintf(page + len, "reference count: 0x%d \n", refer_cnt);
++
++    return len;
++}
++
++MODULE_AUTHOR("Grain Media Corp.");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM-SMP/headsmp.S b/arch/arm/mach-GM-SMP/headsmp.S
+new file mode 100644
+index 00000000..09b2aa91
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/headsmp.S
+@@ -0,0 +1,40 @@
++/*
++ *  linux/arch/arm/mach-realview/headsmp.S
++ *
++ *  Copyright (c) 2003 ARM Limited
++ *  All Rights Reserved
++ *
++ * 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 <linux/linkage.h>
++#include <linux/init.h>
++
++	__INIT
++
++/*
++ * Realview specific entry point for secondary CPUs.  This provides
++ * a "holding pen" into which all secondary cores are held until we're
++ * ready for them to initialise.
++ */
++ENTRY(platform_secondary_startup)
++	mrc	p15, 0, r0, c0, c0, 5
++	and	r0, r0, #15
++	adr	r4, 1f
++	ldmia	r4, {r5, r6}
++	sub	r4, r4, r5
++	add	r6, r6, r4
++pen:	ldr	r7, [r6]
++	cmp	r7, r0
++	bne	pen
++
++	/*
++	 * we've been released from the holding pen: secondary_stack
++	 * should now contain the SVC stack for this core
++	 */
++	b	secondary_startup
++
++1:	.long	.
++	.long	pen_release
++ENDPROC(platform_secondary_startup)
+diff --git a/arch/arm/mach-GM-SMP/hotplug.c b/arch/arm/mach-GM-SMP/hotplug.c
+new file mode 100644
+index 00000000..e0262d75
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/hotplug.c
+@@ -0,0 +1,128 @@
++/*
++ *  linux/arch/arm/mach-realview/hotplug.c
++ *
++ *  Copyright (C) 2002 ARM Ltd.
++ *  All Rights Reserved
++ *
++ * 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 <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/smp.h>
++
++#include <asm/cacheflush.h>
++#include <asm/smp_plat.h>
++
++extern volatile int pen_release;
++
++static inline void cpu_enter_lowpower(void)
++{
++	unsigned int v;
++
++	flush_cache_all();
++	asm volatile(
++	"	mcr	p15, 0, %1, c7, c5, 0\n"
++	"	mcr	p15, 0, %1, c7, c10, 4\n"
++	/*
++	 * Turn off coherency
++	 */
++	"	mrc	p15, 0, %0, c1, c0, 1\n"
++	"	bic	%0, %0, #0x20\n"
++	"	mcr	p15, 0, %0, c1, c0, 1\n"
++	"	mrc	p15, 0, %0, c1, c0, 0\n"
++	"	bic	%0, %0, %2\n"
++	"	mcr	p15, 0, %0, c1, c0, 0\n"
++	  : "=&r" (v)
++	  : "r" (0), "Ir" (CR_C)
++	  : "cc");
++}
++
++static inline void cpu_leave_lowpower(void)
++{
++	unsigned int v;
++
++	asm volatile(	"mrc	p15, 0, %0, c1, c0, 0\n"
++	"	orr	%0, %0, %1\n"
++	"	mcr	p15, 0, %0, c1, c0, 0\n"
++	"	mrc	p15, 0, %0, c1, c0, 1\n"
++	"	orr	%0, %0, #0x20\n"
++	"	mcr	p15, 0, %0, c1, c0, 1\n"
++	  : "=&r" (v)
++	  : "Ir" (CR_C)
++	  : "cc");
++}
++
++static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
++{
++	/*
++	 * there is no power-control hardware on this platform, so all
++	 * we can do is put the core into WFI; this is safe as the calling
++	 * code will have already disabled interrupts
++	 */
++	for (;;) {
++		/*
++		 * here's the WFI
++		 */
++		asm(".word	0xe320f003\n"
++		    :
++		    :
++		    : "memory", "cc");
++
++		if (pen_release == cpu_logical_map(cpu)) {
++			/*
++			 * OK, proper wakeup, we're done
++			 */
++			break;
++		}
++
++		/*
++		 * Getting here, means that we have come out of WFI without
++		 * having been woken up - this shouldn't happen
++		 *
++		 * Just note it happening - when we're woken, we can report
++		 * its occurrence.
++		 */
++		(*spurious)++;
++	}
++}
++
++int platform_cpu_kill(unsigned int cpu)
++{
++	return 1;
++}
++
++/*
++ * platform-specific code to shutdown a CPU
++ *
++ * Called with IRQs disabled
++ */
++void __ref platform_cpu_die(unsigned int cpu)
++{
++	int spurious = 0;
++
++	/*
++	 * we're ready for shutdown now, so do it
++	 */
++	cpu_enter_lowpower();
++	platform_do_lowpower(cpu, &spurious);
++
++	/*
++	 * bring this CPU back into the world of cache
++	 * coherency, and then restore interrupts
++	 */
++	cpu_leave_lowpower();
++
++	if (spurious)
++		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
++}
++
++int platform_cpu_disable(unsigned int cpu)
++{
++	/*
++	 * we don't allow CPU 0 to be shutdown (it is still too special
++	 * e.g. clock tick interrupts)
++	 */
++	return cpu == 0 ? -EPERM : 0;
++}
+diff --git a/arch/arm/mach-GM-SMP/include/mach/debug-macro.S b/arch/arm/mach-GM-SMP/include/mach/debug-macro.S
+new file mode 100644
+index 00000000..aadb8d57
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/debug-macro.S
+@@ -0,0 +1,44 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/debug-macro.S
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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 <linux/linkage.h>
++#include <mach/hardware.h>
++#include <mach/serial.h>
++
++		.macro	addruart, rp, rv, tmp
++		ldr	\rp, =DEBUG_LL_FTUART010_PA_BASE	@ physical base address of UART
++		ldr	\rv, =DEBUG_LL_FTUART010_VA_BASE	@ virtual base address of UART
++		.endm
++
++		.macro	senduart, rd, rx
++		strb	\rd, [\rx, #SERIAL_THR]
++		.endm
++
++		.macro	waituart, rd, rx
++1001:		ldrb	\rd, [\rx, #SERIAL_LSR]	@ LSR
++		tst	\rd, #SERIAL_LSR_THRE	@ test empty
++		beq	1001b
++		.endm
++
++		.macro	busyuart, rd, rx
++		mov	\rd, #0x100
++1010:		subs	\rd, \rd, #1
++		bne	1010b
++		.endm
+diff --git a/arch/arm/mach-GM-SMP/include/mach/dma_gm.h b/arch/arm/mach-GM-SMP/include/mach/dma_gm.h
+new file mode 100644
+index 00000000..0f1f707b
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/dma_gm.h
+@@ -0,0 +1,33 @@
++#ifndef __DMA_GM_H
++#define __DMA_GM_H
++
++enum dma_kind {
++	APB_DMA,
++	AHB_DMA,
++	AXI_DMA,
++};
++
++/** 
++* @brief memory copy used by DMA
++* 
++* @style: choose DMA style (APB, AHB, AXI)
++* @dest: DMA memory copy's destination address
++* @src: DMA memory copy's source address 
++* @len: DMA memory copy's memory length 
++* 
++* @return 0: success, other: failed 
++*/
++int dma_memcpy(enum dma_kind style, dma_addr_t dest, dma_addr_t src, size_t len);
++
++/** 
++* @brief memory set used by DMA
++* 
++* @style: choose DMA style (APB, AHB, AXI)
++* @dest: DMA memory set's destination address
++* @value: DMA memory set's value
++* @len: DMA memory set's memory length 
++* 
++* @return 0: success, other: failed 
++*/
++int dma_memset(enum dma_kind style, dma_addr_t dest, int value, size_t len);
++#endif /* __DMA_GM_H */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/entry-macro.S b/arch/arm/mach-GM-SMP/include/mach/entry-macro.S
+new file mode 100644
+index 00000000..f3e8d129
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/entry-macro.S
+@@ -0,0 +1,306 @@
++/*
++ * arch/arm/mach-GM/include/mach/entry-macro.S
++ *
++ * Faraday Low-level Interrupt Vector Interface Macros
++ *
++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef CONFIG_CPU_FMP626
++
++#include <mach/irqs.h>
++#include <mach/ftintc030.h>
++#include <mach/ftintc010.h>
++
++	.macro	check_status, irqstat, tmp
++	//???
++	stmfd	sp!, {r7}
++	ldr	r7, =ftintc030_base_cpu_0_irq_base
++	ldr	r7, [r7]
++	mov 	r4, \tmp
++	mov	r4, r4, lsr #3				/* >>= 5, then << 2 calc INT offset */
++	ldr	r4, [r7, r4]
++	and	\irqstat, \irqstat, r4
++	ldmfd	sp!, {r7}
++	.endm
++
++	.macro	disable_fiq
++	.endm
++
++	.macro	get_irqnr_preamble, base, tmp
++#ifdef CONFIG_FTINTC030
++	ldr	\base, =ftintc030_base_addr
++#else
++	ldr	\base, =ftintc010_base_addr
++#endif
++	ldr	\base, [\base]
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++#if __LINUX_ARM_ARCH__ >= 5
++	.macro	__get_int_nr_and_base, irqnr, irqstat, tmp
++	clz	\irqnr, \irqstat				/* 32 if no bits are set, and zero if bit 31 is set */
++	rsb	\irqnr, \irqnr, #31			/* irqnr = 31 - irqnr, get irq number */
++	.endm
++#else
++	/*
++	 * An O(1) optimized version for getting IRQ/FIQ number
++	 * 08/29/2005 Luke Lee
++	 * Input/output: irqnr (initial value), irqstat (the word to scan)
++	 * Local R/W:	tmp
++	 */
++	.macro	__get_int_nr_and_base, irqnr, irqstat, tmp
++	mov	\tmp, \irqstat, lsl #16	/* check if lower 16 bits = zero */
++	cmp	\tmp, #0
++	movne	\irqstat, \irqstat, lsl #16	/* irqstat <<= 16 */
++	subne	\irqnr, \irqnr, #16	/* irqnr -= 16 */
++	tst	\irqstat, #0x00FF0000
++	movne	\irqstat, \irqstat, lsl #8	/* irqstat <<= 8 */
++	subne	\irqnr, \irqnr, #8	/* irqnr -= 8 */
++	tst	\irqstat, #0x0F000000
++	movne	\irqstat, \irqstat, lsl #4	/* irqstat <<= 4 */
++	subne	\irqnr, \irqnr, #4	/* irqnr -= 4 */
++	tst	\irqstat, #0x30000000
++	movne	\irqstat, \irqstat, lsl #2	/* irqstat <<= 2 */
++	subne	\irqnr, \irqnr, #2	/* irqnr -= 2 */
++	tst	\irqstat, #0x40000000
++	subne	\irqnr, \irqnr, #1	/* irqnr -= 1 */
++	.endm
++#endif
++
++#ifdef CONFIG_FTINTC010EX
++	/*
++	 * Get EXTEND IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp, base, offset
++   * 					base: irq IP base address
++   * 					offset: register offset
++	 */
++	.macro	__get_ex_nr, irqnr, irqstat, tmp, base, offset
++	ldr	\irqstat, [\base, \offset]
++	cmp	\irqstat, #0
++	beq	15f
++	mov	\irqnr, #31
++
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++
++	add	\irqnr, \irqnr, #32
++	cmp	\irqnr, #NR_IRQS
++15:
++	.endm	/* get_ex_nr */
++#endif
++
++#ifdef CONFIG_FTINTC030
++	/*
++	 * Get SPI INTC030 IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp, base, r5
++   * 					irqstat: spi status
++   * 					tmp: register offset
++   * 					base: irq IP base address
++   * 					offset: register offset
++   * 					r3: irq number base
++	 */
++	.macro	__get_spi_nr, irqnr, irqstat, tmp, base, offset, mode
++	ldr	\irqstat, [\base, \offset]	/* read IRQ status, irq group 1 */
++
++	add \base, \base, #0x20
++	mov \tmp, #32
++	mov r3, #32										/* move spi base to 32 */
++//	???
++	check_status \irqstat, r3
++	cmp	\irqstat, #0
++	beq	7f
++
++	mov	\irqnr, #31								/* irq between this range */
++6:
++	sub \base, \base, \tmp
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++
++	add	\irqnr, \irqnr, r3					/* add irq base and return value */
++	cmp	r3, #(NR_IRQS - 32)
++	b 9f
++7:
++	cmp	r3, #(NR_IRQS - 32)				/* check irq overflow */
++	bge	9f
++	add \tmp, \tmp, #0x20					/* shift to next register offset */
++	add \base, \base, #0x20
++	ldr	\irqstat, [\base, \offset]	/* read IRQ status, irq group 2~14 */
++	add	r3, r3, #32								/* add IRQ number base */
++//	???
++	check_status \irqstat, r3
++	cmp	\irqstat, #0
++	beq	7b
++	b 6b
++9:
++
++	.endm	/* get_spi_nr */
++#endif
++
++	/*
++	 * Get IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp
++	 */
++	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++
++	mov	\irqnr, #0
++#ifdef CONFIG_FTINTC030
++	ldr	\irqstat, [\base, #FTINTC030_OFFSET_IRQPEND]	/* irq group 0 */
++
++	check_status \irqstat, \irqnr
++//???
++#else
++	ldr	\irqstat, [\base, #FTINTC010_OFFSET_IRQSTATUS]/* irq group 0 */
++#endif
++
++	cmp	\irqstat, #0
++	beq	3f
++
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++	cmp	\irqnr, #NR_IRQS
++#if (defined(CONFIG_FTINTC010EX) || defined(CONFIG_FTINTC030))
++	b	5f
++#endif
++3:
++#ifdef CONFIG_FTINTC010EX
++	__get_ex_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC010_OFFSET_IRQSTATUSEX	/* irq group 1 */
++5:
++#endif
++#ifdef CONFIG_FTINTC030
++	__get_spi_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC030_OFFSET_IRQPEND1	, #0	/* irq group 1~14 */
++	cmp \irqnr, #0
++5:
++#endif
++	.endm	/* get_irqnr_and_base */
++
++#ifdef CONFIG_FIQ
++    /*
++    * Get FIQ number and base
++	* Input: none
++	* Output: irqnr, Z flag
++	* Local R/W: irqstat, base, tmp
++	*/
++	.macro get_fiqnr_and_base, irqnr, irqstat, base, tmp
++#ifdef CONFIG_FTINTC030
++	ldr \irqstat, [\base, #FTINTC030_OFFSET_IRQPEND]		/* fiq group 0 */
++#else
++	ldr \irqstat, [\base, #FTINTC010_OFFSET_FIQSTATUS]	/* fiq group 0 */
++#endif
++	cmp	\irqstat, #0
++	beq	2003f
++	mov	\irqnr, #0
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++	cmp	\irqnr, #NR_IRQS
++#if (defined(CONFIG_FTINTC010EX) || defined(CONFIG_FTINTC030))
++    b   2005f
++#endif
++2003:
++#ifdef CONFIG_FTINTC010EX
++	__get_ex_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC010_OFFSET_FIQSTATUSEX	/* fiq group 1 */
++2005:
++#endif
++#ifdef CONFIG_FTINTC030
++	__get_spi_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC030_OFFSET_IRQPEND1, #1		/* fiq group 1~14 */
++2005:
++#endif
++    .endm	/* get_fiqnr_and_base */
++
++#endif /* CONFIG_FIQ */
++
++
++#else	/* CONFIG_CPU_FMP626 */
++
++#include <mach/hardware.h>
++#include <asm/hardware/gic.h>
++
++	.macro	disable_fiq
++	.endm
++
++	.macro	get_irqnr_preamble, base, tmp
++	ldr	\base, =gic_cpu_base_addr
++	ldr	\base, [\base]
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++	/*
++	 * The interrupt numbering scheme is defined in the
++	 * interrupt controller spec.  To wit:
++	 *
++	 * Interrupts 0-15 are IPI
++	 * 16-28 are reserved
++	 * 29-31 are local.  We allow 30 to be used for the watchdog.
++	 * 32-1020 are global
++	 * 1021-1022 are reserved
++	 * 1023 is "spurious" (no interrupt)
++	 *
++	 * For now, we ignore all local interrupts so only return an interrupt if it's
++	 * between 30 and 1020.  The test_for_ipi routine below will pick up on IPIs.
++	 *
++	 * A simple read from the controller will tell us the number of the highest
++	 * priority enabled interrupt.  We then just need to check whether it is in the
++	 * valid range for an IRQ (30-1020 inclusive).
++	 */
++
++	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++
++	ldr	\irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 = src CPU, 9-0 = int # */
++
++	ldr	\tmp, =1021
++
++	bic	\irqnr, \irqstat, #0x1c00
++
++	cmp	\irqnr, #29
++	cmpcc	\irqnr, \irqnr
++	cmpne	\irqnr, \tmp
++	cmpcs	\irqnr, \irqnr
++
++	.endm
++
++	/* We assume that irqstat (the raw value of the IRQ acknowledge
++	 * register) is preserved from the macro above.
++	 * If there is an IPI, we immediately signal end of interrupt on the
++	 * controller, since this requires the original irqstat value which
++	 * we won't easily be able to recreate later.
++	 */
++
++	.macro	test_for_ipi, irqnr, irqstat, base, tmp
++	bic	\irqnr, \irqstat, #0x1c00
++	cmp	\irqnr, #16
++	strcc	\irqstat, [\base, #GIC_CPU_EOI]
++	cmpcs	\irqnr, \irqnr
++	.endm
++
++	/* As above, this assumes that irqstat and base are preserved.. */
++
++	.macro	test_for_ltirq, irqnr, irqstat, base, tmp
++	bic	\irqnr, \irqstat, #0x1c00
++	mov 	\tmp, #0
++	cmp	\irqnr, #29
++	moveq	\tmp, #1
++	streq	\irqstat, [\base, #GIC_CPU_EOI]
++	cmp	\tmp, #0
++	.endm
++
++#endif	/* CONFIG_CPU_FMP626 */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/fmem.h b/arch/arm/mach-GM-SMP/include/mach/fmem.h
+new file mode 100644
+index 00000000..b4e4debc
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/fmem.h
+@@ -0,0 +1,82 @@
++#ifndef __FMEM_H
++#define __FMEM_H
++#include <linux/mm.h>
++#include <asm/io.h>
++#include <asm/setup.h>
++#include <linux/list.h>
++#include <linux/dma-direction.h>
++
++#define MAX_DDR_CHUNKS 2   /* include system memory */
++
++typedef struct g_page_info_s
++{
++    int         nr_node;        /* number of active DDRs */
++    int         block_sz;       /* page allocation size once */
++    int         node_sz[MAX_DDR_CHUNKS];    /* the size for the DDR node */
++    dma_addr_t  phy_start[MAX_DDR_CHUNKS];  /* the min physical start */
++    struct list_head list[MAX_DDR_CHUNKS];  /* page node list */
++} g_page_info_t;
++
++/* page node for each pages allocation */
++typedef struct {
++    struct page     *page;
++    dma_addr_t      phy_start;
++    unsigned int    size;   /* the real size */
++    int             ddr_id; /* belong to which DDR */
++    struct list_head list;
++} page_node_t;
++
++void fmem_get_pageinfo(g_page_info_t **data_ptr);
++int  fmem_give_pages(int node_id, unsigned int give_sz);
++void fmem_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi);
++
++void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle);
++void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id);
++
++/**
++ * @brief to resolve the virtual address (including direct mapping, ioremap or user space address to
++ *      its real physical address.
++ *
++ * @parm vaddr indicates any virtual address
++ *
++ * @return  >= 0 for success, 0xFFFFFFFF for fail
++ */
++phys_addr_t fmem_lookup_pa(unsigned int vaddr);
++
++/*
++ *  * @This function is used to read CPU id and pci id
++ *   * @Return value: 0 for success, -1 for fail
++ *    */
++typedef enum {
++    FMEM_CPU_FA726 = 0,
++    FMEM_CPU_FA626,
++    FMEM_CPU_UNKNOWN,
++} fmem_cpu_id_t;
++
++typedef enum {
++    FMEM_PCI_HOST = 0,
++    FMEM_PCI_DEV0,
++} fmem_pci_id_t;
++
++int fmem_get_identifier(fmem_pci_id_t *pci_id, fmem_cpu_id_t *cpu_id);
++
++/* @this function is a data cache operation function,
++ * @parm: vaddr: any virtual address
++ * @parm: dir will be:
++ * DMA_BIDIRECTIONAL = 0, it means flush operation.
++ * DMA_TO_DEVICE = 1, it means clean operation.
++ * DMA_FROM_DEVICE = 2, it means invalidate operation.
++ * DMA_NONE = 3,
++ */
++void fmem_dcache_sync(void *vaddr, u32 len, enum dma_data_direction dir);
++
++/* The following functions are only valid in GM8210 and adopted by videgraph.
++ */
++int fmem_set_ep_outbound_win(u32 phy_addr, u32 size);
++u32 fmem_get_pcie_addr(u32 axi_phy_addr);
++u32 fmem_get_axi_addr(u32 pcie_phy_addr);
++
++#endif /* __FMEM_H */
++
++
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/ftapbb020.h b/arch/arm/mach-GM-SMP/include/mach/ftapbb020.h
+new file mode 100644
+index 00000000..79570039
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/ftapbb020.h
+@@ -0,0 +1,138 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftapbb020.h
++ *
++ *  Faraday FTAPBB020 APB Bridge with DMA function
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTAPBB020_H
++#define __FTAPBB020_H
++
++#define FTAPBB020_OFFSET_BSR(x)		((x) * 0x4)		/* BSR of slave x */
++#define FTAPBB020_OFFSET_SAR(x)		(0x80 + (x) * 0x10)	/* src addr of channel x */
++#define FTAPBB020_OFFSET_DAR(x)		(0x84 + (x) * 0x10)	/* dst addr of channel x */
++#define FTAPBB020_OFFSET_CYC(x)		(0x88 + (x) * 0x10)	/* cycles of channel x */
++#define FTAPBB020_OFFSET_CMD(x)		(0x8c + (x) * 0x10)	/* command of channel x */
++#define FTAPBB020_OFFSET_CR		0xc0
++#define FTAPBB020_OFFSET_SR		0xc4
++#define FTAPBB020_OFFSET_REV		0xc8
++
++/*
++ * Base/size of each slave
++ */
++#define FTAPBB020_BSR_SIZE_1M		(0 << 16)
++#define FTAPBB020_BSR_SIZE_2M		(1 << 16)
++#define FTAPBB020_BSR_SIZE_4M		(2 << 16)
++#define FTAPBB020_BSR_SIZE_8M		(3 << 16)
++#define FTAPBB020_BSR_SIZE_16M		(4 << 16)
++#define FTAPBB020_BSR_SIZE_32M		(5 << 16)
++#define FTAPBB020_BSR_SIZE_64M		(6 << 16)
++#define FTAPBB020_BSR_SIZE_128M		(7 << 16)
++#define FTAPBB020_BSR_SIZE_256M		(8 << 16)
++#define FTAPBB020_BSR_BASE(x)		((x) & (0x3ff << 20))
++
++/*
++ * Cycle count of each DMA channel
++ */
++#define FTAPBB020_CYC_MASK		0x00ffffff
++
++/*
++ * Command of each DMA channel
++ */
++#define FTAPBB020_CMD_ENABLE		(1 << 0)
++#define FTAPBB020_CMD_FININT_S		(1 << 1)
++#define FTAPBB020_CMD_FININT_E		(1 << 2)
++#define FTAPBB020_CMD_BURST		(1 << 3)
++#define FTAPBB020_CMD_ERRINT_S		(1 << 4)
++#define FTAPBB020_CMD_ERRINT_E		(1 << 5)
++#define FTAPBB020_CMD_SRC_TYPE_AHB	(1 << 6)
++#define FTAPBB020_CMD_DST_TYPE_AHB	(1 << 7)
++#define FTAPBB020_CMD_SRC_MODE_FIXED	(0 << 8)
++#define FTAPBB020_CMD_SRC_MODE_BYTE_INC	(1 << 8)
++#define FTAPBB020_CMD_SRC_MODE_HALF_INC	(2 << 8)
++#define FTAPBB020_CMD_SRC_MODE_WORD_INC	(3 << 8)
++#define FTAPBB020_CMD_SRC_MODE_BYTE_DEC	(5 << 8)
++#define FTAPBB020_CMD_SRC_MODE_HALF_DEC	(6 << 8)
++#define FTAPBB020_CMD_SRC_MODE_WORD_DEC	(7 << 8)
++#define FTAPBB020_CMD_DST_MODE_FIXED	(0 << 12)
++#define FTAPBB020_CMD_DST_MODE_BYTE_INC	(1 << 12)
++#define FTAPBB020_CMD_DST_MODE_HALF_INC	(2 << 12)
++#define FTAPBB020_CMD_DST_MODE_WORD_INC	(3 << 12)
++#define FTAPBB020_CMD_DST_MODE_BYTE_DEC	(5 << 12)
++#define FTAPBB020_CMD_DST_MODE_HALF_DEC	(6 << 12)
++#define FTAPBB020_CMD_DST_MODE_WORD_DEC	(7 << 12)
++#define FTAPBB020_CMD_DST_HANDSHAKE(x)	(((x) & 0xf) << 16)	/* destination handshake channel */
++#define FTAPBB020_CMD_WIDTH_WORD	(0 << 20)
++#define FTAPBB020_CMD_WIDTH_HALF	(1 << 20)
++#define FTAPBB020_CMD_WIDTH_BYTE	(2 << 20)
++#define FTAPBB020_CMD_SRC_HANDSHAKE(x)	(((x) & 0xf) << 24)	/* source handshake channel */
++
++/*
++ * Control register
++ */
++#define FTAPBB020_CR_BUF_NORMAL		(0 << 0)
++#define FTAPBB020_CR_BUF_ALWAYS		(1 << 0)
++#define FTAPBB020_CR_BUF_NEVER		(2 << 0)
++#define FTAPBB020_CR_BWERRINT_E		(1 << 2)
++
++/*
++ * Status register
++ */
++#define FTAPBB020_SR_BWERRINT		(1 << 0)
++
++/*
++ * Revision register
++ */
++#define FTAPBB020_REV_REVISION(rev)	((rev) & ~(0xff << 24))
++
++enum ftapbb020_bus_type {
++	FTAPBB020_BUS_TYPE_AHB,
++	FTAPBB020_BUS_TYPE_APB,
++};
++
++enum ftapbb020_channels {
++	FTAPBB020_CHANNEL_0 = (1 << 0),
++	FTAPBB020_CHANNEL_1 = (1 << 1),
++	FTAPBB020_CHANNEL_2 = (1 << 2),
++	FTAPBB020_CHANNEL_3 = (1 << 3),
++	FTAPBB020_CHANNEL_ALL = 0xf,
++};
++
++/**
++ * struct ftapbb020_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @type: bus type of the device
++ * @channels: bitmap of usable DMA channels
++ * @handshake: hardware handshake number
++ */
++struct ftapbb020_dma_slave {
++	struct dma_slave_config common;
++	enum ftapbb020_bus_type type;
++//	enum ftapbb020_channels channels;
++	unsigned int handshake;
++};
++
++/**
++ * ftapbb020_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftapbb020_dma_slave
++ */
++bool ftapbb020_chan_filter(struct dma_chan *chan, void *data);
++
++#endif	/* __FTAPBB020_H */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/ftdmac020.h b/arch/arm/mach-GM-SMP/include/mach/ftdmac020.h
+new file mode 100644
+index 00000000..6a4a9bd2
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/ftdmac020.h
+@@ -0,0 +1,236 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftdmac020.h
++ *
++ *  Faraday FTDMAC020 DMA controller
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTDMAC020_H
++#define __FTDMAC020_H
++
++#include <linux/dmaengine.h>
++
++#define FTDMAC020_OFFSET_ISR		0x0
++#define FTDMAC020_OFFSET_TCISR		0x4
++#define FTDMAC020_OFFSET_TCICR		0x8
++#define FTDMAC020_OFFSET_EAISR		0xc
++#define FTDMAC020_OFFSET_EAICR		0x10
++#define FTDMAC020_OFFSET_TCRAW		0x14
++#define FTDMAC020_OFFSET_EARAW		0x18
++#define FTDMAC020_OFFSET_CH_ENABLED	0x1c
++#define FTDMAC020_OFFSET_CH_BUSY	0x20
++#define FTDMAC020_OFFSET_CR		    0x24
++#define FTDMAC020_OFFSET_SYNC		0x28
++#define FTDMAC020_OFFSET_REVISION	0x2c
++#define FTDMAC020_OFFSET_FEATURE	0x30
++
++#define FTDMAC020_OFFSET_CCR_CH(x)	(0x100 + (x) * 0x20)
++#define FTDMAC020_OFFSET_CFG_CH(x)	(0x104 + (x) * 0x20)
++#define FTDMAC020_OFFSET_SRC_CH(x)	(0x108 + (x) * 0x20)
++#define FTDMAC020_OFFSET_DST_CH(x)	(0x10c + (x) * 0x20)
++#define FTDMAC020_OFFSET_LLP_CH(x)	(0x110 + (x) * 0x20)
++#define FTDMAC020_OFFSET_CYC_CH(x)	(0x114 + (x) * 0x20)
++
++/*
++ * Error/abort interrupt status/clear register
++ * Error/abort status register
++ */
++#define FTDMAC020_EA_ERR_CH(x)		(1 << (x))
++#define FTDMAC020_EA_ABT_CH(x)		(1 << ((x) + 16))
++
++/*
++ * Main configuration status register
++ */
++#define FTDMAC020_CR_ENABLE		(1 << 0)
++#define FTDMAC020_CR_M0_BE		(1 << 1)	/* master 0 big endian */
++#define FTDMAC020_CR_M1_BE		(1 << 2)	/* master 1 big endian */
++
++/*
++ * Channel control register
++ */
++#define FTDMAC020_CCR_ENABLE		(1 << 0)
++#define FTDMAC020_CCR_DST_M1		(1 << 1)
++#define FTDMAC020_CCR_SRC_M1		(1 << 2)
++#define FTDMAC020_CCR_DST_INC		(0x0 << 3)
++#define FTDMAC020_CCR_DST_DEC		(0x1 << 3)
++#define FTDMAC020_CCR_DST_FIXED		(0x2 << 3)
++#define FTDMAC020_CCR_SRC_INC		(0x0 << 5)
++#define FTDMAC020_CCR_SRC_DEC		(0x1 << 5)
++#define FTDMAC020_CCR_SRC_FIXED		(0x2 << 5)
++#define FTDMAC020_CCR_HANDSHAKE		(1 << 7)
++#define FTDMAC020_CCR_DST_WIDTH_8	(0x0 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_16	(0x1 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_32	(0x2 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_64	(0x3 << 8)
++#define FTDMAC020_CCR_SRC_WIDTH_8	(0x0 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_16	(0x1 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_32	(0x2 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_64	(0x3 << 11)
++#define FTDMAC020_CCR_ABORT		    (1 << 15)
++#define FTDMAC020_CCR_BURST_1		(0x0 << 16)
++#define FTDMAC020_CCR_BURST_4		(0x1 << 16)
++#define FTDMAC020_CCR_BURST_8		(0x2 << 16)
++#define FTDMAC020_CCR_BURST_16		(0x3 << 16)
++#define FTDMAC020_CCR_BURST_32		(0x4 << 16)
++#define FTDMAC020_CCR_BURST_64		(0x5 << 16)
++#define FTDMAC020_CCR_BURST_128		(0x6 << 16)
++#define FTDMAC020_CCR_BURST_256		(0x7 << 16)
++#define FTDMAC020_CCR_PRIVILEGED	(1 << 19)
++#define FTDMAC020_CCR_BUFFERABLE	(1 << 20)
++#define FTDMAC020_CCR_CACHEABLE		(1 << 21)
++#define FTDMAC020_CCR_PRIO_0		(0x0 << 22)
++#define FTDMAC020_CCR_PRIO_1		(0x1 << 22)
++#define FTDMAC020_CCR_PRIO_2		(0x2 << 22)
++#define FTDMAC020_CCR_PRIO_3		(0x3 << 22)
++#define FTDMAC020_CCR_FIFOTH_1		(0x0 << 24)
++#define FTDMAC020_CCR_FIFOTH_2		(0x1 << 24)
++#define FTDMAC020_CCR_FIFOTH_4		(0x2 << 24)
++#define FTDMAC020_CCR_FIFOTH_8		(0x3 << 24)
++#define FTDMAC020_CCR_FIFOTH_16		(0x4 << 24)
++#define FTDMAC020_CCR_MASK_TC		(1 << 31)
++
++/*
++ * Channel configuration register
++ */
++#define FTDMAC020_CFG_MASK_TCI		(1 << 0)	/* mask tc interrupt */
++#define FTDMAC020_CFG_MASK_EI		(1 << 1)	/* mask error interrupt */
++#define FTDMAC020_CFG_MASK_AI		(1 << 2)	/* mask abort interrupt */
++#define FTDMAC020_CFG_SRC_HANDSHAKE(x)	(((x) & 0xf) << 3)
++#define FTDMAC020_CFG_SRC_HANDSHAKE_EN	(1 << 7)
++#define FTDMAC020_CFG_BUSY		(1 << 8)
++#define FTDMAC020_CFG_DST_HANDSHAKE(x)	(((x) & 0xf) << 9)
++#define FTDMAC020_CFG_DST_HANDSHAKE_EN	(1 << 13)
++#define FTDMAC020_CFG_LLP_CNT(cfg)	(((cfg) >> 16) & 0xf)
++
++/*
++ * Link list descriptor pointer
++ */
++#define FTDMAC020_LLP_M1		(1 << 0)
++#define FTDMAC020_LLP_ADDR(a)		((a) & ~0x3)
++
++/*
++ * Transfer size register
++ */
++#define FTDMAC020_CYC_MASK		0x3fffff
++
++/**
++ * Table 3-1. Address Map for Linked List Descriptor(Base Address: Cn_LLP[31:2])
++ *
++ * struct ftdmac020_lld - hardware link list descriptor.
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the next link list descriptor
++ * @ctrl: control field
++ * @cycle: transfer size
++ *
++ * should be word aligned.
++ */
++struct ftdmac020_lld {
++	dma_addr_t src;     /* SrcAddr */
++	dma_addr_t dst;     /* DstAddr */
++	dma_addr_t next;    /* LLP */
++	unsigned int ctrl;  /* Control */
++	unsigned int cycle; /* Total Size */
++};
++
++#define FTDMAC020_LLD_CTRL_DST_M1	(1 << 16)
++#define FTDMAC020_LLD_CTRL_SRC_M1	(1 << 17)
++#define FTDMAC020_LLD_CTRL_DST_INC	(0x0 << 18)
++#define FTDMAC020_LLD_CTRL_DST_DEC	(0x1 << 18)
++#define FTDMAC020_LLD_CTRL_DST_FIXED	(0x2 << 18)
++#define FTDMAC020_LLD_CTRL_SRC_INC	(0x0 << 20)
++#define FTDMAC020_LLD_CTRL_SRC_DEC	(0x1 << 20)
++#define FTDMAC020_LLD_CTRL_SRC_FIXED	(0x2 << 20)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_8	(0x0 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_16	(0x1 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_32	(0x2 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_64	(0x3 << 22)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_8	(0x0 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_16	(0x1 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_32	(0x2 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_64	(0x3 << 25)
++#define FTDMAC020_LLD_CTRL_MASK_TC	(1 << 28)
++#define FTDMAC020_LLD_CTRL_FIFOTH_1	(0x0 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_2	(0x1 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_4	(0x2 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_8	(0x3 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_16	(0x4 << 29)
++
++#define FTDMAC020_LLD_CYCLE_MASK	0x3fffff
++
++enum ftdmac020_channels {
++	FTDMAC020_CHANNEL_0 = (1 << 0),
++	FTDMAC020_CHANNEL_1 = (1 << 1),
++	FTDMAC020_CHANNEL_2 = (1 << 2),
++	FTDMAC020_CHANNEL_3 = (1 << 3),
++	FTDMAC020_CHANNEL_4 = (1 << 4),
++	FTDMAC020_CHANNEL_5 = (1 << 5),
++	FTDMAC020_CHANNEL_6 = (1 << 6),
++	FTDMAC020_CHANNEL_7 = (1 << 7),
++	FTDMAC020_CHANNEL_ALL = 0xff,
++};
++
++enum ftdmac020_burst {
++    FTDMAC020_BURST_SZ_1 = 0,
++    FTDMAC020_BURST_SZ_4,
++    FTDMAC020_BURST_SZ_8,
++    FTDMAC020_BURST_SZ_16,
++    FTDMAC020_BURST_SZ_32,
++    FTDMAC020_BURST_SZ_64,
++    FTDMAC020_BURST_SZ_128,
++    FTDMAC020_BURST_SZ_256
++};
++
++enum ftdmac020_ahbmaster {
++    FTDMA020_AHBMASTER_0 = 0,
++    FTDMA020_AHBMASTER_1
++};
++
++/**
++ * struct ftdmac020_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @id: specify which ftdmac020 device to use, -1 for wildcard
++ * @handshake: hardware handshake number, -1 to disable handshake mode
++ */
++struct ftdmac020_dma_slave {
++	struct dma_slave_config common;
++	int id;
++	int handshake;      /* handshake number, -1 means disable */
++	enum ftdmac020_burst     src_size;   /* source burst size selection */
++	enum ftdmac020_ahbmaster src_sel;  /* AHB Master selection */
++	enum ftdmac020_ahbmaster dst_sel;  /* AHB Master selection */
++};
++
++/**
++ * ftdmac020_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftdmac020_dma_slave
++ */
++bool ftdmac020_chan_filter(struct dma_chan *chan, void *data);
++
++/**
++ * ftdmac020_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac020_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac020_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id));
++
++#endif	/* __FTDMAC020_H */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/ftintc010.h b/arch/arm/mach-GM-SMP/include/mach/ftintc010.h
+new file mode 100644
+index 00000000..78fa0edf
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/ftintc010.h
+@@ -0,0 +1,83 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftintc010.h
++ *
++ *  Faraday FTINTC010 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef __FTINTC010_H
++#define __FTINTC010_H
++
++#define FTINTC010_OFFSET_IRQSRC		0x00
++#define FTINTC010_OFFSET_IRQMASK	0x04
++#define FTINTC010_OFFSET_IRQCLEAR	0x08
++#define FTINTC010_OFFSET_IRQMODE	0x0c
++#define FTINTC010_OFFSET_IRQLEVEL	0x10
++#define FTINTC010_OFFSET_IRQSTATUS	0x14
++
++#define FTINTC010_OFFSET_FIQSRC		0x20
++#define FTINTC010_OFFSET_FIQMASK	0x24
++#define FTINTC010_OFFSET_FIQCLEAR	0x28
++#define FTINTC010_OFFSET_FIQMODE	0x2c
++#define FTINTC010_OFFSET_FIQLEVEL	0x30
++#define FTINTC010_OFFSET_FIQSTATUS	0x34
++
++#define FTINTC010_OFFSET_IRQSRCEX	0x60
++#define FTINTC010_OFFSET_IRQMASKEX	0x64
++#define FTINTC010_OFFSET_IRQCLEAREX	0x68
++#define FTINTC010_OFFSET_IRQMODEEX	0x6c
++#define FTINTC010_OFFSET_IRQLEVELEX	0x70
++#define FTINTC010_OFFSET_IRQSTATUSEX	0x74
++
++#define FTINTC010_OFFSET_FIQSRCEX		0x80
++#define FTINTC010_OFFSET_FIQMASKEX	    0x84
++#define FTINTC010_OFFSET_FIQCLEAREX	    0x88
++#define FTINTC010_OFFSET_FIQMODEEX	    0x8c
++#define FTINTC010_OFFSET_FIQLEVELEX	    0x90
++#define FTINTC010_OFFSET_FIQSTATUSEX	0x94
++
++#ifndef __ASSEMBLY__
++struct ftintc010_trigger_type {
++	unsigned int irqmode;
++	unsigned int irqlevel;
++	unsigned int fiqmode;
++	unsigned int fiqlevel;
++#ifdef CONFIG_FTINTC010EX
++	unsigned int irqmodeex;
++	unsigned int irqlevelex;
++	unsigned int fiqmodeex;
++	unsigned int fiqlevelex;
++#endif
++};
++
++#include <linux/irq.h>
++
++void __init ftintc010_cascade_irq(unsigned int ftintc010_nr, unsigned int irq);
++
++void __init ftintc010_init(unsigned int ftintc010_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc010_trigger_type *trigger_type);
++/* reconfigure the irq type. Maybe the original is edge trigger, now change to level trigger 
++ * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
++ */
++int ftintc010_set_irq_type(unsigned int irq, unsigned int type);
++			   
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FTINTC010_H */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/ftintc030.h b/arch/arm/mach-GM-SMP/include/mach/ftintc030.h
+new file mode 100644
+index 00000000..56b4437d
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/ftintc030.h
+@@ -0,0 +1,88 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftintc030.h
++ *
++ *  Faraday FTINTC030 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef __FTINTC030_H
++#define __FTINTC030_H
++
++#define FTINTC030_OFFSET_IRQTARGET	FTINTC030_OFFSET_CPU_0_IRQ
++
++#define FTINTC030_OFFSET_IRQSRC		0x00
++#define FTINTC030_OFFSET_IRQENABLE  0x04
++#define FTINTC030_OFFSET_IRQCLEAR	0x08
++#define FTINTC030_OFFSET_IRQMODE	0x0c
++#define FTINTC030_OFFSET_IRQLEVEL	0x10
++#define FTINTC030_OFFSET_IRQPEND	0x14//IRQSTATUS
++#define FTINTC030_OFFSET_IRQPEND1	0x34
++
++
++#define FTINTC030_OFFSET_IRQCONFIG	0x200
++//#define FTINTC030_OFFSET_IRQTARGET	0x420
++
++#define FTINTC030_OFFSET_CPU_0_FIQ	0x420
++#define FTINTC030_OFFSET_CPU_0_IRQ	0x45C
++#define FTINTC030_OFFSET_CPU_1_FIQ	0x498
++#define FTINTC030_OFFSET_CPU_1_IRQ	0x4D4
++#define FTINTC030_OFFSET_CPU_2_FIQ	0x510
++#define FTINTC030_OFFSET_CPU_2_IRQ	0x54C
++#define FTINTC030_OFFSET_CPU_3_FIQ	0x588
++#define FTINTC030_OFFSET_CPU_3_IRQ	0x5C4
++
++#define FTINTC010_OFFSET_FIQCLEAREX	0x88
++
++#ifndef __ASSEMBLY__
++struct ftintc030_trigger_type {
++	unsigned int irqmode[15];
++	unsigned int irqlevel[15];
++	unsigned int fiqmode[15];
++	unsigned int fiqlevel[15];
++};
++
++/* IRQ */
++#define FTINTC030_TARGETIRQ_CPU0   0x1
++#define FTINTC030_TARGETIRQ_CPU1   0x2
++#define FTINTC030_TARGETIRQ_CPU2   0x4
++#define FTINTC030_TARGETIRQ_CPU3   0x8
++/* FIQ */
++#define FTINTC030_TARGETFIQ_CPU0   0x1
++#define FTINTC030_TARGETFIQ_CPU1   0x2
++#define FTINTC030_TARGETFIQ_CPU2   0x4
++#define FTINTC030_TARGETFIQ_CPU3   0x8
++
++void __init ftintc030_cascade_irq(unsigned int ftintc030_nr, unsigned int irq);
++
++void __init ftintc030_init(unsigned int ftintc030_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc030_trigger_type *trigger_type);
++
++/*
++ * Set a highlevel chained flow handler for a given IRQ.
++ * ftintc030_nr: INTC030 index
++ * irq: which irq number is the cascade irq
++ * handler: the handler function of this cascade irq
++ * handler_data: private data of the handler
++ */
++void ftintc030_setup_chain_irq(unsigned int ftintc030_nr, unsigned int irq, void *handler, void *handler_data);
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FTINTC030_H */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/ftpmu010.h b/arch/arm/mach-GM-SMP/include/mach/ftpmu010.h
+new file mode 100644
+index 00000000..45cc016e
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/ftpmu010.h
+@@ -0,0 +1,275 @@
++/*
++ *  arch/arm/mach-GM/include/mach/ftpmu010.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __FTPMU010_H
++#define __FTPMU010_H
++
++#include <mach/platform/pmu.h>
++
++#define PMU010_NAME "ftpmu010"
++#define NAME_SZ     20
++
++
++/*  MACROs for reading clock source
++ */
++#define PLL1_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL1)
++#define PLL2_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL2)
++#define PLL3_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL3)
++#define PLL4_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL4)
++#define PLL5_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL5)
++#define PLL6_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL6)
++#define PLL7_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL7)
++#define AXI_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_AXI)
++#define AXI0_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_AXI0)
++#define AXI1_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_AXI1)
++#define AHB_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_AHB)
++#define APB_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_APB)
++#define APB0_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_APB0)
++#define CPU_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_CPU)
++
++typedef enum {
++    FTPMU_H264E_0 = 0x1,
++    FTPMU_H264D_0,
++    FTPMU_H264E_1,
++    FTPMU_H264D_1,
++    FTPMU_SCALER_0,
++    FTPMU_SCALER_1,
++    FTPMU_3DI_0,
++    FTPMU_3DI_1,
++    FTPMU_LCD_0,
++    FTPMU_LCD_1,
++    FTPMU_LCD_2,
++    FTPMU_CAP_0,
++    FTPMU_CAP_1,
++    FTPMU_CAP_2,
++    FTPMU_CAP_3,
++    FTPMU_ISP_0,
++    FTPMU_ISP_1,
++    FTPMU_AES,
++    FTPMU_MCP100_0,
++    FTPMU_NONE = 0xFFFFF,
++} ftpmu010_midx_t;
++
++typedef struct {
++    ftpmu010_midx_t midx;   /* module idx */
++    int             num;    /* number of clock gate */
++    struct {
++        unsigned int ofs;
++        unsigned int bit_val;    //specify the enable value
++        unsigned int bit_mask;   //specify gating clock bits
++    } reg[3];
++} ftpmu010_gate_clk_t;
++
++/* PMU init function
++ * Input parameters: virtual address of PMU
++ *  tbl: clock gating table for IPs
++ *  pmu_handler: the callback from pmu to reload/reconfigure pmu. NULL if unecessary
++ * Return: 0 for success, < 0 for fail
++ */
++int ftpmu010_init(void __iomem  *base, ftpmu010_gate_clk_t *tbl, void *pmu_handler);
++
++typedef enum
++{
++    ATTR_TYPE_NONE = 0,
++    ATTR_TYPE_PLL1,
++    ATTR_TYPE_PLL2,
++    ATTR_TYPE_PLL3,
++    ATTR_TYPE_PLL4,
++    ATTR_TYPE_PLL5,
++    ATTR_TYPE_PLL6,
++    ATTR_TYPE_PLL7,
++    ATTR_TYPE_AXI,
++    ATTR_TYPE_AHB,
++    ATTR_TYPE_APB,
++    ATTR_TYPE_APB0,
++    ATTR_TYPE_CPU,
++    ATTR_TYPE_PMUVER,
++    ATTR_TYPE_CHIPVER,
++    ATTR_TYPE_EPCNT,
++    ATTR_TYPE_CPUENUM,  //for: 0 for RC_FA726, 1: RC_FA626, 2: RC_fC7500......
++    ATTR_TYPE_AXI0,
++    ATTR_TYPE_AXI1,
++    ATTR_TYPE_IDPIN,
++} ATTR_TYPE_T;
++
++/* cpu enumerator in whole system */
++typedef enum {
++    CPU_RC_FA726    = 0,
++    CPU_RC_FA626    = 1,
++    CPU_RC_FC7500   = 2,
++    CPU_EP0_FA726   = 3,
++    CPU_EP0_FA626   = 4,
++    CPU_EP0_FC7500  = 5,
++} attr_cpu_enum_t;
++
++typedef enum {
++    PMUVER_A = 0,
++    PMUVER_B,
++    PMUVER_C,
++    PMUVER_D,
++    PMUVER_UNKNOWN,
++} pmuver_t;
++
++typedef struct
++{
++    char          name[NAME_SZ+1];    /* hclk, .... */
++    ATTR_TYPE_T   attr_type;
++    unsigned int  value;
++} attrInfo_t;
++
++/* register attribute
++ */
++int ftpmu010_register_attr(attrInfo_t *attr);
++int ftpmu010_deregister_attr(attrInfo_t *attr);
++/* get attribute value
++ * return value: 0 for fail, > 0 for success
++ */
++unsigned int ftpmu010_get_attr(ATTR_TYPE_T attr);
++
++
++/*
++ * Structure for pinMux
++ */
++typedef struct
++{
++    unsigned int  reg_off;    /* register offset from PMU base */
++    unsigned int  bits_mask;  /* bits this module covers */
++    unsigned int  lock_bits;  /* bits this module locked */
++    unsigned int  init_val;   /* initial value */
++    unsigned int  init_mask;  /* initial mask */
++} pmuReg_t;
++
++typedef struct
++{
++    char        name[NAME_SZ+1];    /* module name length */
++    int         num;                /* number of register entries */
++    ATTR_TYPE_T clock_src;          /* which clock this module uses */
++    pmuReg_t    *pRegArray;         /* register array */
++} pmuRegInfo_t;
++
++/* register/de-register the register table
++ * return value:
++ *  give an unique fd if return value >= 0, otherwise < 0 if fail.
++ */
++int ftpmu010_register_reg(pmuRegInfo_t *info);
++int ftpmu010_deregister_reg(int fd);
++
++/* lock/unlock/replace the bits in lock_bits field
++ * return value:
++ *  0 for success, < 0 for fail
++ */
++int ftpmu010_add_lockbits(int fd, unsigned int reg_off, unsigned int lock_bits);
++int ftpmu010_del_lockbits(int fd, unsigned int reg_off, unsigned int unlock_bits);
++int ftpmu010_update_lockbits(int fd, unsigned int reg_off, unsigned int new_lock_bits);
++/* @int ftpmu010_bits_is_locked(int reg_off, unsigned int bits)
++ * @Purpose: This function is used to check if the bits are locked by any module or not.
++ * @Parameter:
++ *   reg_off: register offset
++ *   bits: the checked bits
++ * @Return:
++ *      If the any bit in bits is locked, then the returned value will be 0
++ *      otherwise, -1 is returned to indicates all bits are available.
++ *
++ */
++int ftpmu010_bits_is_locked(int fd, unsigned int reg_off, unsigned int bits);
++
++/* PMU register read/write
++ */
++unsigned int ftpmu010_read_reg(unsigned int reg_off);
++/* return value < 0 for fail */
++int ftpmu010_write_reg(int fd, unsigned int reg_off, unsigned int val, unsigned int mask);
++
++/* Purpose: calculate the divisor by input clock
++ * Input: fd, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor(int fd, unsigned int in_clock, int near);
++
++/* Purpose: calculate the divisor by input clock attribute
++ * Input: clock_src, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor2(ATTR_TYPE_T clock_src, unsigned int in_clock, int near);
++
++/* @Purpose: request the pmu PINs
++ * @Parameter:
++ *      fd: unique identifier
++ *      reg_off: register offset
++ *      req_bits: request registers
++ *      b_wait: 1 for blocking until the resource is available
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_request_pins(int fd, unsigned int reg_off, unsigned int req_bits, int b_wait);
++
++
++/* Purpose: release the pmu PINs
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_release_pins(int fd, unsigned int reg_off, unsigned int req_bits);
++
++/* Purpose: check if the PINs was requested by others except myself.
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: those pins occupied by others. zero indicates the pin are available.
++ */
++unsigned int ftpmu010_pins_is_requested(int fd, unsigned int reg_off, unsigned int req_bits);
++/*
++ * The following is used for specific functionality to PMU
++ */
++#define FUNC_TYPE_RELOAD_ATTR   0
++#define FUNC_TYPE_INTR_CLR      1
++#define FUNC_TYPE_INTR_FIRE     2
++
++/*
++ * The following function are used for module to send/clear interrupt.
++ * return: 0 for success, -1 for fail
++ */
++/* send interrupt from pmu */
++static inline int ftpmu010_trigger_intr(int irq)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_INTR_FIRE , irq, 0);
++}
++/* clear interupt in pmu */
++static inline int ftpmu010_clear_intr(int irq)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_INTR_CLR , irq, 0);
++}
++/* force the attribute refresh again */
++static inline int ftpmu010_reload_attr(ATTR_TYPE_T attr_type)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_RELOAD_ATTR , attr_type, 0);
++}
++
++#endif	/* __FTPMU010_H */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/fttmr010.h b/arch/arm/mach-GM-SMP/include/mach/fttmr010.h
+new file mode 100644
+index 00000000..4f10f121
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/fttmr010.h
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (C) 2009 Po-Yu Chuang
++ * Copyright (C) 2009 Faraday Technology
++ *
++ * 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.
++ */
++
++/*
++ * Timer
++ */
++#ifndef __FTTMR010_H
++#define __FTTMR010_H
++
++#define FTTMR010_OFFSET_COUNTER		0x00
++#define FTTMR010_OFFSET_LOAD		0x04
++#define FTTMR010_OFFSET_MATCH1		0x08
++#define FTTMR010_OFFSET_MATCH2		0x0c
++#define FTTMR010_OFFSET_TIMER(x)	((x) * 0x10)
++#define FTTMR010_OFFSET_CR		0x30
++#define FTTMR010_OFFSET_INTR_STATE	0x34
++#define FTTMR010_OFFSET_INTR_MASK	0x38
++
++/*
++ * Timer Control Register
++ */
++#define FTTMR010_TM3_UPDOWN	(1 << 11)
++#define FTTMR010_TM2_UPDOWN	(1 << 10)
++#define FTTMR010_TM1_UPDOWN	(1 << 9)
++#define FTTMR010_TM3_OFENABLE	(1 << 8)
++#define FTTMR010_TM3_CLOCK	(1 << 7)
++#define FTTMR010_TM3_ENABLE	(1 << 6)
++#define FTTMR010_TM2_OFENABLE	(1 << 5)
++#define FTTMR010_TM2_CLOCK	(1 << 4)
++#define FTTMR010_TM2_ENABLE	(1 << 3)
++#define FTTMR010_TM1_OFENABLE	(1 << 2)
++#define FTTMR010_TM1_CLOCK	(1 << 1)
++#define FTTMR010_TM1_ENABLE	(1 << 0)
++
++/*
++ * Timer Interrupt State & Mask Registers
++ */
++#define FTTMR010_TM3_OVERFLOW	(1 << 8)
++#define FTTMR010_TM3_MATCH2	(1 << 7)
++#define FTTMR010_TM3_MATCH1	(1 << 6)
++#define FTTMR010_TM2_OVERFLOW	(1 << 5)
++#define FTTMR010_TM2_MATCH2	(1 << 4)
++#define FTTMR010_TM2_MATCH1	(1 << 3)
++#define FTTMR010_TM1_OVERFLOW	(1 << 2)
++#define FTTMR010_TM1_MATCH2	(1 << 1)
++#define FTTMR010_TM1_MATCH1	(1 << 0)
++
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++
++struct fttmr010_clockevent {
++	struct clock_event_device	clockevent;
++	struct irqaction		irqaction;
++	void __iomem			*base;
++	unsigned int			id;	/* one of 3 counters */
++	unsigned int			reload;
++	unsigned int			freq;
++};
++
++struct fttmr010_clocksource {
++	struct clocksource	clocksource;
++	void __iomem		*base;
++	unsigned int		id;	/* one of 3 counters */
++	unsigned int		freq;
++};
++
++void __init fttmr010_clockevent_init(struct fttmr010_clockevent *fttmr010);
++void __init fttmr010_clocksource_init(struct fttmr010_clocksource *fttmr010);
++
++#endif	/* __FTTMR010_H */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/gm_jiffies.h b/arch/arm/mach-GM-SMP/include/mach/gm_jiffies.h
+new file mode 100644
+index 00000000..66d4196b
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/gm_jiffies.h
+@@ -0,0 +1,27 @@
++#ifndef __GM_JIFFIES_H__
++#define __GM_JIFFIES_H__
++
++#define gm_jiffies      get_gm_jiffies()
++#define gm_jiffies_u64  get_gm_jiffies_u64()
++
++/* @unsigned long get_gm_jiffies(void)
++ * @Purpose: This function provides jiffies with 1ms granularity. This value will count up to 0xFFFFFFFF
++ *           and warp around again.
++ * @Parameter:
++ *   None
++ * @Return:
++ *      0 means the timer is not active. Othwise return non-zero value.
++ */
++unsigned long get_gm_jiffies(void);
++
++/* @u64 get_gm_jiffies_u64(void)
++ * @Purpose: This function provides jiffies with 1ms granularity. This value will count up to 0xFFFFFFFFFFFFFFFF
++ *           and warp around again.
++ * @Parameter:
++ *   None
++ * @Return:
++ *      0 means the timer is not active. Othwise return non-zero value.
++ */
++u64 get_gm_jiffies_u64(void);
++
++#endif /* __GM_JIFFIES_H__ */
+\ No newline at end of file
+diff --git a/arch/arm/mach-GM-SMP/include/mach/hardware.h b/arch/arm/mach-GM-SMP/include/mach/hardware.h
+new file mode 100644
+index 00000000..cd3c7737
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/hardware.h
+@@ -0,0 +1,38 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/hardware.h
++ *
++ *  This file contains the hardware definitions of the Faraday boards.
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_H
++#define __ASM_ARCH_HARDWARE_H
++
++#ifndef PCIBIOS_MIN_IO
++/* the mini io address is 0x6000,that is IO will allocate from 0-0x6000 offset*/
++#define PCIBIOS_MIN_IO	0x0
++#endif
++
++#ifndef PCIBIOS_MIN_MEM
++/* the mini MEM address is 0x100000,that is MEM will allocate from 0-0x100000 offset*/
++#define PCIBIOS_MIN_MEM	0x0
++#endif
++
++#define pcibios_assign_all_busses()	1
++
++#endif /* __ASM_ARCH_HARDWARE_H */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/io.h b/arch/arm/mach-GM-SMP/include/mach/io.h
+new file mode 100644
+index 00000000..238defe3
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/io.h
+@@ -0,0 +1,18 @@
++/* arch/arm/mach-s3c64xxinclude/mach/io.h
++ *
++ * Copyright 2008 Simtec Electronics
++ *	Ben Dooks <ben-linux@fluff.org>
++ *
++ * Default IO routines for S3C64XX based
++ */
++
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++/* No current ISA/PCI bus support. */
++#define __io(a)		((void __iomem *)(a))//__typesafe_io(a)
++#define __mem_pci(a)	(a)
++
++#define IO_SPACE_LIMIT (0xFFFFFFFF)
++
++#endif
+diff --git a/arch/arm/mach-GM-SMP/include/mach/irqs.h b/arch/arm/mach-GM-SMP/include/mach/irqs.h
+new file mode 100644
+index 00000000..a30bfb22
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/irqs.h
+@@ -0,0 +1,34 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/irqs.h
++ *
++ *  Faraday Platform Independent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 09/16/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__
++
++/* Include platform *dependent* IRQ definitions */
++#include <mach/platform/irqs.h>
++
++#endif /* __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__ */
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/memory.h b/arch/arm/mach-GM-SMP/include/mach/memory.h
+new file mode 100644
+index 00000000..0a52abdb
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/memory.h
+@@ -0,0 +1,47 @@
++/*
++ *  
++ *  Faraday Platform Independent Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ *  Harry Hsu 04/06/2010 add "isolate high memory" function
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__
++
++#include <asm/sizes.h>
++#include <mach/platform/memory.h>
++#include <mach/platform/platform_io.h>
++
++#define MEM_SIZE        SZ_256M
++#define END_MEM		    (CPU_MEM_PA_LIMIT + 1)
++
++#define CONSISTENT_DMA_SIZE  (12 << 20)	/* 12M NISH_20121015 */
++
++#ifndef __ASSEMBLY__
++extern unsigned long fmem_virt_to_phys(unsigned int vaddr);
++extern unsigned int fmem_phys_to_virt(unsigned long phys);
++
++#define __virt_to_phys(x)	fmem_virt_to_phys((unsigned int)(x))  //((x) - PAGE_OFFSET + PHYS_OFFSET)
++#define __phys_to_virt(x)	fmem_phys_to_virt((unsigned long)(x))  //((x) - PHYS_OFFSET + PAGE_OFFSET)
++#endif /* __ASSEMBLY__ */
++
++#endif /* __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/board.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/board.h
+new file mode 100644
+index 00000000..c9e45e7a
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/board.h
+@@ -0,0 +1,172 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/board.h
++ *
++ *  GM board Independent Specification
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ *  ChangeLog
++ *
++ *   Harry  2012/3/6 03:15 created.
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM8220 series"
++#define BOOT_PARAMETER_PA_OFFSET  0x100
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++#ifdef CONFIG_FPGA /*----------------------------- FPGA --------------------------------------*/
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0xa0200000//use DMA base to do
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* GIC_DIST */
++#define PLATFORM_GIC_DIST_PA_BASE   (PLATFORM_GIC_PA_BASE + 0x1000)//use DMA base to do
++#define PLATFORM_GIC_DIST_VA_BASE   (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define PLATFORM_GIC_DIST_VA_SIZE   SZ_4K
++
++/* GIC_CPU */
++#define PLATFORM_GIC_CPU_PA_BASE    (PLATFORM_GIC_PA_BASE + 0x2000)//use DMA base to do
++#define PLATFORM_GIC_CPU_VA_BASE    (PLATFORM_GIC_DIST_VA_BASE + PLATFORM_GIC_DIST_VA_SIZE)
++#define PLATFORM_GIC_CPU_VA_SIZE    SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE	0xa0800000
++#define UART_FTUART010_0_VA_BASE    (PLATFORM_GIC_CPU_VA_BASE + PLATFORM_GIC_CPU_VA_SIZE)//0xfa800000//(PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        (IRQ_GIC_START + 4)
++
++#define UART_FTUART010_1_PA_BASE    0xa0900000
++#define UART_FTUART010_1_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)//0xfa810000//(UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_1_VA_SIZE    SZ_4K
++#define UART_FTUART010_1_IRQ        (IRQ_GIC_START + 6)
++
++#define UART_FTUART010_2_PA_BASE    0x90900000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_1_VA_BASE + UART_FTUART010_1_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        (IRQ_GIC_START + 7)
++
++/* TIMER */
++#ifdef CONFIG_FTTMR010
++#define TIMER_FTTMR010_PA_BASE	    0xa0a00000
++#define TIMER_FTTMR010_VA_BASE	    0xfa820000
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         (IRQ_GIC_START + 1)
++#define TIMER_FTTMR010_IRQ1         (IRQ_GIC_START + 2)
++#define TIMER_FTTMR010_IRQ2         (IRQ_GIC_START + 3)
++#endif
++
++#else /*-------------------------------- GM8220 -------------------------------------*/
++
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0xfe000000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE	  0xfe200000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        (IRQ_GIC_START + 38)
++
++#define UART_FTUART010_1_PA_BASE    0xfe220000
++#define UART_FTUART010_1_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_1_VA_SIZE    SZ_4K
++#define UART_FTUART010_1_IRQ        (IRQ_GIC_START + 39)
++
++#define UART_FTUART010_2_PA_BASE    0xfe240000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_1_VA_BASE + UART_FTUART010_1_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        (IRQ_GIC_START + 43)
++
++#define UART_FTUART010_3_PA_BASE	  0xfe260000
++#define UART_FTUART010_3_VA_BASE    (UART_FTUART010_2_VA_BASE + UART_FTUART010_2_VA_SIZE)
++#define UART_FTUART010_3_VA_SIZE    SZ_4K
++#define UART_FTUART010_3_IRQ        (IRQ_GIC_START + 44)
++
++#define UART_FTUART010_4_PA_BASE    0xfe280000
++#define UART_FTUART010_4_VA_BASE    (UART_FTUART010_3_VA_BASE + UART_FTUART010_3_VA_SIZE)
++#define UART_FTUART010_4_VA_SIZE    SZ_4K
++#define UART_FTUART010_4_IRQ        (IRQ_GIC_START + 45)
++
++#define UART_FTUART010_5_PA_BASE    0xfe2a0000
++#define UART_FTUART010_5_VA_BASE    (UART_FTUART010_4_VA_BASE + UART_FTUART010_4_VA_SIZE)
++#define UART_FTUART010_5_VA_SIZE    SZ_4K
++#define UART_FTUART010_5_IRQ        (IRQ_GIC_START + 46)
++
++#define UART_FTUART010_6_PA_BASE    0xfe2c0000
++#define UART_FTUART010_6_VA_BASE    (UART_FTUART010_5_VA_BASE + UART_FTUART010_5_VA_SIZE)
++#define UART_FTUART010_6_VA_SIZE    SZ_4K
++#define UART_FTUART010_6_IRQ        (IRQ_GIC_START + 47)
++
++#define UART_FTUART010_7_PA_BASE    0xfe2e0000
++#define UART_FTUART010_7_VA_BASE    (UART_FTUART010_6_VA_BASE + UART_FTUART010_6_VA_SIZE)
++#define UART_FTUART010_7_VA_SIZE    SZ_4K
++#define UART_FTUART010_7_IRQ        (IRQ_GIC_START + 48)
++
++/* TIMER */
++#ifdef CONFIG_FTTMR010
++#define TIMER_FTTMR010_PA_BASE	    0xfe8c0000
++#define TIMER_FTTMR010_VA_BASE	    (UART_FTUART010_7_VA_BASE + UART_FTUART010_7_VA_SIZE)
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         (IRQ_GIC_START + 26)
++#define TIMER_FTTMR010_IRQ1         (IRQ_GIC_START + 26)
++#define TIMER_FTTMR010_IRQ2         (IRQ_GIC_START + 26)
++
++#endif
++
++/* TIMER */
++#if 0//def CONFIG_ARMGENERICTIMER
++#define TIMER_ARMGTIMER_PA_BASE	    0xA0547000//???
++#define TIMER_ARMGTIMER_VA_BASE	    (UART_FTUART010_7_VA_BASE + UART_FTUART010_7_VA_SIZE)
++#define TIMER_ARMGTIMER_VA_SIZE	    SZ_4K
++#define TIMER_ARMGTIMER_IRQ         27
++#endif
++
++#endif
++	
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/dma_route.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/dma_route.h
+new file mode 100644
+index 00000000..4fbf887a
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/dma_route.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
++ *
++ * 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.
++ * 
++ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++#ifndef __DMA_ROUTE_H__
++#define __DMA_ROUTE_H__
++
++/* define AHB DMA routing table 
++ */
++#define AHBDMA_REQ_SSP0_RX  0
++#define AHBDMA_REQ_SSP0_TX  1
++#define AHBDMA_REQ_SSP1_RX  2
++#define AHBDMA_REQ_SSP1_TX  3
++#define AHBDMA_REQ_SSP2_RX  4
++#define AHBDMA_REQ_SSP2_TX  5
++#define AHBDMA_REQ_SDC      6
++#define AHBDMA_REQ_NANDC    9
++#define AHBDMA_REQ_PWMTMR5  12
++#define AHBDMA_REQ_PWMTMR6  13
++#define AHBDMA_REQ_PWMTMR7  14
++#define AHBDMA_REQ_PWMTMR8  15
++
++/* define APB DMA routing table 
++ */
++#define APBDMA_REQ_UART0_RX 1
++#define APBDMA_REQ_UART0_TX 2
++#define APBDMA_REQ_UART1_RX 3
++#define APBDMA_REQ_UART1_TX 4
++#define APBDMA_REQ_UART2_RX 5
++#define APBDMA_REQ_UART2_TX 6
++#define APBDMA_REQ_UART3_RX 7  
++#define APBDMA_REQ_UART3_TX 8
++#define APBDMA_REQ_UART4_RX 9  
++#define APBDMA_REQ_UART4_TX 10
++#define APBDMA_REQ_PWMTMR1  12
++#define APBDMA_REQ_PWMTMR2  13
++#define APBDMA_REQ_PWMTMR3  14
++#define APBDMA_REQ_PWMTMR4  15
++
++
++#endif /* __DMA_ROUTE_H__ */
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/gpio.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/gpio.h
+new file mode 100644
+index 00000000..c8119e6c
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8220_GPIO_H__
++#define __GM8220_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		2
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8220_GPIO_H__
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/irqs.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/irqs.h
+new file mode 100644
+index 00000000..01306a9f
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/irqs.h
+@@ -0,0 +1,35 @@
++/*
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 10/06/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/memory.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/memory.h
+new file mode 100644
+index 00000000..8fcb0d97
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/memory.h
+@@ -0,0 +1,62 @@
++/*
++ *  
++ *  GM Platform Dependent Memory Configuration
++ *  
++ * 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
++ *  
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define PHYS_OFFSET     CPU_MEM_PA_BASE
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management. 
++ *
++ * Users can adjust the memory size based on the real memory size requirement.  
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     0x1000000
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement. 
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE. 
++ * The memory boundary is 16M alginment 
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/platform_io.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/platform_io.h
+new file mode 100644
+index 00000000..47c82901
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/platform_io.h
+@@ -0,0 +1,726 @@
++/*
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++#define IRQ_LOCALTIMER          29
++#define IRQ_LOCALWDOG           30
++#define PLATFORM_LEGACY_IRQ     31
++#define IRQ_GIC_START           32
++
++#define PLATFORM_IRQ_TOTALCOUNT	(IRQ_GIC_START + 128)
++#define PLATFORM_INTERRUPTS     PLATFORM_IRQ_TOTALCOUNT
++#define CPU_MEM_PA_BASE         0x0     /* the memory physical start address(DDR) */
++
++#ifdef CONFIG_FPGA/*==================================== FPGA ================================================*/
++
++#define IRQ_CA7_PMU_CPU0	(IRQ_GIC_START + 64)
++#define IRQ_CA7_PMU_CPU1	(IRQ_GIC_START + 65)
++#define IRQ_CA7_PMU_CPU2	(IRQ_GIC_START + 66)
++#define IRQ_CA7_PMU_CPU3	(IRQ_GIC_START + 67)
++
++/*
++ * currently, only IRQ 0 ~ 5 is available on HAPS
++ */
++/*
++#define IRQ_HAPS_FTUART010_1	(IRQ_HAPS_START + 6)
++#define IRQ_HAPS_FTDMAC030_0_TC	(IRQ_HAPS_START + 10)
++#define IRQ_HAPS_FTDMAC030_0_INT	(IRQ_HAPS_START + 11)
++#define IRQ_HAPS_FTDMAC030_0_ERR	(IRQ_HAPS_START + 12)
++
++#define PLATFORM_FIQ_BASE       0
++*/
++
++#define PLATFORM_GIC_PA_BASE       0xf0000000
++/*
++#define PLATFORM_GIC_VA_BASE       0xfa900000
++
++#define PLATFORM_GIC_DIST_PA_BASE	(PLATFORM_GIC_PA_BASE + 0x1000)
++#define PLATFORM_GIC_DIST_VA_BASE	(PLATFORM_GIC_VA_BASE + 0x1000)
++#define PLATFORM_GIC_CPU_PA_BASE	(PLATFORM_GIC_PA_BASE + 0x2000)
++#define PLATFORM_GIC_CPU_VA_BASE	(PLATFORM_GIC_VA_BASE + 0x2000)
++
++
++
++#define HAPS_FTUART010_0_PA_BASE	0xa0800000
++#define HAPS_FTUART010_1_PA_BASE	0xa0900000
++#define HAPS_FTTMR010_0_PA_BASE		0xa0a00000
++#define HAPS_FTINTC030_0_PA_BASE	0xa0b00000
++
++#define HAPS_FTDMAC030_0_PA_BASE	0xa0200000
++
++#define HAPS_FTUART010_0_VA_BASE	0xfa800000
++#define HAPS_FTUART010_1_VA_BASE	0xfa810000
++#define HAPS_FTTMR010_0_VA_BASE		0xfa820000
++#define HAPS_FTINTC030_0_VA_BASE	0xfa830000
++
++#define HAPS_FTGMAC030_0_PA_BASE	0xa0400000
++#define HAPS_FTGMAC030_0_VA_BASE	0xfa840000
++*/
++#define MAC_FTGMAC030_IRQ_COUNT	1
++#define MAC_FTGMAC030_IRQ	(IRQ_GIC_START + 5)
++#define MAC_FTGMAC030_0_IRQ	(IRQ_GIC_START + 5)
++
++#define MAC_FTGMAC030_PA_COUNT	1
++#define MAC_FTGMAC030_PA_BASE	0xa0400000
++#define MAC_FTGMAC030_PA_LIMIT	0xa0400FFF
++#define MAC_FTGMAC030_PA_SIZE	0x00001000
++#define MAC_FTGMAC030_0_PA_BASE	0xa0400000
++#define MAC_FTGMAC030_0_PA_LIMIT	0xa0400FFF
++#define MAC_FTGMAC030_0_PA_SIZE	0x00001000
++
++#define HAPS_SRAM_0_PA_BASE		0x90000000
++#define HAPS_SRAM_0_VA_BASE		0xfa850000
++#define SYS_FLAGSS_BASE			HAPS_SRAM_0_VA_BASE
++#define SYS_FLAGSS_OFFSET		0x50    /* record CPU boot address => SYS_FLAGSS_BASE + SYS_FLAGSS_OFFSET */
++/*
++#define DEBUG_LL_FTUART010_PA_BASE	HAPS_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE	HAPS_FTUART010_0_VA_BASE
++*/
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x90E00000
++#define WDT_FTWDT010_PA_LIMIT	0x90E00FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x90E00000
++#define WDT_FTWDT010_0_PA_LIMIT	0x90E00FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++#else/*======================================== GM8220 ============================================*/
++/*
++ * Component counts
++ */
++
++#define IRQ_CA7_PMU_CPU0	(IRQ_GIC_START + 100)
++#define IRQ_CA7_PMU_CPU1	(IRQ_GIC_START + 101)
++#define IRQ_CA7_PMU_CPU2	(IRQ_GIC_START + 102)
++#define IRQ_CA7_PMU_CPU3	(IRQ_GIC_START + 103)
++
++#define PLATFORM_GIC_PA_BASE       0xF9C00000
++
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	7
++#define GPIO_FTGPIO010_COUNT	7
++/* I2C */
++#define I2C_COUNT	6
++#define I2C_FTI2C010_COUNT	6
++/* SSP */
++#define SSP_COUNT	2
++#define SSP_FTSSP010_COUNT	2
++/* SPI020 */
++#define SPI_COUNT	1
++#define SPI_FTSPI020_COUNT	1
++/* SDC */
++#define SDC_COUNT	1
++#define SDC_FTSDC021_COUNT	1
++/* USB */
++#define USB_COUNT       2
++#define USB_FOTG2XX_COUNT       2
++/* LCD */
++#define LCD_COUNT	1
++#define LCD_FTLCDC200_COUNT	1
++/* MAC */
++#define MAC_COUNT	2
++#define MAC_FTGMAC030_COUNT	2
++/* TVE */
++#define TVE_COUNT	1
++#define TVE_FTTVE100_COUNT	1
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* 2D GRAPHIC */
++#define GRA_COUNT	2
++#define GRA_FT2DGRA_COUNT	2
++/* CAP */
++#define CAP_COUNT	2
++#define CAP_FTCAP300_COUNT	2
++/* H264E */
++#define H264E_COUNT	4
++#define H264E_FTMCP290_COUNT	4
++/* H264D */
++#define H264D_COUNT	4
++#define H264D_FTMCP300_COUNT	4
++/* MCP */
++#define MCP_COUNT	2
++#define MCP_FTMCP100_COUNT	2
++/* IVS */
++#define IVS_COUNT   4
++#define IVS_FTIVS_COUNT 4
++/* SATA */
++#define SATA_COUNT	4
++#define SATA_FTSATA100_COUNT	4
++/* DMAC */
++#define DMAC_COUNT	1
++#define DMAC_FTDMAC020_COUNT	1
++/* XDMAC */
++#define XDMAC_COUNT	2
++#define XDMAC_FTDMAC030_COUNT	2
++/* IR_DET */
++#define IR_DET_COUNT	1
++#define IR_DET_FTIRDET_COUNT	1
++/* KEYSCAN */
++#define KEYSCAN_COUNT	1
++#define KEYSCAN_FTKEYSCAN_COUNT	1
++/* HDMI */
++#define HDMI_COUNT	1
++#define HDMI_FTHDMI_COUNT	1
++
++/*
++ * Interrrupt numbers
++ */
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	(IRQ_GIC_START + 68)
++#define WDT_FTWDT010_0_IRQ	(IRQ_GIC_START + 68)
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	1
++#define GPIO_FTGPIO010_IRQ	(IRQ_GIC_START + 55)
++#define GPIO_FTGPIO010_0_IRQ	(IRQ_GIC_START + 55)
++#define GPIO_FTGPIO010_1_IRQ	(IRQ_GIC_START + 89)
++#define GPIO_FTGPIO010_2_IRQ	(IRQ_GIC_START + 90)
++#define GPIO_FTGPIO010_3_IRQ	(IRQ_GIC_START + 91)
++#define GPIO_FTGPIO010_4_IRQ	(IRQ_GIC_START + 92)
++#define GPIO_FTGPIO010_5_IRQ	(IRQ_GIC_START + 93)
++#define GPIO_FTGPIO010_6_IRQ	(IRQ_GIC_START + 94)
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	(IRQ_GIC_START + 49)
++#define I2C_FTI2C010_0_IRQ	(IRQ_GIC_START + 49)
++#define I2C_FTI2C010_1_IRQ	(IRQ_GIC_START + 50)
++#define I2C_FTI2C010_2_IRQ	(IRQ_GIC_START + 51)
++#define I2C_FTI2C010_3_IRQ	(IRQ_GIC_START + 52)
++#define I2C_FTI2C010_4_IRQ	(IRQ_GIC_START + 53)
++#define I2C_FTI2C010_5_IRQ	(IRQ_GIC_START + 54)
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	(IRQ_GIC_START + 67)
++#define SSP_FTSSP010_0_IRQ	(IRQ_GIC_START + 67)
++#define SSP_FTSSP010_1_IRQ	(IRQ_GIC_START + 69)
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	(IRQ_GIC_START + 42)
++#define SPI_FTSPI020_0_IRQ	(IRQ_GIC_START + 42)
++
++/* SDC */
++#define SDC_FTSDC021_IRQ_COUNT	1
++#define SDC_FTSDC021_IRQ	(IRQ_GIC_START + 40)
++#define SDC_FTSDC021_0_IRQ	(IRQ_GIC_START + 40)
++
++/* USB */
++#define USB_FOTG2XX_IRQ_COUNT	1
++#define USB_FOTG2XX_IRQ		(IRQ_GIC_START + 34)
++#define USB_FOTG2XX_0_IRQ	(IRQ_GIC_START + 34)
++#define USB_FOTG2XX_1_IRQ	(IRQ_GIC_START + 35)
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	(IRQ_GIC_START + 15)
++#define LCD_FTLCDC200_0_IRQ	(IRQ_GIC_START + 15)
++
++/* MAC */
++#define MAC_FTGMAC030_IRQ_COUNT	2
++#define MAC_FTGMAC030_IRQ	(IRQ_GIC_START + 16)
++#define MAC_FTGMAC030_0_IRQ	(IRQ_GIC_START + 16)
++#define MAC_FTGMAC030_1_IRQ	(IRQ_GIC_START + 17)
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	(IRQ_GIC_START + 64)
++#define AES_FTAES020_0_IRQ	(IRQ_GIC_START + 64)
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_IRQ_COUNT	2
++#define GRA_FT2DGRA_IRQ	(IRQ_GIC_START + 28)
++#define GRA_FT2DGRA_0_IRQ	(IRQ_GIC_START + 28)
++#define GRA_FT2DGRA_0_IRQ	(IRQ_GIC_START + 14)
++
++/* CAP */
++#define CAP_FTCAP300_IRQ_COUNT	2
++#define CAP_FTCAP300_IRQ	(IRQ_GIC_START + 0)
++#define CAP_FTCAP300_0_IRQ	(IRQ_GIC_START + 0)
++#define CAP_FTCAP300_1_IRQ	(IRQ_GIC_START + 1)
++
++/* H264E */
++#define H264E_FTMCP290_IRQ_COUNT	4
++#define H264E_FTMCP290_IRQ	(IRQ_GIC_START + 5)
++#define H264E_FTMCP290_0_IRQ	(IRQ_GIC_START + 5)
++#define H264E_FTMCP290_1_IRQ	(IRQ_GIC_START + 6)
++#define H264E_FTMCP290_2_IRQ	(IRQ_GIC_START + 7)
++#define H264E_FTMCP290_3_IRQ	(IRQ_GIC_START + 8)
++
++/* H264D */
++#define H264D_FTMCP300_IRQ_COUNT	4
++#define H264D_FTMCP300_IRQ	(IRQ_GIC_START + 9)
++#define H264D_FTMCP300_0_IRQ	(IRQ_GIC_START + 9)
++#define H264D_FTMCP300_1_IRQ	(IRQ_GIC_START + 10)
++#define H264D_FTMCP300_2_IRQ	(IRQ_GIC_START + 11)
++#define H264D_FTMCP300_3_IRQ	(IRQ_GIC_START + 12)
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	2
++#define MCP_FTMCP100_IRQ	(IRQ_GIC_START + 32)
++#define MCP_FTMCP100_0_IRQ	(IRQ_GIC_START + 32)
++#define MCP_FTMCP100_1_IRQ	(IRQ_GIC_START + 33)
++
++/* IVS */
++#define IVS_IRQ_COUNT   4
++#define IVS_IRQ     (IRQ_GIC_START + 31)
++#define IVS_0_IRQ   (IRQ_GIC_START + 31)
++#define IVS_1_IRQ   (IRQ_GIC_START + 56)
++#define IVS_2_IRQ   (IRQ_GIC_START + 57)
++#define IVS_3_IRQ   (IRQ_GIC_START + 58)
++
++/* SATA */
++#define SATA_FTSATA100_IRQ_COUNT	1
++#define SATA_FTSATA100_IRQ	(IRQ_GIC_START + 20)
++#define SATA_FTSATA100_0_IRQ	(IRQ_GIC_START + 20)
++#define SATA_FTSATA100_1_IRQ	(IRQ_GIC_START + 21)
++#define SATA_FTSATA100_2_IRQ	(IRQ_GIC_START + 22)
++#define SATA_FTSATA100_3_IRQ	(IRQ_GIC_START + 23)
++
++/* DMAC */
++#define DMAC_FTDMAC020_IRQ_COUNT	1
++#define DMAC_FTDMAC020_IRQ		(IRQ_GIC_START + 37)
++#define DMAC_FTDMAC020_0_IRQ	(IRQ_GIC_START + 37)
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_IRQ_COUNT	2
++#define XDMAC_FTDMAC030_IRQ		(IRQ_GIC_START + 18)
++#define XDMAC_FTDMAC030_0_IRQ	(IRQ_GIC_START + 18)
++#define XDMAC_FTDMAC030_1_IRQ   (IRQ_GIC_START + 19)
++
++/* IR_DET */
++#define IR_DET_FTIRDET_IRQ_COUNT	1
++#define IR_DET_FTIRDET_IRQ		(IRQ_GIC_START + 65)
++#define IR_DET_FTIRDET_0_IRQ	(IRQ_GIC_START + 65)
++
++/* KEYSCAN */
++#define KEYSCAN_FTKEYSCAN_IRQ_COUNT     1
++#define KEYSCAN_FTKEYSCAN_IRQ           (IRQ_GIC_START + 66)
++#define KEYSCAN_FTKEYSCAN_0_IRQ         (IRQ_GIC_START + 66)
++
++/* HDMI */
++//#define HDMI_FTHDMI_IRQ_COUNT	1
++//#define HDMI_FTHDMI_IRQ		(PLATFORM_GM8312_IRQ_BASE + 8)
++//#define HDMI_FTHDMI_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 8)
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_IRQ_COUNT    1
++#define DMAC_FTDMAC020_IRQ  (IRQ_GIC_START + 37)
++#define DMAC_FTDMAC020_0_IRQ		(IRQ_GIC_START + 37)
++
++/*
++ * Base addresses
++ */
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0xFE8A0000
++#define WDT_FTWDT010_PA_LIMIT	0xFE8A0FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0xFE8A0000
++#define WDT_FTWDT010_0_PA_LIMIT	0xFE8A0FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	1
++#define GPIO_FTGPIO010_PA_BASE	0xFE400000
++#define GPIO_FTGPIO010_PA_LIMIT	0xFE400FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0xFE400000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0xFE400FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0xFE420000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0xFE420FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_2_PA_BASE	0xFE440000
++#define GPIO_FTGPIO010_2_PA_LIMIT	0xFE440FFF
++#define GPIO_FTGPIO010_2_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_3_PA_BASE	0xFE460000
++#define GPIO_FTGPIO010_3_PA_LIMIT	0xFE460FFF
++#define GPIO_FTGPIO010_3_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_4_PA_BASE	0xFE480000
++#define GPIO_FTGPIO010_4_PA_LIMIT	0xFE480FFF
++#define GPIO_FTGPIO010_4_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_5_PA_BASE	0xFE4A0000
++#define GPIO_FTGPIO010_5_PA_LIMIT	0xFE4A0FFF
++#define GPIO_FTGPIO010_5_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_6_PA_BASE	0xFE4C0000
++#define GPIO_FTGPIO010_6_PA_LIMIT	0xFE4C0FFF
++#define GPIO_FTGPIO010_6_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0xFE300000
++#define I2C_FTI2C010_PA_LIMIT	0xFE300FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0xFE320000
++#define I2C_FTI2C010_0_PA_LIMIT	0xFE320FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_FTI2C010_1_PA_BASE	0xFE340000
++#define I2C_FTI2C010_1_PA_LIMIT	0xFE340FFF
++#define I2C_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_FTI2C010_2_PA_BASE	0xFE360000
++#define I2C_FTI2C010_2_PA_LIMIT	0xFE360FFF
++#define I2C_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_FTI2C010_3_PA_BASE	0xFE380000
++#define I2C_FTI2C010_3_PA_LIMIT	0xFE380FFF
++#define I2C_FTI2C010_3_PA_SIZE	0x00001000
++#define I2C_FTI2C010_4_PA_BASE	0xFE3A0000
++#define I2C_FTI2C010_4_PA_LIMIT	0xFE3A0FFF
++#define I2C_FTI2C010_4_PA_SIZE	0x00001000
++
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0xFE3C0000
++#define SSP_FTSSP010_PA_LIMIT	0xFE3C0FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0xFE3C0000
++#define SSP_FTSSP010_0_PA_LIMIT	0xFE3C0FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0xFE3E0000
++#define SSP_FTSSP010_1_PA_LIMIT	0xFE3E0FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++
++/* SPI */
++#define SPI_FTSPI020_PA_COUNT	1
++#define SPI_FTSPI020_PA_BASE	0xFA700000
++#define SPI_FTSPI020_PA_LIMIT	0xFA700FFF
++#define SPI_FTSPI020_PA_SIZE	0x00001000
++#define SPI_FTSPI020_0_PA_BASE	0xFA700000
++#define SPI_FTSPI020_0_PA_LIMIT	0xFA700FFF
++#define SPI_FTSPI020_0_PA_SIZE	0x00001000
++
++/* SDC */
++#define SDC_FTSDC021_PA_COUNT	1
++#define SDC_FTSDC021_PA_BASE	0xFA600000
++#define SDC_FTSDC021_PA_LIMIT	0xFA600FFF
++#define SDC_FTSDC021_PA_SIZE	0x00001000
++#define SDC_FTSDC021_0_PA_BASE	0xFA600000
++#define SDC_FTSDC021_0_PA_LIMIT	0xFA600FFF
++#define SDC_FTSDC021_0_PA_SIZE	0x00001000
++
++/* USB */
++#define USB_FOTG2XX_PA_COUNT	1
++#define USB_FOTG2XX_PA_BASE	0xF9300000
++#define USB_FOTG2XX_PA_LIMIT	0xF9300FFF
++#define USB_FOTG2XX_PA_SIZE	0x00001000
++#define USB_FOTG2XX_0_PA_BASE	0xF9300000
++#define USB_FOTG2XX_0_PA_LIMIT	0xF9300FFF
++#define USB_FOTG2XX_0_PA_SIZE	0x00001000
++#define USB_FOTG2XX_1_PA_BASE	0xF9400000
++#define USB_FOTG2XX_1_PA_LIMIT	0xF9400FFF
++#define USB_FOTG2XX_1_PA_SIZE	0x00001000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	1
++#define LCD_FTLCDC200_PA_BASE	0xFD900000
++#define LCD_FTLCDC200_PA_LIMIT	0xFD90CFFF
++#define LCD_FTLCDC200_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	0xFD900000
++#define LCD_FTLCDC200_0_PA_LIMIT	0xFD90CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	0x0000D000
++
++/* MAC */
++#define MAC_FTGMAC030_PA_COUNT	1
++#define MAC_FTGMAC030_PA_BASE	0xFCC00000
++#define MAC_FTGMAC030_PA_LIMIT	0xFCC00FFF
++#define MAC_FTGMAC030_PA_SIZE	0x00001000
++#define MAC_FTGMAC030_0_PA_BASE	0xFCC00000
++#define MAC_FTGMAC030_0_PA_LIMIT	0xFCC00FFF
++#define MAC_FTGMAC030_0_PA_SIZE	0x00001000
++#define MAC_FTGMAC030_1_PA_BASE	0xFCD00000
++#define MAC_FTGMAC030_1_PA_LIMIT	0xFCD00FFF
++#define MAC_FTGMAC030_1_PA_SIZE	0x00001000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT	1
++#define TVE_FTTVE100_PA_BASE	0xFBF00000
++#define TVE_FTTVE100_PA_LIMIT	0xFBF00FFF
++#define TVE_FTTVE100_PA_SIZE	0x00001000
++#define TVE_FTTVE100_0_PA_BASE	0xFBF00000
++#define TVE_FTTVE100_0_PA_LIMIT	0xFBF00FFF
++#define TVE_FTTVE100_0_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0xFA400000
++#define AES_FTAES020_PA_LIMIT	0xFA400FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0xFA400000
++#define AES_FTAES020_0_PA_LIMIT	0xFA400FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_PA_COUNT	2
++#define GRA_FT2DGRA_PA_BASE	0xFB800000
++#define GRA_FT2DGRA_PA_LIMIT	0xFB800FFF
++#define GRA_FT2DGRA_PA_SIZE	0x00001000
++#define GRA_FT2DGRA_0_PA_BASE	0xFB800000
++#define GRA_FT2DGRA_0_PA_LIMIT	0xFB800FFF
++#define GRA_FT2DGRA_0_PA_SIZE	0x00001000
++#define GRA_FT2DGRA_1_PA_BASE	0xFB900000
++#define GRA_FT2DGRA_1_PA_LIMIT	0xFB900FFF
++#define GRA_FT2DGRA_1_PA_SIZE	0x00001000
++
++/* CAP */
++#define CAP_FTCAP300_PA_COUNT	1
++#define CAP_FTCAP300_PA_BASE	0xF9100000
++#define CAP_FTCAP300_PA_LIMIT	0xF9100FFF
++#define CAP_FTCAP300_PA_SIZE	0x00001000
++#define CAP_FTCAP300_0_PA_BASE	0xF9100000
++#define CAP_FTCAP300_0_PA_LIMIT	0xF9100FFF
++#define CAP_FTCAP300_0_PA_SIZE	0x00001000
++#define CAP_FTCAP300_1_PA_BASE	0xF9200000
++#define CAP_FTCAP300_1_PA_LIMIT	0xF9200FFF
++#define CAP_FTCAP300_1_PA_SIZE	0x00001000
++
++/* H264E */
++#define H264E_FTMCP290_PA_COUNT	    1
++#define H264E_FTMCP290_PA_BASE      0xFA800000
++#define H264E_FTMCP290_PA_LIMIT	    0xFA801FFF
++#define H264E_FTMCP290_PA_SIZE      0x00002000
++#define H264E_FTMCP290_0_PA_BASE    0xFA800000
++#define H264E_FTMCP290_0_PA_LIMIT   0xFA801FFF
++#define H264E_FTMCP290_0_PA_SIZE    0x00002000
++#define H264E_FTMCP290_1_PA_BASE    0xFAA00000
++#define H264E_FTMCP290_1_PA_LIMIT   0xFAA01FFF
++#define H264E_FTMCP290_1_PA_SIZE    0x00002000
++#define H264E_FTMCP290_2_PA_BASE    0xFAC00000
++#define H264E_FTMCP290_2_PA_LIMIT   0xFAC01FFF
++#define H264E_FTMCP290_2_PA_SIZE    0x00002000
++#define H264E_FTMCP290_3_PA_BASE   	0xFAE00000
++#define H264E_FTMCP290_3_PA_LIMIT  	0xFAE01FFF
++#define H264E_FTMCP290_3_PA_SIZE    0x00002000
++#define H264E_FTMCP290_VC_0_PA_BASE     0xFA900000
++#define H264E_FTMCP290_VC_0_PA_LIMIT    0xFA900FFF
++#define H264E_FTMCP290_VC_0_PA_SIZE     0x00001000
++#define H264E_FTMCP290_VC_1_PA_BASE     0xFAB00000
++#define H264E_FTMCP290_VC_1_PA_LIMIT    0xFAB00FFF
++#define H264E_FTMCP290_VC_1_PA_SIZE     0x00001000
++#define H264E_FTMCP290_VC_2_PA_BASE     0xFAD00000
++#define H264E_FTMCP290_VC_2_PA_LIMIT    0xFAD00FFF
++#define H264E_FTMCP290_VC_2_PA_SIZE     0x00001000
++#define H264E_FTMCP290_VC_3_PA_BASE     0xFAF00000
++#define H264E_FTMCP290_VC_3_PA_LIMIT    0xFAF00FFF
++#define H264E_FTMCP290_VC_3_PA_SIZE     0x00001000
++
++/* H264D */
++#define H264D_FTMCP300_PA_COUNT	    1
++#define H264D_FTMCP300_PA_BASE      0xFB000000
++#define H264D_FTMCP300_PA_LIMIT     0xFB07FFFF
++#define H264D_FTMCP300_PA_SIZE      0x00080000
++#define H264D_FTMCP300_0_PA_BASE    0xFB000000
++#define H264D_FTMCP300_0_PA_LINIT   0xFB07FFFF
++#define H264D_FTMCP300_0_PA_SIZE    0x00080000
++#define H264D_FTMCP300_1_PA_BASE    0xFB200000
++#define H264D_FTMCP300_1_PA_LINIT   0xFB27FFFF
++#define H264D_FTMCP300_1_PA_SIZE    0x00080000
++#define H264D_FTMCP300_2_PA_BASE    0xFB400000
++#define H264D_FTMCP300_2_PA_LINIT   0xFB47FFFF
++#define H264D_FTMCP300_2_PA_SIZE    0x00080000
++#define H264D_FTMCP300_3_PA_BASE    0xFB600000
++#define H264D_FTMCP300_3_PA_LINIT   0xFB67FFFF
++#define H264D_FTMCP300_3_PA_SIZE    0x00080000
++#define H264D_FTMCP300_VC_0_PA_BASE     0xFB100000
++#define H264D_FTMCP300_VC_0_PA_LIMIT    0xFB100FFF
++#define H264D_FTMCP300_VC_0_PA_SIZE     0x00001000
++#define H264D_FTMCP300_VC_1_PA_BASE     0xFB300000
++#define H264D_FTMCP300_VC_1_PA_LIMIT    0xFB300FFF
++#define H264D_FTMCP300_VC_1_PA_SIZE     0x00001000
++#define H264D_FTMCP300_VC_2_PA_BASE     0xFB500000
++#define H264D_FTMCP300_VC_2_PA_LIMIT    0xFB500FFF
++#define H264D_FTMCP300_VC_2_PA_SIZE     0x00001000
++#define H264D_FTMCP300_VC_3_PA_BASE     0xFB700000
++#define H264D_FTMCP300_VC_3_PA_LIMIT    0xFB700FFF
++#define H264D_FTMCP300_VC_3_PA_SIZE     0x00001000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0xFBB00000
++#define MCP_FTMCP100_PA_LIMIT	0xFBBFFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_WRP_PA_BASE    0xFBA00000
++#define MCP_FTMCP100_WRP_PA_LIMIT   0xFBA00FFF
++#define MCP_FTMCP100_WRP_PA_SIZE    0x00001000
++#define MCP_FTMCP100_0_PA_BASE	0xFBB00000
++#define MCP_FTMCP100_0_PA_LIMIT	0xFBBFFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++#define MCP_FTMCP100_WRP_0_PA_BASE  0xFBA00000
++#define MCP_FTMCP100_WRP_0_PA_LIMIT 0xFBA00FFF
++#define MCP_FTMCP100_WRP_0_PA_SIZE  0x00001000
++#define MCP_FTMCP100_1_PA_BASE	0xFBD00000
++#define MCP_FTMCP100_1_PA_LIMIT	0xFBDFFFFF
++#define MCP_FTMCP100_1_PA_SIZE	0x00100000
++#define MCP_FTMCP100_WRP_1_PA_BASE  0xFBC00000
++#define MCP_FTMCP100_WRP_1_PA_LIMIT 0xFBC00FFF
++#define MCP_FTMCP100_WRP_1_PA_SIZE  0x00001000
++
++/* IVS */
++#define IVS_PA_COUNT    1
++#define IVS_PA_BASE     0xFEC20000
++#define IVS_PA_LIMIT    0xFEC2FFFF
++#define IVS_PA_SIZE     0x00010000
++#define IVS_0_PA_BASE   0xFEC20000
++#define IVS_0_PA_LIMIT  0xFEC2FFFF
++#define IVS_0_PA_SIZE   0x00010000
++#define IVS_1_PA_BASE   0xFEC40000
++#define IVS_1_PA_LIMIT  0xFEC4FFFF
++#define IVS_1_PA_SIZE   0x00010000
++#define IVS_2_PA_BASE   0xFEC60000
++#define IVS_2_PA_LIMIT  0xFEC6FFFF
++#define IVS_2_PA_SIZE   0x00010000
++#define IVS_3_PA_BASE   0xFEC80000
++#define IVS_3_PA_LIMIT  0xFEC8FFFF
++#define IVS_3_PA_SIZE   0x00010000
++
++/* SATA */
++#define SATA_FTSATA100_PA_COUNT	    4
++#define SATA_FTSATA100_PA_BASE      0xF9800000
++#define SATA_FTSATA100_PA_LIMIT     0xF9800FFF
++#define SATA_FTSATA100_PA_SIZE      0x00001000
++#define SATA_FTSATA100_0_PA_BASE    0xF9800000
++#define SATA_FTSATA100_0_PA_LIMIT   0xF9800FFF
++#define SATA_FTSATA100_0_PA_SIZE    0x00001000
++#define SATA_FTSATA100_1_PA_BASE    0xF9600000
++#define SATA_FTSATA100_1_PA_LIMIT   0xF9600FFF
++#define SATA_FTSATA100_1_PA_SIZE    0x00001000
++#define SATA_FTSATA100_2_PA_BASE    0xF9700000
++#define SATA_FTSATA100_2_PA_LIMIT   0xF9700FFF
++#define SATA_FTSATA100_2_PA_SIZE    0x00001000
++#define SATA_FTSATA100_3_PA_BASE    0xF9A00000
++#define SATA_FTSATA100_3_PA_LIMIT   0xF9A00FFF
++#define SATA_FTSATA100_3_PA_SIZE    0x00001000
++
++/* DMAC */
++#define DMAC_FTDMAC020_PA_COUNT		1
++#define DMAC_FTDMAC020_PA_BASE		0xFA500000
++#define DMAC_FTDMAC020_PA_LIMIT		0xFA500FFF
++#define DMAC_FTDMAC020_PA_SIZE		0x00001000
++#define DMAC_FTDMAC020_0_PA_BASE	0xFA500000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0xFA500FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_PA_COUNT	2
++#define XDMAC_FTDMAC030_PA_BASE		0xFCA00000
++#define XDMAC_FTDMAC030_PA_LIMIT	0xFCA00FFF
++#define XDMAC_FTDMAC030_PA_SIZE		0x00001000
++#define XDMAC_FTDMAC030_0_PA_BASE	0xFCA00000
++#define XDMAC_FTDMAC030_0_PA_LIMIT	0xFCA00FFF
++#define XDMAC_FTDMAC030_0_PA_SIZE	0x00001000
++#define XDMAC_FTDMAC030_1_PA_BASE	0xFCB00000
++#define XDMAC_FTDMAC030_1_PA_LIMIT	0xFCB00FFF
++#define XDMAC_FTDMAC030_1_PA_SIZE	0x00001000
++
++/* IR_DET */
++#define IR_DET_FTIRDET_PA_COUNT	1
++#define IR_DET_FTIRDET_PA_BASE	0xFE540000
++#define IR_DET_FTIRDET_PA_LIMIT	0xFE540FFF
++#define IR_DET_FTIRDET_PA_SIZE	0x00001000
++#define IR_DET_FTIRDET_0_PA_BASE	0xFE540000
++#define IR_DET_FTIRDET_0_PA_LIMIT	0xFE540FFF
++#define IR_DET_FTIRDET_0_PA_SIZE	0x00001000
++
++/* KEYSCAN */
++#define KEYSCAN_FTKEYSCAN_PA_COUNT      1
++#define KEYSCAN_FTKEYSCAN_PA_BASE       0xFE560000
++#define KEYSCAN_FTKEYSCAN_PA_LIMIT      0xFE560FFF
++#define KEYSCAN_FTKEYSCAN_PA_SIZE       0x00001000
++#define KEYSCAN_FTKEYSCAN_0_PA_BASE     0xFE560000
++#define KEYSCAN_FTKEYSCAN_0_PA_LIMIT    0xFE560FFF
++#define KEYSCAN_FTKEYSCAN_0_PA_SIZE     0x00001000
++
++/* HDMI */
++#define HDMI_FTHDMI_PA_COUNT	1
++#define HDMI_FTHDMI_PA_BASE	0xFE6E0000
++#define HDMI_FTHDMI_PA_LIMIT	0xFE6E0FFF
++#define HDMI_FTHDMI_PA_SIZE	0x00001000
++#define HDMI_FTHDMI_0_PA_BASE	0xFE6E0000
++#define HDMI_FTHDMI_0_PA_LIMIT	0xFE6E0FFF
++#define HDMI_FTHDMI_0_PA_SIZE	0x00001000
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_PA_COUNT 1
++#define DMAC_FTDMAC020_PA_BASE  0xFA500000
++#define DMAC_FTDMAC020_PA_LIMIT 0xFA500FFF
++#define DMAC_FTDMAC020_PA_SIZE  0x0001000
++#define DMAC_FTDMAC020_0_PA_BASE	0xFA500000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0xFA500FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++#define PLATFORM_IRQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL1	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL1	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL3	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL3	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL4	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL4	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL5	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL5	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL6	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL6	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL7	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL7	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL8	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL8	0xFFFFFFFF
++
++#endif//====================================================================================
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/pmu.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/pmu.h
+new file mode 100644
+index 00000000..00e0588a
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/pmu.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++
++
++unsigned int pmu_get_apb_clk(void);
++int platform_check_flash_type(void);
++int platform_spi_four_byte_mode(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/serial.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/serial.h
+new file mode 100644
+index 00000000..b63bcc64
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/serial.h
+@@ -0,0 +1,96 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 4 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ *  Luke Lee  11/16/2005  Add conditional compilation.
++ */
++
++#ifdef CONFIG_FPGA
++#define CONFIG_UART_CLK			18432000//12000000
++#else
++#define CONFIG_UART_CLK			25000000
++#endif
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#ifdef CONFIG_SERIAL_UART1_IP
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++#else
++#define EXTENDED_UART_1 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART2_IP
++#define EXTENDED_UART_2 \
++     { 0, BASE_BAUD, UART_FTUART010_2_VA_BASE, UART_FTUART010_2_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS2 */
++#else
++#define EXTENDED_UART_2 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1            \
++        EXTENDED_UART_2
++
++/* set uart clock source select to PLL2 divider output / 2 and clock divided value */
++static inline void ft_set_uartclk(void)
++{
++    unsigned int val, pval;
++
++#if 0
++    /* default is already set to pll2out_div2 */
++    val = inl(PMU_FTPMU010_VA_BASE + 0x28);
++    val &= ~(1 << 3);
++    outl(val, PMU_FTPMU010_VA_BASE + 0x28);
++#endif
++    pval = 0;
++    val = inl(PMU_FTPMU010_VA_BASE + 0x70);
++    val = (val & ~(0x3F << 16)) | (pval << 16);
++    outl(val, PMU_FTPMU010_VA_BASE + 0x70);
++}
++
++#define OSCH_FREQ   30000000
++
++/* get UCLK at run time, CONFIG_UART_CLK is omitted */
++static inline unsigned int ft_get_uartclk(void)
++{
++    unsigned int pval, mul, div;
++    static int set_done = 0;
++
++    if (set_done == 0) {
++        ft_set_uartclk();
++        set_done = 1;
++    }
++
++    pval = (inl(PMU_FTPMU010_VA_BASE + 0x70) >> 16) & 0x3F;
++
++    /* uart clock source = PLL2 divider output / 2 */
++    mul = (inl(PMU_FTPMU010_VA_BASE + 0x34) >> 4) & 0x7F;
++    div = (inl(PMU_FTPMU010_VA_BASE + 0x34) >> 11) & 0x1F;
++
++    return (OSCH_FREQ / div * mul) / 2 / (pval + 1);
++}
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/system.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/system.h
+new file mode 100644
+index 00000000..9174d6c5
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/system.h
+@@ -0,0 +1,77 @@
++/*
++ *
++ *  Faraday Platform Dependent System Definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/22/2005  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++static inline void arch_reset(char mode, const char *cmd)
++{
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++
++    pmuReg_t regRSTArray[] = {
++        /* reg_off, bit_masks, lock_bits,init_val, init_mask */
++        {0xB8, (1<< 10), (1<< 10), 0, (1<< 10)},
++    };
++
++    pmuRegInfo_t rst_clk_info = {
++        "rst_clk",
++        ARRAY_SIZE(regRSTArray),
++        ATTR_TYPE_NONE,
++        regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<15)), (PMU_FTPMU010_VA_BASE + 0x3C));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C));        // reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));        // load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08));   // Magic number
++    writeb(0x03, (wdt_va_base + 0x0C));     // Enable WDT
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/vmalloc.h b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/vmalloc.h
+new file mode 100644
+index 00000000..127ef2b8
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform-GM8220/vmalloc.h
+@@ -0,0 +1,35 @@
++/*
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  10/06/2005  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/board.h b/arch/arm/mach-GM-SMP/include/mach/platform/board.h
+new file mode 100644
+index 00000000..c9e45e7a
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/board.h
+@@ -0,0 +1,172 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/board.h
++ *
++ *  GM board Independent Specification
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ *  ChangeLog
++ *
++ *   Harry  2012/3/6 03:15 created.
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM8220 series"
++#define BOOT_PARAMETER_PA_OFFSET  0x100
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++#ifdef CONFIG_FPGA /*----------------------------- FPGA --------------------------------------*/
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0xa0200000//use DMA base to do
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* GIC_DIST */
++#define PLATFORM_GIC_DIST_PA_BASE   (PLATFORM_GIC_PA_BASE + 0x1000)//use DMA base to do
++#define PLATFORM_GIC_DIST_VA_BASE   (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define PLATFORM_GIC_DIST_VA_SIZE   SZ_4K
++
++/* GIC_CPU */
++#define PLATFORM_GIC_CPU_PA_BASE    (PLATFORM_GIC_PA_BASE + 0x2000)//use DMA base to do
++#define PLATFORM_GIC_CPU_VA_BASE    (PLATFORM_GIC_DIST_VA_BASE + PLATFORM_GIC_DIST_VA_SIZE)
++#define PLATFORM_GIC_CPU_VA_SIZE    SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE	0xa0800000
++#define UART_FTUART010_0_VA_BASE    (PLATFORM_GIC_CPU_VA_BASE + PLATFORM_GIC_CPU_VA_SIZE)//0xfa800000//(PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        (IRQ_GIC_START + 4)
++
++#define UART_FTUART010_1_PA_BASE    0xa0900000
++#define UART_FTUART010_1_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)//0xfa810000//(UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_1_VA_SIZE    SZ_4K
++#define UART_FTUART010_1_IRQ        (IRQ_GIC_START + 6)
++
++#define UART_FTUART010_2_PA_BASE    0x90900000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_1_VA_BASE + UART_FTUART010_1_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        (IRQ_GIC_START + 7)
++
++/* TIMER */
++#ifdef CONFIG_FTTMR010
++#define TIMER_FTTMR010_PA_BASE	    0xa0a00000
++#define TIMER_FTTMR010_VA_BASE	    0xfa820000
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         (IRQ_GIC_START + 1)
++#define TIMER_FTTMR010_IRQ1         (IRQ_GIC_START + 2)
++#define TIMER_FTTMR010_IRQ2         (IRQ_GIC_START + 3)
++#endif
++
++#else /*-------------------------------- GM8220 -------------------------------------*/
++
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0xfe000000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE	  0xfe200000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        (IRQ_GIC_START + 38)
++
++#define UART_FTUART010_1_PA_BASE    0xfe220000
++#define UART_FTUART010_1_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_1_VA_SIZE    SZ_4K
++#define UART_FTUART010_1_IRQ        (IRQ_GIC_START + 39)
++
++#define UART_FTUART010_2_PA_BASE    0xfe240000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_1_VA_BASE + UART_FTUART010_1_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        (IRQ_GIC_START + 43)
++
++#define UART_FTUART010_3_PA_BASE	  0xfe260000
++#define UART_FTUART010_3_VA_BASE    (UART_FTUART010_2_VA_BASE + UART_FTUART010_2_VA_SIZE)
++#define UART_FTUART010_3_VA_SIZE    SZ_4K
++#define UART_FTUART010_3_IRQ        (IRQ_GIC_START + 44)
++
++#define UART_FTUART010_4_PA_BASE    0xfe280000
++#define UART_FTUART010_4_VA_BASE    (UART_FTUART010_3_VA_BASE + UART_FTUART010_3_VA_SIZE)
++#define UART_FTUART010_4_VA_SIZE    SZ_4K
++#define UART_FTUART010_4_IRQ        (IRQ_GIC_START + 45)
++
++#define UART_FTUART010_5_PA_BASE    0xfe2a0000
++#define UART_FTUART010_5_VA_BASE    (UART_FTUART010_4_VA_BASE + UART_FTUART010_4_VA_SIZE)
++#define UART_FTUART010_5_VA_SIZE    SZ_4K
++#define UART_FTUART010_5_IRQ        (IRQ_GIC_START + 46)
++
++#define UART_FTUART010_6_PA_BASE    0xfe2c0000
++#define UART_FTUART010_6_VA_BASE    (UART_FTUART010_5_VA_BASE + UART_FTUART010_5_VA_SIZE)
++#define UART_FTUART010_6_VA_SIZE    SZ_4K
++#define UART_FTUART010_6_IRQ        (IRQ_GIC_START + 47)
++
++#define UART_FTUART010_7_PA_BASE    0xfe2e0000
++#define UART_FTUART010_7_VA_BASE    (UART_FTUART010_6_VA_BASE + UART_FTUART010_6_VA_SIZE)
++#define UART_FTUART010_7_VA_SIZE    SZ_4K
++#define UART_FTUART010_7_IRQ        (IRQ_GIC_START + 48)
++
++/* TIMER */
++#ifdef CONFIG_FTTMR010
++#define TIMER_FTTMR010_PA_BASE	    0xfe8c0000
++#define TIMER_FTTMR010_VA_BASE	    (UART_FTUART010_7_VA_BASE + UART_FTUART010_7_VA_SIZE)
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         (IRQ_GIC_START + 26)
++#define TIMER_FTTMR010_IRQ1         (IRQ_GIC_START + 26)
++#define TIMER_FTTMR010_IRQ2         (IRQ_GIC_START + 26)
++
++#endif
++
++/* TIMER */
++#if 0//def CONFIG_ARMGENERICTIMER
++#define TIMER_ARMGTIMER_PA_BASE	    0xA0547000//???
++#define TIMER_ARMGTIMER_VA_BASE	    (UART_FTUART010_7_VA_BASE + UART_FTUART010_7_VA_SIZE)
++#define TIMER_ARMGTIMER_VA_SIZE	    SZ_4K
++#define TIMER_ARMGTIMER_IRQ         27
++#endif
++
++#endif
++	
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/dma_route.h b/arch/arm/mach-GM-SMP/include/mach/platform/dma_route.h
+new file mode 100644
+index 00000000..4fbf887a
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/dma_route.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
++ *
++ * 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.
++ * 
++ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++#ifndef __DMA_ROUTE_H__
++#define __DMA_ROUTE_H__
++
++/* define AHB DMA routing table 
++ */
++#define AHBDMA_REQ_SSP0_RX  0
++#define AHBDMA_REQ_SSP0_TX  1
++#define AHBDMA_REQ_SSP1_RX  2
++#define AHBDMA_REQ_SSP1_TX  3
++#define AHBDMA_REQ_SSP2_RX  4
++#define AHBDMA_REQ_SSP2_TX  5
++#define AHBDMA_REQ_SDC      6
++#define AHBDMA_REQ_NANDC    9
++#define AHBDMA_REQ_PWMTMR5  12
++#define AHBDMA_REQ_PWMTMR6  13
++#define AHBDMA_REQ_PWMTMR7  14
++#define AHBDMA_REQ_PWMTMR8  15
++
++/* define APB DMA routing table 
++ */
++#define APBDMA_REQ_UART0_RX 1
++#define APBDMA_REQ_UART0_TX 2
++#define APBDMA_REQ_UART1_RX 3
++#define APBDMA_REQ_UART1_TX 4
++#define APBDMA_REQ_UART2_RX 5
++#define APBDMA_REQ_UART2_TX 6
++#define APBDMA_REQ_UART3_RX 7  
++#define APBDMA_REQ_UART3_TX 8
++#define APBDMA_REQ_UART4_RX 9  
++#define APBDMA_REQ_UART4_TX 10
++#define APBDMA_REQ_PWMTMR1  12
++#define APBDMA_REQ_PWMTMR2  13
++#define APBDMA_REQ_PWMTMR3  14
++#define APBDMA_REQ_PWMTMR4  15
++
++
++#endif /* __DMA_ROUTE_H__ */
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/gpio.h b/arch/arm/mach-GM-SMP/include/mach/platform/gpio.h
+new file mode 100644
+index 00000000..c8119e6c
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8220_GPIO_H__
++#define __GM8220_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		2
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8220_GPIO_H__
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/irqs.h b/arch/arm/mach-GM-SMP/include/mach/platform/irqs.h
+new file mode 100644
+index 00000000..01306a9f
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/irqs.h
+@@ -0,0 +1,35 @@
++/*
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 10/06/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/memory.h b/arch/arm/mach-GM-SMP/include/mach/platform/memory.h
+new file mode 100644
+index 00000000..8fcb0d97
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/memory.h
+@@ -0,0 +1,62 @@
++/*
++ *  
++ *  GM Platform Dependent Memory Configuration
++ *  
++ * 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
++ *  
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define PHYS_OFFSET     CPU_MEM_PA_BASE
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management. 
++ *
++ * Users can adjust the memory size based on the real memory size requirement.  
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     0x1000000
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement. 
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE. 
++ * The memory boundary is 16M alginment 
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/platform_io.h b/arch/arm/mach-GM-SMP/include/mach/platform/platform_io.h
+new file mode 100644
+index 00000000..94adbeb2
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/platform_io.h
+@@ -0,0 +1,643 @@
++/*
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++#define IRQ_LOCALTIMER          29
++#define IRQ_LOCALWDOG           30
++#define PLATFORM_LEGACY_IRQ     31
++#define IRQ_GIC_START           32
++
++#define PLATFORM_IRQ_TOTALCOUNT	(IRQ_GIC_START + 128)
++#define PLATFORM_INTERRUPTS     PLATFORM_IRQ_TOTALCOUNT
++#define CPU_MEM_PA_BASE         0x0     /* the memory physical start address(DDR) */
++
++#ifdef CONFIG_FPGA/*==================================== FPGA ================================================*/
++
++#define IRQ_CA7_PMU_CPU0	(IRQ_GIC_START + 64)
++#define IRQ_CA7_PMU_CPU1	(IRQ_GIC_START + 65)
++#define IRQ_CA7_PMU_CPU2	(IRQ_GIC_START + 66)
++#define IRQ_CA7_PMU_CPU3	(IRQ_GIC_START + 67)
++
++/*
++ * currently, only IRQ 0 ~ 5 is available on HAPS
++ */
++/*
++#define IRQ_HAPS_FTUART010_1	(IRQ_HAPS_START + 6)
++#define IRQ_HAPS_FTDMAC030_0_TC	(IRQ_HAPS_START + 10)
++#define IRQ_HAPS_FTDMAC030_0_INT	(IRQ_HAPS_START + 11)
++#define IRQ_HAPS_FTDMAC030_0_ERR	(IRQ_HAPS_START + 12)
++
++#define PLATFORM_FIQ_BASE       0
++*/
++
++#define PLATFORM_GIC_PA_BASE       0xf0000000
++/*
++#define PLATFORM_GIC_VA_BASE       0xfa900000
++
++#define PLATFORM_GIC_DIST_PA_BASE	(PLATFORM_GIC_PA_BASE + 0x1000)
++#define PLATFORM_GIC_DIST_VA_BASE	(PLATFORM_GIC_VA_BASE + 0x1000)
++#define PLATFORM_GIC_CPU_PA_BASE	(PLATFORM_GIC_PA_BASE + 0x2000)
++#define PLATFORM_GIC_CPU_VA_BASE	(PLATFORM_GIC_VA_BASE + 0x2000)
++
++
++
++#define HAPS_FTUART010_0_PA_BASE	0xa0800000
++#define HAPS_FTUART010_1_PA_BASE	0xa0900000
++#define HAPS_FTTMR010_0_PA_BASE		0xa0a00000
++#define HAPS_FTINTC030_0_PA_BASE	0xa0b00000
++
++#define HAPS_FTDMAC030_0_PA_BASE	0xa0200000
++
++#define HAPS_FTUART010_0_VA_BASE	0xfa800000
++#define HAPS_FTUART010_1_VA_BASE	0xfa810000
++#define HAPS_FTTMR010_0_VA_BASE		0xfa820000
++#define HAPS_FTINTC030_0_VA_BASE	0xfa830000
++
++#define HAPS_FTGMAC030_0_PA_BASE	0xa0400000
++#define HAPS_FTGMAC030_0_VA_BASE	0xfa840000
++*/
++#define MAC_FTGMAC030_IRQ_COUNT	1
++#define MAC_FTGMAC030_IRQ	(IRQ_GIC_START + 5)
++#define MAC_FTGMAC030_0_IRQ	(IRQ_GIC_START + 5)
++
++#define MAC_FTGMAC030_PA_COUNT	1
++#define MAC_FTGMAC030_PA_BASE	0xa0400000
++#define MAC_FTGMAC030_PA_LIMIT	0xa0400FFF
++#define MAC_FTGMAC030_PA_SIZE	0x00001000
++#define MAC_FTGMAC030_0_PA_BASE	0xa0400000
++#define MAC_FTGMAC030_0_PA_LIMIT	0xa0400FFF
++#define MAC_FTGMAC030_0_PA_SIZE	0x00001000
++
++#define HAPS_SRAM_0_PA_BASE		0x90000000
++#define HAPS_SRAM_0_VA_BASE		0xfa850000
++#define SYS_FLAGSS_BASE			HAPS_SRAM_0_VA_BASE
++#define SYS_FLAGSS_OFFSET		0x50    /* record CPU boot address => SYS_FLAGSS_BASE + SYS_FLAGSS_OFFSET */
++/*
++#define DEBUG_LL_FTUART010_PA_BASE	HAPS_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE	HAPS_FTUART010_0_VA_BASE
++*/
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x90E00000
++#define WDT_FTWDT010_PA_LIMIT	0x90E00FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x90E00000
++#define WDT_FTWDT010_0_PA_LIMIT	0x90E00FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++#else/*======================================== GM8220 ============================================*/
++/*
++ * Component counts
++ */
++
++#define IRQ_CA7_PMU_CPU0	(IRQ_GIC_START + 100)
++#define IRQ_CA7_PMU_CPU1	(IRQ_GIC_START + 101)
++#define IRQ_CA7_PMU_CPU2	(IRQ_GIC_START + 102)
++#define IRQ_CA7_PMU_CPU3	(IRQ_GIC_START + 103)
++
++#define PLATFORM_GIC_PA_BASE       0xF9C00000
++
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	7
++#define GPIO_FTGPIO010_COUNT	7
++/* I2C */
++#define I2C_COUNT	6
++#define I2C_FTI2C010_COUNT	6
++/* SSP */
++#define SSP_COUNT	2
++#define SSP_FTSSP010_COUNT	2
++/* SPI020 */
++#define SPI_COUNT	1
++#define SPI_FTSPI020_COUNT	1
++/* SDC */
++#define SDC_COUNT	1
++#define SDC_FTSDC021_COUNT	1
++/* USB */
++#define USB_COUNT       2
++#define USB_FOTG2XX_COUNT       2
++/* LCD */
++#define LCD_COUNT	1
++#define LCD_FTLCDC200_COUNT	1
++/* MAC */
++#define MAC_COUNT	2
++#define MAC_FTGMAC030_COUNT	2
++/* TVE */
++#define TVE_COUNT	1
++#define TVE_FTTVE100_COUNT	1
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* 2D GRAPHIC */
++#define GRA_COUNT	2
++#define GRA_FT2DGRA_COUNT	2
++/* CAP */
++#define CAP_COUNT	2
++#define CAP_FTCAP300_COUNT	2
++/* H264E */
++#define H264E_COUNT	4
++#define H264E_FTMCP280_COUNT	4
++/* H264D */
++#define H264D_COUNT	4
++#define H264D_FTMCP300_COUNT	4
++/* MCP */
++#define MCP_COUNT	2
++#define MCP_FTMCP100_COUNT	2
++/* SATA */
++#define SATA_COUNT	4
++#define SATA_FTSATA100_COUNT	4
++/* DMAC */
++#define DMAC_COUNT	1
++#define DMAC_FTDMAC020_COUNT	1
++/* XDMAC */
++#define XDMAC_COUNT	2
++#define XDMAC_FTDMAC030_COUNT	2
++/* IR_DET */
++#define IR_DET_COUNT	1
++#define IR_DET_FTIRDET_COUNT	1
++/* KEYSCAN */
++#define KEYSCAN_COUNT	1
++#define KEYSCAN_FTKEYSCAN_COUNT	1
++/* HDMI */
++#define HDMI_COUNT	1
++#define HDMI_FTHDMI_COUNT	1
++
++/*
++ * Interrrupt numbers
++ */
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	(IRQ_GIC_START + 68)
++#define WDT_FTWDT010_0_IRQ	(IRQ_GIC_START + 68)
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	1
++#define GPIO_FTGPIO010_IRQ	(IRQ_GIC_START + 55)
++#define GPIO_FTGPIO010_0_IRQ	(IRQ_GIC_START + 55)
++#define GPIO_FTGPIO010_1_IRQ	(IRQ_GIC_START + 89)
++#define GPIO_FTGPIO010_2_IRQ	(IRQ_GIC_START + 90)
++#define GPIO_FTGPIO010_3_IRQ	(IRQ_GIC_START + 91)
++#define GPIO_FTGPIO010_4_IRQ	(IRQ_GIC_START + 92)
++#define GPIO_FTGPIO010_5_IRQ	(IRQ_GIC_START + 93)
++#define GPIO_FTGPIO010_6_IRQ	(IRQ_GIC_START + 94)
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	(IRQ_GIC_START + 49)
++#define I2C_FTI2C010_0_IRQ	(IRQ_GIC_START + 49)
++#define I2C_FTI2C010_1_IRQ	(IRQ_GIC_START + 50)
++#define I2C_FTI2C010_2_IRQ	(IRQ_GIC_START + 51)
++#define I2C_FTI2C010_3_IRQ	(IRQ_GIC_START + 52)
++#define I2C_FTI2C010_4_IRQ	(IRQ_GIC_START + 53)
++#define I2C_FTI2C010_5_IRQ	(IRQ_GIC_START + 54)
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	(IRQ_GIC_START + 67)
++#define SSP_FTSSP010_0_IRQ	(IRQ_GIC_START + 67)
++#define SSP_FTSSP010_1_IRQ	(IRQ_GIC_START + 69)
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	(IRQ_GIC_START + 44)
++#define SPI_FTSPI020_0_IRQ	(IRQ_GIC_START + 44)
++
++/* SDC */
++#define SDC_FTSDC021_IRQ_COUNT	1
++#define SDC_FTSDC021_IRQ	(IRQ_GIC_START + 40)
++#define SDC_FTSDC021_0_IRQ	(IRQ_GIC_START + 40)
++
++/* USB */
++#define USB_FOTG2XX_IRQ_COUNT	1
++#define USB_FOTG2XX_IRQ		(IRQ_GIC_START + 34)
++#define USB_FOTG2XX_0_IRQ	(IRQ_GIC_START + 34)
++#define USB_FOTG2XX_1_IRQ	(IRQ_GIC_START + 35)
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	(IRQ_GIC_START + 15)
++#define LCD_FTLCDC200_0_IRQ	(IRQ_GIC_START + 15)
++
++/* MAC */
++#define MAC_FTGMAC030_IRQ_COUNT	2
++#define MAC_FTGMAC030_IRQ	(IRQ_GIC_START + 16)
++#define MAC_FTGMAC030_0_IRQ	(IRQ_GIC_START + 16)
++#define MAC_FTGMAC030_1_IRQ	(IRQ_GIC_START + 17)
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	(IRQ_GIC_START + 64)
++#define AES_FTAES020_0_IRQ	(IRQ_GIC_START + 64)
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_IRQ_COUNT	2
++#define GRA_FT2DGRA_IRQ	(IRQ_GIC_START + 28)
++#define GRA_FT2DGRA_0_IRQ	(IRQ_GIC_START + 28)
++#define GRA_FT2DGRA_0_IRQ	(IRQ_GIC_START + 14)
++
++/* CAP */
++#define CAP_FTCAP300_IRQ_COUNT	2
++#define CAP_FTCAP300_IRQ	(IRQ_GIC_START + 0)
++#define CAP_FTCAP300_0_IRQ	(IRQ_GIC_START + 0)
++#define CAP_FTCAP300_1_IRQ	(IRQ_GIC_START + 1)
++
++/* H264E */
++#define H264E_FTMCP280_IRQ_COUNT	4
++#define H264E_FTMCP280_IRQ	(IRQ_GIC_START + 5)
++#define H264E_FTMCP280_0_IRQ	(IRQ_GIC_START + 5)
++#define H264E_FTMCP280_1_IRQ	(IRQ_GIC_START + 6)
++#define H264E_FTMCP280_2_IRQ	(IRQ_GIC_START + 7)
++#define H264E_FTMCP280_3_IRQ	(IRQ_GIC_START + 8)
++
++/* H264D */
++#define H264D_FTMCP300_IRQ_COUNT	4
++#define H264D_FTMCP300_IRQ	(IRQ_GIC_START + 9)
++#define H264D_FTMCP300_0_IRQ	(IRQ_GIC_START + 9)
++#define H264D_FTMCP300_1_IRQ	(IRQ_GIC_START + 10)
++#define H264D_FTMCP300_2_IRQ	(IRQ_GIC_START + 11)
++#define H264D_FTMCP300_3_IRQ	(IRQ_GIC_START + 12)
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	2
++#define MCP_FTMCP100_IRQ	(IRQ_GIC_START + 32)
++#define MCP_FTMCP100_0_IRQ	(IRQ_GIC_START + 32)
++#define MCP_FTMCP100_1_IRQ	(IRQ_GIC_START + 33)
++
++/* SATA */
++#define SATA_FTSATA100_IRQ_COUNT	1
++#define SATA_FTSATA100_IRQ	(IRQ_GIC_START + 20)
++#define SATA_FTSATA100_0_IRQ	(IRQ_GIC_START + 20)
++#define SATA_FTSATA100_1_IRQ	(IRQ_GIC_START + 21)
++#define SATA_FTSATA100_2_IRQ	(IRQ_GIC_START + 22)
++#define SATA_FTSATA100_3_IRQ	(IRQ_GIC_START + 23)
++
++/* DMAC */
++#define DMAC_FTDMAC020_IRQ_COUNT	1
++#define DMAC_FTDMAC020_IRQ		(IRQ_GIC_START + 37)
++#define DMAC_FTDMAC020_0_IRQ	(IRQ_GIC_START + 37)
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_IRQ_COUNT	2
++#define XDMAC_FTDMAC030_IRQ		(IRQ_GIC_START + 18)
++#define XDMAC_FTDMAC030_0_IRQ	(IRQ_GIC_START + 18)
++#define XDMAC_FTDMAC030_1_IRQ   (IRQ_GIC_START + 19)
++
++/* IR_DET */
++#define IR_DET_FTIRDET_IRQ_COUNT	1
++#define IR_DET_FTIRDET_IRQ		(IRQ_GIC_START + 65)
++#define IR_DET_FTIRDET_0_IRQ	(IRQ_GIC_START + 65)
++
++/* KEYSCAN */
++#define KEYSCAN_FTKEYSCAN_IRQ_COUNT     1
++#define KEYSCAN_FTKEYSCAN_IRQ           (IRQ_GIC_START + 66)
++#define KEYSCAN_FTKEYSCAN_0_IRQ         (IRQ_GIC_START + 66)
++
++/* HDMI */
++//#define HDMI_FTHDMI_IRQ_COUNT	1
++//#define HDMI_FTHDMI_IRQ		(PLATFORM_GM8312_IRQ_BASE + 8)
++//#define HDMI_FTHDMI_0_IRQ	(PLATFORM_GM8312_IRQ_BASE + 8)
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_IRQ_COUNT    1
++#define DMAC_FTDMAC020_IRQ  (IRQ_GIC_START + 37)
++#define DMAC_FTDMAC020_0_IRQ		(IRQ_GIC_START + 37)
++
++/*
++ * Base addresses
++ */
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0xFE8A0000
++#define WDT_FTWDT010_PA_LIMIT	0xFE8A0FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0xFE8A0000
++#define WDT_FTWDT010_0_PA_LIMIT	0xFE8A0FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	1
++#define GPIO_FTGPIO010_PA_BASE	0xFE400000
++#define GPIO_FTGPIO010_PA_LIMIT	0xFE400FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0xFE400000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0xFE400FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0xFE420000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0xFE420FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_2_PA_BASE	0xFE440000
++#define GPIO_FTGPIO010_2_PA_LIMIT	0xFE440FFF
++#define GPIO_FTGPIO010_2_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_3_PA_BASE	0xFE460000
++#define GPIO_FTGPIO010_3_PA_LIMIT	0xFE460FFF
++#define GPIO_FTGPIO010_3_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_4_PA_BASE	0xFE480000
++#define GPIO_FTGPIO010_4_PA_LIMIT	0xFE480FFF
++#define GPIO_FTGPIO010_4_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_5_PA_BASE	0xFE4A0000
++#define GPIO_FTGPIO010_5_PA_LIMIT	0xFE4A0FFF
++#define GPIO_FTGPIO010_5_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_6_PA_BASE	0xFE4C0000
++#define GPIO_FTGPIO010_6_PA_LIMIT	0xFE4C0FFF
++#define GPIO_FTGPIO010_6_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0xFE300000
++#define I2C_FTI2C010_PA_LIMIT	0xFE300FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0xFE320000
++#define I2C_FTI2C010_0_PA_LIMIT	0xFE320FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_FTI2C010_1_PA_BASE	0xFE340000
++#define I2C_FTI2C010_1_PA_LIMIT	0xFE340FFF
++#define I2C_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_FTI2C010_2_PA_BASE	0xFE360000
++#define I2C_FTI2C010_2_PA_LIMIT	0xFE360FFF
++#define I2C_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_FTI2C010_3_PA_BASE	0xFE380000
++#define I2C_FTI2C010_3_PA_LIMIT	0xFE380FFF
++#define I2C_FTI2C010_3_PA_SIZE	0x00001000
++#define I2C_FTI2C010_4_PA_BASE	0xFE3A0000
++#define I2C_FTI2C010_4_PA_LIMIT	0xFE3A0FFF
++#define I2C_FTI2C010_4_PA_SIZE	0x00001000
++
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0xFE3C0000
++#define SSP_FTSSP010_PA_LIMIT	0xFE3C0FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0xFE3C0000
++#define SSP_FTSSP010_0_PA_LIMIT	0xFE3C0FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0xFE3E0000
++#define SSP_FTSSP010_1_PA_LIMIT	0xFE3E0FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++
++/* SPI */
++#define SPI_FTSPI020_PA_COUNT	1
++#define SPI_FTSPI020_PA_BASE	0xFA700000
++#define SPI_FTSPI020_PA_LIMIT	0xFA700FFF
++#define SPI_FTSPI020_PA_SIZE	0x00001000
++#define SPI_FTSPI020_0_PA_BASE	0xFA700000
++#define SPI_FTSPI020_0_PA_LIMIT	0xFA700FFF
++#define SPI_FTSPI020_0_PA_SIZE	0x00001000
++
++/* SDC */
++#define SDC_FTSDC021_PA_COUNT	1
++#define SDC_FTSDC021_PA_BASE	0xFA600000
++#define SDC_FTSDC021_PA_LIMIT	0xFA600FFF
++#define SDC_FTSDC021_PA_SIZE	0x00001000
++#define SDC_FTSDC021_0_PA_BASE	0xFA600000
++#define SDC_FTSDC021_0_PA_LIMIT	0xFA600FFF
++#define SDC_FTSDC021_0_PA_SIZE	0x00001000
++
++/* USB */
++#define USB_FOTG2XX_PA_COUNT	1
++#define USB_FOTG2XX_PA_BASE	0xF9300000
++#define USB_FOTG2XX_PA_LIMIT	0xF9300FFF
++#define USB_FOTG2XX_PA_SIZE	0x00001000
++#define USB_FOTG2XX_0_PA_BASE	0xF9300000
++#define USB_FOTG2XX_0_PA_LIMIT	0xF9300FFF
++#define USB_FOTG2XX_0_PA_SIZE	0x00001000
++#define USB_FOTG2XX_1_PA_BASE	0xF9400000
++#define USB_FOTG2XX_1_PA_LIMIT	0xF9400FFF
++#define USB_FOTG2XX_1_PA_SIZE	0x00001000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	1
++#define LCD_FTLCDC200_PA_BASE	0xFD900000
++#define LCD_FTLCDC200_PA_LIMIT	0xFD90CFFF
++#define LCD_FTLCDC200_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	0xFD900000
++#define LCD_FTLCDC200_0_PA_LIMIT	0xFD90CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	0x0000D000
++
++/* MAC */
++#define MAC_FTGMAC030_PA_COUNT	1
++#define MAC_FTGMAC030_PA_BASE	0xFCC00000
++#define MAC_FTGMAC030_PA_LIMIT	0xFCC00FFF
++#define MAC_FTGMAC030_PA_SIZE	0x00001000
++#define MAC_FTGMAC030_0_PA_BASE	0xFCC00000
++#define MAC_FTGMAC030_0_PA_LIMIT	0xFCC00FFF
++#define MAC_FTGMAC030_0_PA_SIZE	0x00001000
++#define MAC_FTGMAC030_1_PA_BASE	0xFCD00000
++#define MAC_FTGMAC030_1_PA_LIMIT	0xFCD00FFF
++#define MAC_FTGMAC030_1_PA_SIZE	0x00001000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT	1
++#define TVE_FTTVE100_PA_BASE	0xFBF00000
++#define TVE_FTTVE100_PA_LIMIT	0xFBF00FFF
++#define TVE_FTTVE100_PA_SIZE	0x00001000
++#define TVE_FTTVE100_0_PA_BASE	0xFBF00000
++#define TVE_FTTVE100_0_PA_LIMIT	0xFBF00FFF
++#define TVE_FTTVE100_0_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0xFA400000
++#define AES_FTAES020_PA_LIMIT	0xFA400FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0xFA400000
++#define AES_FTAES020_0_PA_LIMIT	0xFA400FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_PA_COUNT	2
++#define GRA_FT2DGRA_PA_BASE	0xFB800000
++#define GRA_FT2DGRA_PA_LIMIT	0xFB800FFF
++#define GRA_FT2DGRA_PA_SIZE	0x00001000
++#define GRA_FT2DGRA_0_PA_BASE	0xFB800000
++#define GRA_FT2DGRA_0_PA_LIMIT	0xFB800FFF
++#define GRA_FT2DGRA_0_PA_SIZE	0x00001000
++#define GRA_FT2DGRA_1_PA_BASE	0xFB900000
++#define GRA_FT2DGRA_1_PA_LIMIT	0xFB900FFF
++#define GRA_FT2DGRA_1_PA_SIZE	0x00001000
++
++/* CAP */
++#define CAP_FTCAP300_PA_COUNT	1
++#define CAP_FTCAP300_PA_BASE	0xF9100000
++#define CAP_FTCAP300_PA_LIMIT	0xF9100FFF
++#define CAP_FTCAP300_PA_SIZE	0x00001000
++#define CAP_FTCAP300_0_PA_BASE	0xF9100000
++#define CAP_FTCAP300_0_PA_LIMIT	0xF9100FFF
++#define CAP_FTCAP300_0_PA_SIZE	0x00001000
++#define CAP_FTCAP300_1_PA_BASE	0xF9200000
++#define CAP_FTCAP300_1_PA_LIMIT	0xF9200FFF
++#define CAP_FTCAP300_1_PA_SIZE	0x00001000
++
++/* H264E */
++#define H264E_FTMCP280_PA_COUNT	1
++#define H264E_FTMCP280_PA_BASE	0xFA800000
++#define H264E_FTMCP280_PA_LIMIT	0xFA800FFF
++#define H264E_FTMCP280_PA_SIZE	0x00001000
++#define H264E_FTMCP280_0_PA_BASE	0xFA800000
++#define H264E_FTMCP280_0_PA_LIMIT	0xFA800FFF
++#define H264E_FTMCP280_0_PA_SIZE	0x00001000
++#define H264E_FTMCP280_1_PA_BASE	0xFAA00000
++#define H264E_FTMCP280_1_PA_LIMIT	0xFAA00FFF
++#define H264E_FTMCP280_1_PA_SIZE	0x00001000
++#define H264E_FTMCP280_2_PA_BASE	0xFAC00000
++#define H264E_FTMCP280_2_PA_LIMIT	0xFAC00FFF
++#define H264E_FTMCP280_2_PA_SIZE	0x00001000
++#define H264E_FTMCP280_3_PA_BASE	0xFAE00000
++#define H264E_FTMCP280_3_PA_LIMIT	0xFAE00FFF
++#define H264E_FTMCP280_3_PA_SIZE	0x00001000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0xFBB00000
++#define MCP_FTMCP100_PA_LIMIT	0xFBBFFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_0_PA_BASE	0xFBD00000
++#define MCP_FTMCP100_0_PA_LIMIT	0xFBDFFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++
++/* SATA */
++#define SATA_FTSATA100_PA_COUNT	    4
++#define SATA_FTSATA100_PA_BASE      0xF9800000
++#define SATA_FTSATA100_PA_LIMIT     0xF9800FFF
++#define SATA_FTSATA100_PA_SIZE      0x00001000
++#define SATA_FTSATA100_0_PA_BASE    0xF9800000
++#define SATA_FTSATA100_0_PA_LIMIT   0xF9800FFF
++#define SATA_FTSATA100_0_PA_SIZE    0x00001000
++#define SATA_FTSATA100_1_PA_BASE    0xF9600000
++#define SATA_FTSATA100_1_PA_LIMIT   0xF9600FFF
++#define SATA_FTSATA100_1_PA_SIZE    0x00001000
++#define SATA_FTSATA100_2_PA_BASE    0xF9700000
++#define SATA_FTSATA100_2_PA_LIMIT   0xF9700FFF
++#define SATA_FTSATA100_2_PA_SIZE    0x00001000
++#define SATA_FTSATA100_3_PA_BASE    0xF9A00000
++#define SATA_FTSATA100_3_PA_LIMIT   0xF9A00FFF
++#define SATA_FTSATA100_3_PA_SIZE    0x00001000
++
++/* DMAC */
++#define DMAC_FTDMAC020_PA_COUNT		1
++#define DMAC_FTDMAC020_PA_BASE		0xFA500000
++#define DMAC_FTDMAC020_PA_LIMIT		0xFA500FFF
++#define DMAC_FTDMAC020_PA_SIZE		0x00001000
++#define DMAC_FTDMAC020_0_PA_BASE	0xFA500000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0xFA500FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++
++/* XDMAC */
++#define XDMAC_FTDMAC030_PA_COUNT	2
++#define XDMAC_FTDMAC030_PA_BASE		0xFCA00000
++#define XDMAC_FTDMAC030_PA_LIMIT	0xFCA00FFF
++#define XDMAC_FTDMAC030_PA_SIZE		0x00001000
++#define XDMAC_FTDMAC030_0_PA_BASE	0xFCA00000
++#define XDMAC_FTDMAC030_0_PA_LIMIT	0xFCA00FFF
++#define XDMAC_FTDMAC030_0_PA_SIZE	0x00001000
++#define XDMAC_FTDMAC030_1_PA_BASE	0xFCB00000
++#define XDMAC_FTDMAC030_1_PA_LIMIT	0xFCB00FFF
++#define XDMAC_FTDMAC030_1_PA_SIZE	0x00001000
++
++/* IR_DET */
++#define IR_DET_FTIRDET_PA_COUNT	1
++#define IR_DET_FTIRDET_PA_BASE	0xFE540000
++#define IR_DET_FTIRDET_PA_LIMIT	0xFE540FFF
++#define IR_DET_FTIRDET_PA_SIZE	0x00001000
++#define IR_DET_FTIRDET_0_PA_BASE	0xFE540000
++#define IR_DET_FTIRDET_0_PA_LIMIT	0xFE540FFF
++#define IR_DET_FTIRDET_0_PA_SIZE	0x00001000
++
++/* KEYSCAN */
++#define KEYSCAN_FTKEYSCAN_PA_COUNT      1
++#define KEYSCAN_FTKEYSCAN_PA_BASE       0xFE560000
++#define KEYSCAN_FTKEYSCAN_PA_LIMIT      0xFE560FFF
++#define KEYSCAN_FTKEYSCAN_PA_SIZE       0x00001000
++#define KEYSCAN_FTKEYSCAN_0_PA_BASE     0xFE560000
++#define KEYSCAN_FTKEYSCAN_0_PA_LIMIT    0xFE560FFF
++#define KEYSCAN_FTKEYSCAN_0_PA_SIZE     0x00001000
++
++/* HDMI */
++#define HDMI_FTHDMI_PA_COUNT	1
++#define HDMI_FTHDMI_PA_BASE	0xFE6E0000
++#define HDMI_FTHDMI_PA_LIMIT	0xFE6E0FFF
++#define HDMI_FTHDMI_PA_SIZE	0x00001000
++#define HDMI_FTHDMI_0_PA_BASE	0xFE6E0000
++#define HDMI_FTHDMI_0_PA_LIMIT	0xFE6E0FFF
++#define HDMI_FTHDMI_0_PA_SIZE	0x00001000
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_PA_COUNT 1
++#define DMAC_FTDMAC020_PA_BASE  0xFA500000
++#define DMAC_FTDMAC020_PA_LIMIT 0xFA500FFF
++#define DMAC_FTDMAC020_PA_SIZE  0x0001000
++#define DMAC_FTDMAC020_0_PA_BASE	0xFA500000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0xFA500FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++#define PLATFORM_IRQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL1	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL1	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL3	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL3	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL4	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL4	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL5	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL5	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL6	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL6	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL7	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL7	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL8	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL8	0xFFFFFFFF
++
++#endif//====================================================================================
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/pmu.h b/arch/arm/mach-GM-SMP/include/mach/platform/pmu.h
+new file mode 100644
+index 00000000..00e0588a
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/pmu.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++
++
++unsigned int pmu_get_apb_clk(void);
++int platform_check_flash_type(void);
++int platform_spi_four_byte_mode(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/serial.h b/arch/arm/mach-GM-SMP/include/mach/platform/serial.h
+new file mode 100644
+index 00000000..b63bcc64
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/serial.h
+@@ -0,0 +1,96 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 4 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ *  Luke Lee  11/16/2005  Add conditional compilation.
++ */
++
++#ifdef CONFIG_FPGA
++#define CONFIG_UART_CLK			18432000//12000000
++#else
++#define CONFIG_UART_CLK			25000000
++#endif
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#ifdef CONFIG_SERIAL_UART1_IP
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++#else
++#define EXTENDED_UART_1 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART2_IP
++#define EXTENDED_UART_2 \
++     { 0, BASE_BAUD, UART_FTUART010_2_VA_BASE, UART_FTUART010_2_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS2 */
++#else
++#define EXTENDED_UART_2 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1            \
++        EXTENDED_UART_2
++
++/* set uart clock source select to PLL2 divider output / 2 and clock divided value */
++static inline void ft_set_uartclk(void)
++{
++    unsigned int val, pval;
++
++#if 0
++    /* default is already set to pll2out_div2 */
++    val = inl(PMU_FTPMU010_VA_BASE + 0x28);
++    val &= ~(1 << 3);
++    outl(val, PMU_FTPMU010_VA_BASE + 0x28);
++#endif
++    pval = 0;
++    val = inl(PMU_FTPMU010_VA_BASE + 0x70);
++    val = (val & ~(0x3F << 16)) | (pval << 16);
++    outl(val, PMU_FTPMU010_VA_BASE + 0x70);
++}
++
++#define OSCH_FREQ   30000000
++
++/* get UCLK at run time, CONFIG_UART_CLK is omitted */
++static inline unsigned int ft_get_uartclk(void)
++{
++    unsigned int pval, mul, div;
++    static int set_done = 0;
++
++    if (set_done == 0) {
++        ft_set_uartclk();
++        set_done = 1;
++    }
++
++    pval = (inl(PMU_FTPMU010_VA_BASE + 0x70) >> 16) & 0x3F;
++
++    /* uart clock source = PLL2 divider output / 2 */
++    mul = (inl(PMU_FTPMU010_VA_BASE + 0x34) >> 4) & 0x7F;
++    div = (inl(PMU_FTPMU010_VA_BASE + 0x34) >> 11) & 0x1F;
++
++    return (OSCH_FREQ / div * mul) / 2 / (pval + 1);
++}
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/system.h b/arch/arm/mach-GM-SMP/include/mach/platform/system.h
+new file mode 100644
+index 00000000..9174d6c5
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/system.h
+@@ -0,0 +1,77 @@
++/*
++ *
++ *  Faraday Platform Dependent System Definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/22/2005  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++static inline void arch_reset(char mode, const char *cmd)
++{
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++
++    pmuReg_t regRSTArray[] = {
++        /* reg_off, bit_masks, lock_bits,init_val, init_mask */
++        {0xB8, (1<< 10), (1<< 10), 0, (1<< 10)},
++    };
++
++    pmuRegInfo_t rst_clk_info = {
++        "rst_clk",
++        ARRAY_SIZE(regRSTArray),
++        ATTR_TYPE_NONE,
++        regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<15)), (PMU_FTPMU010_VA_BASE + 0x3C));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C));        // reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));        // load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08));   // Magic number
++    writeb(0x03, (wdt_va_base + 0x0C));     // Enable WDT
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/platform/vmalloc.h b/arch/arm/mach-GM-SMP/include/mach/platform/vmalloc.h
+new file mode 100644
+index 00000000..127ef2b8
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/platform/vmalloc.h
+@@ -0,0 +1,35 @@
++/*
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  10/06/2005  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM-SMP/include/mach/serial.h b/arch/arm/mach-GM-SMP/include/mach/serial.h
+new file mode 100644
+index 00000000..8e282348
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/serial.h
+@@ -0,0 +1,64 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/serial.h
++ *  
++ *  Platform Independent UART Console Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * Note
++ *
++ *  The first UART (FTUART010) in the system is used as the console.
++ * 
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ */
++
++#ifndef __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__
++#define __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__
++
++#ifndef __ASSEMBLY__
++
++#include <mach/platform/board.h>
++#include <linux/serial.h>
++/* Include platform *dependent* UART console configuration */
++#include <mach/platform/serial.h>
++
++#ifndef STD_COM_FLAGS
++#define STD_COM_FLAGS  (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
++#endif
++
++#ifndef PLATFORM_MORE_SERIAL_PORTS
++#define PLATFORM_MORE_SERIAL_PORTS
++#endif
++
++#ifndef SERIAL_PORT_DFNS
++     /* UART CLK        PORT                 IRQ                 FLAGS          hub6 io_type iomem_base reg_shift*/
++#define SERIAL_PORT_DFNS	\
++     { 0, BASE_BAUD, UART_FTUART010_0_VA_BASE, UART_FTUART010_0_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS0 */ \
++     PLATFORM_MORE_SERIAL_PORTS
++#endif
++
++/*
++ * We use a 18.432MHz clock rather than typical 1.8432 MHz clock for UART.
++ */
++#define BASE_BAUD       (CONFIG_UART_CLK / 16)
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__ */
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/system.h b/arch/arm/mach-GM-SMP/include/mach/system.h
+new file mode 100644
+index 00000000..20dfbefd
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/system.h
+@@ -0,0 +1,49 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/system.h
++ *  
++ *  Faraday Platform Independent System Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__
++
++/* Include platform *dependent* system definitions */
++#include <mach/platform/system.h>
++
++#include <asm/proc-fns.h>
++#ifndef arch_idle
++static inline void arch_idle(void)
++{
++	cpu_do_idle();
++}
++#endif
++
++#ifndef arch_reset
++extern inline void arch_reset(char mode, const char *cmd)
++{
++	/* NOP */
++}
++#endif
++
++#endif /* __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__ */
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/timex.h b/arch/arm/mach-GM-SMP/include/mach/timex.h
+new file mode 100644
+index 00000000..24672316
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/timex.h
+@@ -0,0 +1,33 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/timex.h
++ *  
++ *  Faraday Platform Independent Clock Tick Rate Definition
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ */
++
++#ifndef __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__
++#define __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__
++
++#define CLOCK_TICK_RATE	CONFIG_CLOCK_TICK_RATE
++
++#endif /* __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__ */
++
+diff --git a/arch/arm/mach-GM-SMP/include/mach/uncompress.h b/arch/arm/mach-GM-SMP/include/mach/uncompress.h
+new file mode 100644
+index 00000000..9766482e
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/include/mach/uncompress.h
+@@ -0,0 +1,51 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/uncompress.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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 <mach/platform/board.h>
++
++#define SERIAL_THR	0x00
++#define SERIAL_LSR	0x14
++#define SERIAL_LSR_THRE	0x20
++
++#define readl(a)	(*(volatile unsigned int *)(a))
++#define writel(v,a)	(*(volatile unsigned int *)(a) = (v))
++
++/*
++ * This does not append a newline
++ */
++static inline void putc(int c)
++{
++	unsigned long base = DEBUG_LL_FTUART010_PA_BASE;
++
++	while ((readl(base + SERIAL_LSR) & SERIAL_LSR_THRE) == 0)
++		barrier();
++
++	writel(c, base + SERIAL_THR);
++}
++
++static inline void flush(void)
++{
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
+diff --git a/arch/arm/mach-GM-SMP/platform-GM8220/Kconfig b/arch/arm/mach-GM-SMP/platform-GM8220/Kconfig
+new file mode 100644
+index 00000000..42ba4daa
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/platform-GM8220/Kconfig
+@@ -0,0 +1,29 @@
++#
++
++#config SYS_CLK
++config CLOCK_TICK_RATE	
++        int "AHB System Clock"
++        default 240000000
++        help
++          Manual setting of AHB clock, must match the jumper setting on
++          the board, or the system time won't be correctly calculated.
++          Notice that even when AUTO_SYS_CLK is ON, this value is still
++          required for adjusting minor time offsets. However, the influence
++          should be within micro-second to nano-second scale.
++
++config PLATFORM_AXIDMA
++	bool "AXI DMA support"
++	default y
++
++config FTINTC030
++	bool "FTINTC030 support"
++	default y if !CPU_HAS_GIC
++
++config FTTMR010
++	bool "FTTMR010 support"
++	default n
++
++config FPGA
++	bool "FPGA Verify"
++	default n
++
+diff --git a/arch/arm/mach-GM-SMP/platform-GM8220/Makefile b/arch/arm/mach-GM-SMP/platform-GM8220/Makefile
+new file mode 100644
+index 00000000..33db255e
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/platform-GM8220/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the GM platform dependent files
++
++# Object file lists.
++
++obj-y		:= board.o pmu.o platform.o
++
++ifeq ($(CONFIG_FTTMR010),y)
++obj-y		+= timer_fixup.o
++endif
+diff --git a/arch/arm/mach-GM-SMP/platform-GM8220/board.c b/arch/arm/mach-GM-SMP/platform-GM8220/board.c
+new file mode 100644
+index 00000000..251cba44
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/platform-GM8220/board.c
+@@ -0,0 +1,282 @@
++/*
++ *  board depdenent initialization
++ *
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/setup.h>
++#include <asm/arch_timer.h>
++#include <mach/platform/board.h>
++#include <mach/platform/pmu.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/system.h>
++//#include <mach/ftintc030.h>
++#include <mach/fttmr010.h>
++//#include <mach/arm_global_timer.h>
++#include <mach/fmem.h>
++#include <linux/dma-mapping.h>
++
++#ifdef CONFIG_CPU_HAS_GIC
++#include <asm/hardware/gic.h>
++#endif
++
++/* External functions and variables declaration
++ */
++extern void platform_devices_init(void);
++
++/* Local variables declaration
++ */
++//void __iomem *ftintc030_base_addr;
++//void __iomem *ftintc030_base_cpu_0_irq_base; //entry-macro.S will reference it
++
++/******************************************************************************
++ * IPs virtual address mapping
++ *****************************************************************************/
++static struct map_desc board_io_desc[] __initdata = {
++    /* PMU */
++    {
++        .virtual	= PMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PMU_FTPMU010_PA_BASE),
++		.length		= PMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* GIC DIST */
++    {    
++        .virtual    = PLATFORM_GIC_DIST_VA_BASE,
++        .pfn        = __phys_to_pfn(PLATFORM_GIC_DIST_PA_BASE),
++        .length     = PLATFORM_GIC_DIST_VA_SIZE,
++        .type       = MT_DEVICE,
++    },
++    { /* GIC CPU */
++        .virtual    = PLATFORM_GIC_CPU_VA_BASE,
++        .pfn        = __phys_to_pfn(PLATFORM_GIC_CPU_PA_BASE),
++        .length     = PLATFORM_GIC_CPU_VA_SIZE,
++        .type       = MT_DEVICE,
++    }, 
++    /* UART0 */
++    {
++        .virtual	= UART_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_0_PA_BASE),
++		.length		= UART_FTUART010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART1 */
++    {
++        .virtual	= UART_FTUART010_1_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_1_PA_BASE),
++		.length		= UART_FTUART010_1_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART2 */
++    {
++        .virtual	= UART_FTUART010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_2_PA_BASE),
++		.length		= UART_FTUART010_2_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#ifndef CONFIG_FPGA
++	/* UART3 */
++    {
++        .virtual	= UART_FTUART010_3_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_3_PA_BASE),
++		.length		= UART_FTUART010_3_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART4 */
++    {
++        .virtual	= UART_FTUART010_4_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_4_PA_BASE),
++		.length		= UART_FTUART010_4_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART5 */
++    {
++        .virtual	= UART_FTUART010_5_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_5_PA_BASE),
++		.length		= UART_FTUART010_5_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++	/* UART6 */
++    {
++        .virtual	= UART_FTUART010_6_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_6_PA_BASE),
++		.length		= UART_FTUART010_6_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART7 */
++    {
++        .virtual	= UART_FTUART010_7_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_7_PA_BASE),
++		.length		= UART_FTUART010_7_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#endif
++#ifdef CONFIG_FTTMR010
++    /* TIMER */
++    {
++        .virtual	= TIMER_FTTMR010_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_PA_BASE),
++		.length		= TIMER_FTTMR010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#endif
++#ifdef CONFIG_FPGA
++    /* SRAM */ //<====================================== for secondary boot
++    {
++        .virtual	= HAPS_SRAM_0_VA_BASE,
++		.pfn		= __phys_to_pfn(HAPS_SRAM_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++    },
++#endif
++};
++
++/* fixup the memory for MACHINE_START. The parameters come from commandline of menuconfig
++ */
++static void __init board_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    fmem_fixup_memory(tag, cmdline, mi);
++}
++
++/* 2. create the iotable for IPs in MACHINE_START
++ */
++static void __init board_map_io(void)
++{
++    iotable_init(&board_io_desc[0], ARRAY_SIZE(board_io_desc));
++
++    /* set the base to pmu module */
++    pmu_earlyinit((void *)PMU_FTPMU010_VA_BASE);
++
++    /* init dma coherent mapping size,
++     * CONSISTENT_DMA_SIZE is defined in memory.h
++     * max allowable dma consistent size is 14M (0xFFE0_0000 - 0xFF00_00000)
++     * set as 12M to avoid unexpected data overlay, NISH_20121015
++     */
++    #ifdef CONSISTENT_DMA_SIZE
++    init_consistent_dma_size(CONSISTENT_DMA_SIZE);
++    #endif
++}
++
++static void __init board_init_irq(void)
++{
++	/*
++	 * initialize primary interrupt controller
++	 */
++    printk("board_init_irq=%d\n", IRQ_LOCALTIMER);
++    gic_init(0, IRQ_LOCALTIMER, __io(PLATFORM_GIC_DIST_VA_BASE), __io(PLATFORM_GIC_CPU_VA_BASE));
++
++#ifdef CONFIG_FTTMR010
++#ifdef CONFIG_FPGA
++    //irq_set_irq_type(IRQ_FTTMR010_0_T, IRQ_TYPE_EDGE_RISING);
++    irq_set_irq_type(IRQ_GIC_START + 0, IRQ_TYPE_EDGE_RISING);
++#endif
++    irq_set_irq_type(TIMER_FTTMR010_IRQ0, IRQ_TYPE_EDGE_RISING);
++    irq_set_irq_type(TIMER_FTTMR010_IRQ1, IRQ_TYPE_EDGE_RISING);
++    irq_set_irq_type(TIMER_FTTMR010_IRQ2, IRQ_TYPE_EDGE_RISING);
++#endif
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++#ifdef CONFIG_FTTMR010
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 1,
++};
++#endif
++
++#ifdef CONFIG_ARM_ARCH_TIMER
++static struct arch_timer arm_arch_timer __initdata = {
++    .res[0] = {
++        .start  = IRQ_LOCALTIMER,
++        .flags  = IORESOURCE_IRQ,
++    },
++	.res[1] = {
++        .start  = IRQ_LOCALWDOG,
++        .flags  = IORESOURCE_IRQ,
++    },
++};
++#endif
++
++static void __init board_sys_timer_init(void)
++{
++    //unsigned int pclk = pmu_get_apb_clk();
++
++#ifdef CONFIG_ARM_ARCH_TIMER
++	printk("arm_arch_timer\n");
++    arch_timer_register(&arm_arch_timer);
++#endif
++
++#ifdef CONFIG_FTTMR010
++    fttmr010_0_clockevent.freq = CLOCK_TICK_RATE;//pclk;
++    fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++    fttmr010_1_clocksource.freq = CLOCK_TICK_RATE;//pclk;
++    fttmr010_clocksource_init(&fttmr010_1_clocksource);
++#endif
++}
++
++struct sys_timer board_sys_timer = {
++	.init	= board_sys_timer_init,
++};
++
++/* board init */
++static void __init board_init_machine(void)
++{
++    int i;
++
++    platform_devices_init();
++
++    /* dump iotable information
++     */
++    for (i = 0; i < ARRAY_SIZE(board_io_desc); i ++) {
++        printk("iotable: VA: 0x%x, PA: 0x%x, Length: %d \n",
++                (u32)board_io_desc[i].virtual,
++                (u32)board_io_desc[i].pfn << PAGE_SHIFT,
++                (u32)board_io_desc[i].length);
++    }
++}
++
++MACHINE_START(GM, BOARD_NAME)
++	.atag_offset	= BOOT_PARAMETER_PA_OFFSET,   //boot command line, after kernel 3.2 change as relative address
++	.map_io		    = board_map_io,
++	.init_irq	    = board_init_irq,
++	.timer		    = &board_sys_timer,
++	.fixup          = board_fixup_memory,
++	.init_machine	= board_init_machine,
++	.restart	= arch_reset,
++#ifdef CONFIG_CPU_HAS_GIC
++    .handle_irq     = gic_handle_irq,
++#endif
++MACHINE_END
+diff --git a/arch/arm/mach-GM-SMP/platform-GM8220/platform.c b/arch/arm/mach-GM-SMP/platform-GM8220/platform.c
+new file mode 100644
+index 00000000..b05971ba
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/platform-GM8220/platform.c
+@@ -0,0 +1,482 @@
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/dma-mapping.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach-types.h>
++#include <asm/pmu.h>
++
++/******************************************************************************
++ * CA7 devices
++ *****************************************************************************/
++#ifdef CONFIG_CPU_CA7
++static struct resource pmu_resources[] = {
++    [0] = {
++            .start          = IRQ_CA7_PMU_CPU0,
++            .flags          = IORESOURCE_IRQ,
++    },
++    [1] = {
++            .start          = IRQ_CA7_PMU_CPU1,
++            .flags          = IORESOURCE_IRQ,
++    },
++    [2] = {
++            .start          = IRQ_CA7_PMU_CPU2,
++            .flags          = IORESOURCE_IRQ,
++    },
++    [3] = {
++            .start          = IRQ_CA7_PMU_CPU3,
++            .flags          = IORESOURCE_IRQ,
++    },
++};
++
++static struct platform_device pmu_device = {
++    .name                   = "arm-pmu",
++    .id                     = ARM_PMU_DEVICE_CPU,
++    .num_resources          = ARRAY_SIZE(pmu_resources),
++    .resource               = pmu_resources,
++};
++#endif
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++#ifdef CONFIG_I2C
++/* i2c:0 */
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start  = I2C_FTI2C010_0_PA_BASE,
++		.end    = I2C_FTI2C010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_0_IRQ,
++		.end	= I2C_FTI2C010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		    = 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++#endif
++/******************************************************************************
++ * OTG devices
++ *****************************************************************************/
++#ifdef CONFIG_USB_SUPPORT
++/* OTG:0 */
++static struct resource fotg210_0_resources[] = {
++	{
++		.start  = USB_FOTG2XX_0_PA_BASE,
++		.end    = USB_FOTG2XX_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_0_IRQ,
++		.end    = USB_FOTG2XX_0_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_0_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_0_device = {
++	.name           = "fotg210",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(fotg210_0_resources),
++	.resource       = fotg210_0_resources,
++	.dev = {
++		.dma_mask = &fotg210_0_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif /* CONFIG_USB_SUPPORT */
++
++/******************************************************************************
++ * SDC devices
++ *****************************************************************************/
++/* FTSDC021 */
++#ifdef CONFIG_MMC_FTSDC021
++static u64 ftsdc021_dmamask = 0xFFFFFFUL;
++#endif
++#if defined(CONFIG_SDC0_IP)
++static struct resource ftsdc021_0_resource[] = {
++	[0] = {
++	       .start = SDC_FTSDC021_PA_BASE,
++	       .end = SDC_FTSDC021_PA_LIMIT,
++	       .flags = IORESOURCE_MEM,
++	       },
++	[1] = {
++	       .start = SDC_FTSDC021_0_IRQ,
++	       .end = SDC_FTSDC021_0_IRQ,
++	       .flags = IORESOURCE_IRQ,
++	       }
++};
++static struct platform_device ftsdc021_0_device = {
++	.name = "ftsdc021",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(ftsdc021_0_resource),
++	.resource = ftsdc021_0_resource,
++	.dev = {
++		.dma_mask = &ftsdc021_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif
++#if defined(CONFIG_SDC1_IP)
++static struct resource ftsdc021_1_resource[] = {
++        [0] = {
++               .start = SDC_FTSDC021_1_PA_BASE,
++               .end = SDC_FTSDC021_1_PA_LIMIT,
++               .flags = IORESOURCE_MEM,
++               },
++        [1] = {
++               .start = SDC_FTSDC021_1_IRQ,
++               .end = SDC_FTSDC021_1_IRQ,
++               .flags = IORESOURCE_IRQ,
++               }
++};
++static struct platform_device ftsdc021_1_device = {
++        .name = "ftsdc021",
++        .id = 1,
++        .num_resources = ARRAY_SIZE(ftsdc021_1_resource),
++        .resource = ftsdc021_1_resource,
++        .dev = {
++                .dma_mask = &ftsdc021_dmamask,
++                .coherent_dma_mask = 0xFFFFFFFF,
++        },
++};
++#endif
++
++/******************************************************************************
++ * GPIO devices
++ *****************************************************************************/
++#ifdef CONFIG_GPIO_FTGPIO010
++/* GPIO 0 */
++static struct resource ftgpio010_0_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_PA_BASE,
++		.end 	= GPIO_FTGPIO010_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_0_IRQ,
++		.end	= GPIO_FTGPIO010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_0_device = {
++	.name	= "ftgpio0",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgpio010_0_resource),
++	.resource	= ftgpio010_0_resource
++};
++
++/* GPIO 1 */
++static struct resource ftgpio010_1_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_1_PA_BASE,
++		.end 	= GPIO_FTGPIO010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_1_IRQ,
++		.end	= GPIO_FTGPIO010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_1_device = {
++	.name	= "ftgpio1",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgpio010_1_resource),
++	.resource	= ftgpio010_1_resource
++};
++
++/* GPIO 2 */
++static struct resource ftgpio010_2_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_2_PA_BASE,
++		.end 	= GPIO_FTGPIO010_2_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_2_IRQ,
++		.end	= GPIO_FTGPIO010_2_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_2_device = {
++	.name	= "ftgpio2",
++	.id		= 2,
++	.num_resources	= ARRAY_SIZE(ftgpio010_2_resource),
++	.resource	= ftgpio010_2_resource
++};
++
++/* GPIO 3 */
++static struct resource ftgpio010_3_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_3_PA_BASE,
++		.end 	= GPIO_FTGPIO010_3_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_3_IRQ,
++		.end	= GPIO_FTGPIO010_3_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_3_device = {
++	.name	= "ftgpio3",
++	.id		= 3,
++	.num_resources	= ARRAY_SIZE(ftgpio010_3_resource),
++	.resource	= ftgpio010_3_resource
++};
++
++/* GPIO 4 */
++static struct resource ftgpio010_4_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_4_PA_BASE,
++		.end 	= GPIO_FTGPIO010_4_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_4_IRQ,
++		.end	= GPIO_FTGPIO010_4_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_4_device = {
++	.name	= "ftgpio4",
++	.id		= 4,
++	.num_resources	= ARRAY_SIZE(ftgpio010_4_resource),
++	.resource	= ftgpio010_4_resource
++};
++
++/* GPIO 5 */
++static struct resource ftgpio010_5_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_5_PA_BASE,
++		.end 	= GPIO_FTGPIO010_5_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_5_IRQ,
++		.end	= GPIO_FTGPIO010_5_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_5_device = {
++	.name	= "ftgpio5",
++	.id		= 5,
++	.num_resources	= ARRAY_SIZE(ftgpio010_5_resource),
++	.resource	= ftgpio010_5_resource
++};
++
++/* GPIO 6 */
++static struct resource ftgpio010_6_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_6_PA_BASE,
++		.end 	= GPIO_FTGPIO010_6_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_6_IRQ,
++		.end	= GPIO_FTGPIO010_6_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_6_device = {
++	.name	= "ftgpio6",
++	.id		= 6,
++	.num_resources	= ARRAY_SIZE(ftgpio010_6_resource),
++	.resource	= ftgpio010_6_resource
++};
++#endif
++
++/******************************************************************************
++ * AHB DMA controllers
++ *****************************************************************************/
++#ifdef CONFIG_FTDMAC020
++static struct resource ftdmac020_0_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_0_PA_BASE,
++		.end	= DMAC_FTDMAC020_0_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_0_IRQ,
++		.end    = DMAC_FTDMAC020_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_0_device = {
++	.name		= "ftdmac020",
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_0_resources),
++	.resource	= ftdmac020_0_resources,
++};
++#endif /* CONFIG_FTDMAC020 */
++
++#ifdef CONFIG_FTDMAC030
++static struct resource ftdmac030_resources[] = {
++	{
++		.start	= XDMAC_FTDMAC030_1_PA_BASE,
++		.end	= XDMAC_FTDMAC030_1_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= XDMAC_FTDMAC030_1_IRQ,
++		.end    = XDMAC_FTDMAC030_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++#define DRV_NAME	"ftdmac030"
++static struct platform_device ftdmac030_device = {
++	.name		= DRV_NAME,
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac030_resources),
++	.resource	= ftdmac030_resources,
++};
++#endif /* CONFIG_FTDMAC030 */
++/******************************************************************************
++ * SPI020 controllers
++ *****************************************************************************/
++#ifdef CONFIG_SPI_FTSPI020
++static struct resource ftspi020_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,     /* Register Base address */
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static u64 ftspi020_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftspi020_device = {
++    .name = "ftspi020",
++    .id = 0,//must match with bus_num
++    .num_resources = ARRAY_SIZE(ftspi020_resource),
++    .resource = ftspi020_resource,
++    .dev = {
++            .dma_mask = &ftspi020_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            },
++};
++#endif /* CONFIG_SPI_FTSPI020 */
++
++#ifdef CONFIG_SPI_FTSSP010
++static struct resource ftssp010_1_resources[] = {
++	{
++		.start	= SSP_FTSSP010_1_PA_BASE,
++		.end	= SSP_FTSSP010_1_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= SSP_FTSSP010_1_IRQ,
++		.end    = SSP_FTSSP010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftssp010_1_device = {
++	.name		= "ssp_spi",
++	.id		    = 1,
++	.num_resources	= ARRAY_SIZE(ftssp010_1_resources),
++	.resource	= ftssp010_1_resources,	
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++};
++
++static struct spi_board_info spi_devs_info[] __initdata = {
++    /* SONY sensor */
++    {
++            .modalias       = "spidev",
++            .max_speed_hz   = 6000000,
++            .bus_num        = 1,    //use controller 1
++            .chip_select    = 0,    //chip select 0
++            .mode = SPI_MODE_3,
++    },
++};
++#endif /* CONFIG_SPI_FTSSP010 */
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/
++static struct platform_device *gm_devices[] __initdata =
++{
++#ifdef CONFIG_CPU_CA7
++    &pmu_device,
++#endif
++#ifdef CONFIG_I2C
++	/* I2C */
++	&ftiic010_0_device,
++#endif
++	/* OTG */
++#ifdef CONFIG_USB_SUPPORT
++	&fotg210_0_device,
++#endif
++#if defined(CONFIG_SDC0_IP)
++    &ftsdc021_0_device,
++#endif
++#if defined(CONFIG_SDC1_IP)
++    &ftsdc021_1_device,
++#endif
++#ifdef CONFIG_GPIO_FTGPIO010
++	/* GPIO */
++	&ftgpio010_0_device,
++	&ftgpio010_1_device,
++	&ftgpio010_2_device,
++	&ftgpio010_3_device,
++	&ftgpio010_4_device,
++	&ftgpio010_5_device,
++	&ftgpio010_6_device,
++#endif
++#ifdef CONFIG_FTDMAC020
++    &ftdmac020_0_device,
++#endif
++#ifdef CONFIG_SPI_FTSPI020
++    &ftspi020_device,
++#endif
++#ifdef CONFIG_SPI_FTSSP010
++    &ftssp010_1_device,
++#endif
++#ifdef CONFIG_FTDMAC030
++    &ftdmac030_device,
++#endif
++};
++
++void __init platform_devices_init(void)
++{
++    /* add platform devices here
++     */
++
++    /* will invoke platform_device_register() to register all platform devices
++     */
++	platform_add_devices(gm_devices, ARRAY_SIZE(gm_devices));
++#ifdef CONFIG_SPI_FTSSP010
++	spi_register_board_info(spi_devs_info, ARRAY_SIZE(spi_devs_info));
++#endif
++}
+diff --git a/arch/arm/mach-GM-SMP/platform-GM8220/pmu.c b/arch/arm/mach-GM-SMP/platform-GM8220/pmu.c
+new file mode 100644
+index 00000000..f3d86978
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/platform-GM8220/pmu.c
+@@ -0,0 +1,533 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++#include <mach/fmem.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++#ifdef CONFIG_GPIO_FTGPIO010
++static int gpio_fd = -1;
++#endif
++static int dmac_fd = -1;
++static int gmac_fd = -1;
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x54, (0xF << 22), (0xF << 22), (0x5 << 22), (0xF << 22)},
++    {0xB8, (0x1 << 7),  (0x1 << 7),  (0x0 << 7),  (0x1 << 7)},
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x68, (0x1 << 6), (0x1 << 6), (0x0 << 6), (0x1 << 6)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++/* MAC
++ */
++static pmuReg_t regGMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x60, (0x3 << 21), (0x3 << 21), (0x3 << 21), (0x3 << 21)},
++    {0x6C, (0x3 << 19), (0x3 << 19), (0x3 << 19), (0x3 << 19)},
++    {0x70, (0x3 << 11), (0x3 << 11), (0x3 << 11), (0x3 << 11)},
++};
++
++static pmuRegInfo_t gmac_clk_info = {
++    "GMAC_CLK",
++    ARRAY_SIZE(regGMACArray),
++    ATTR_TYPE_PLL2,
++    regGMACArray
++};
++
++/* GPIO
++ */
++#ifdef CONFIG_GPIO_FTGPIO010
++static pmuReg_t regGPIOArray[] = {
++	/* reg_off, bit_masks, lock_bits, init_val, init_mask */
++	{0x74, 1 << 3, 1 << 3, 0, 1 << 3}, // FTGPIO010_0
++	{0x74, 1 << 4, 1 << 4, 0, 1 << 4}, // FTGPIO010_1
++	{0x74, 1 << 5, 1 << 5, 0, 1 << 5}, // FTGPIO010_2
++	{0x74, 1 << 6, 1 << 6, 0, 1 << 6}, // FTGPIO010_3
++	{0x74, 1 << 7, 1 << 7, 0, 1 << 7}, // FTGPIO010_4
++	{0x74, 1 << 8, 1 << 8, 0, 1 << 8}, // FTGPIO010_5
++	{0x74, 1 << 9, 1 << 9, 0, 1 << 9}, // FTGPIO010_6
++};
++static pmuRegInfo_t gpio_clk_info = {
++	"gpio_clk",
++	ARRAY_SIZE(regGPIOArray),
++	ATTR_TYPE_NONE,             /* no clock source */
++	regGPIOArray
++};
++#endif
++
++static unsigned int pmu_get_chip(void)
++{
++	unsigned int product = 0x8220;
++
++	return product;
++}
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	pmuver_t pmuver;
++	//unsigned int product;
++
++	/*
++	 * Version ID:
++	 *     81360: 8136
++	 *     81361: 8136 B
++	 */
++	if (!version) {
++	    //product = (ioread32(pmu_base_addr) >> 16) & 0xFFFF;
++	    version = (ioread32(pmu_base_addr) >> 8) & 0xF;
++
++	    printk("IC: GM%x, version: 0x%x \n", pmu_get_chip(), version);
++	}
++
++	switch (version) {
++      case 0x00:
++        pmuver = PMUVER_A;
++        break;
++      case 0x01:
++        pmuver = PMUVER_B;
++        break;
++      default:
++        printk("@@@@@@@@@@@@@@@@@@@@@@@@ CHIP Version: unknown! @@@@@@@@@@@@@@@@@@@@@@@@\n");
++        pmuver = PMUVER_UNKNOWN;
++        break;
++    }
++
++	return (unsigned int)pmuver;
++}
++
++/* 0 for system running NAND, -1 for SPI NOR, 1 for SPI NAND */
++int platform_check_flash_type(void)
++{
++	static unsigned int jmp_data;
++	int ret = 0;
++
++	jmp_data = ioread32(pmu_base_addr + 0x4);
++
++    if (jmp_data & BIT4)
++        ret = -1;
++    else
++        ret = 1;
++
++	return ret;
++}
++
++/* 0: 3 byte, 1: 4 byte */
++int platform_spi_four_byte_mode(void)
++{
++	static unsigned int jmp_data;
++	int ret = 0;
++
++	jmp_data = ioread32(pmu_base_addr + 0x4);
++
++    if (jmp_data & BIT5)
++        ret = 0;
++    else
++        ret = 1;
++
++	return ret;
++}
++
++//format: xxxx_yyyy. xxxx: 8136, yyyy:IC revision
++unsigned int pmu_get_chipversion(void)
++{
++    unsigned int value = (pmu_get_chip() << 16);
++
++    value |= pmu_get_version();
++
++    return value;
++}
++
++uint pmu_read_pll0out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    uint value, n, m, frange;
++
++    value = readl(CONFIG_PMU_BASE + 0x30);
++    frange = (value >> 4) & 0x3;   
++    n = (value >> 16) & 0xF;
++    m = (value >> 8) & 0xF;
++    value = (SYS_CLK * n) / m;
++
++	switch (frange) {
++	  case 0:
++	    value /= 8;
++	    break;
++	  case 1:
++	    value /= 4;
++	    break;
++	  case 2:
++	    value /= 2;
++	    break;
++	  default:
++	    break;
++	}
++
++    return value;
++#endif
++}
++
++uint pmu_read_pll1out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    uint value, n, m, frange;
++
++    value = readl(CONFIG_PMU_BASE + 0x34);
++    n = (value >> 16) & 0xF;
++    m = (value >> 8) & 0xF;
++    value = (pmu_read_pll0out() * n) / m;
++
++    return value;
++#endif
++}
++
++uint pmu_read_pll2out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m, frange;
++
++    value = readl(CONFIG_PMU_BASE + 0x38);
++    frange = (value >> 4) & 0x3;
++    n = (value >> 16) & 0x7F;
++    m = (value >> 8) & 0x1F;
++    value = (SYS_CLK * n) / m;    
++
++	switch (frange) {
++	  case 0:
++	    value /= 8;
++	    break;
++	  case 1:
++	    value /= 4;
++	    break;
++	  case 2:
++	    value /= 2;
++	    break;
++	  default:
++	    break;
++	}
++
++    return value;
++#endif
++}
++
++uint pmu_read_pll3out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m, frange;
++
++    value = readl(CONFIG_PMU_BASE + 0x3C);
++    n = (value >> 16) & 0x7F;
++    m = (value >> 8) & 0x1F;
++	value = (SYS_CLK * n) / m;
++
++    return value;
++#endif
++}
++
++uint pmu_read_pll4out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m, frange;
++
++    value = readl(CONFIG_PMU_BASE + 0x40);
++    n = (value >> 16) & 0x1FF;
++    m = (value >> 8) & 0x1F;
++	value = (SYS_CLK * n) / m;
++
++    return value;
++#endif
++}
++
++uint pmu_read_pll5out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m, frange;
++
++    value = readl(CONFIG_PMU_BASE + 0x44);
++    frange = (value >> 4) & 0x3;
++    n = (value >> 16) & 0x7F;
++    m = (value >> 8) & 0x1F;
++	value = (SYS_CLK * n) / m;
++
++	switch (frange) {
++	  case 0:
++	    value /= 8;
++	    break;
++	  case 1:
++	    value /= 4;
++	    break;
++	  case 2:
++	    value /= 2;
++	    break;
++	  default:
++	    break;
++	}
++
++    return value;
++#endif
++}
++
++uint pmu_read_pll6out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    return 20000000;
++#endif
++}
++
++uint pmu_read_pll7out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m, frange;
++
++    value = readl(CONFIG_PMU_BASE + 0x34);
++    n = (value >> 16) & 0xFF;
++    m = (value >> 8) & 0x1F;
++	value = (SYS_CLK * n) / m;
++
++    return value;
++#endif
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 18) & 0x3;
++
++	switch (value) {
++	  case 0:
++	    value = pmu_read_pll1out() / 3;
++	    break;
++	  case 1:
++	    value = pmu_read_pll2out() / 3;
++	    break;
++	  case 2:case 3:
++	    value = pmu_read_pll2out() / 4;
++	    break;
++	  default:
++	    break;
++	}
++
++    return value;
++#endif
++}
++
++static unsigned int pmu_get_axi0_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 50000000;
++#else
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 20) & 0x3;
++
++	switch (value) {
++	  case 0:
++	    value = pmu_read_pll1out() / 3;
++	    break;
++	  case 1:
++	    value = pmu_read_pll2out() / 3;
++	    break;
++	  case 2:case 3:
++	    value = pmu_read_pll2out() / 4;
++	    break;
++	  default:
++	    break;
++	}
++
++    return value;
++#endif
++}
++
++static unsigned int pmu_get_axi1_clk(void)
++{
++    return pmu_get_axi0_clk();
++}
++
++unsigned int pmu_get_apb_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    return pmu_get_ahb_clk() / 2;
++#endif
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    return pmu_read_pll1out();
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk0",  ATTR_TYPE_AXI0,   0}, pmu_get_axi0_clk},
++    {{"aclk1",  ATTR_TYPE_AXI1,   0}, pmu_get_axi1_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    {{"pclk",   ATTR_TYPE_APB,    0}, pmu_get_apb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll2",   ATTR_TYPE_PLL2,   0}, pmu_read_pll2out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"pll4",   ATTR_TYPE_PLL4,   0}, pmu_read_pll4out},
++    {{"pll5",   ATTR_TYPE_PLL5,   0}, pmu_read_pll5out},
++    {{"pll6",   ATTR_TYPE_PLL6,   0}, pmu_read_pll6out},
++    {{"pll7",   ATTR_TYPE_PLL7,   0}, pmu_read_pll7out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++    {{"chipver", ATTR_TYPE_CHIPVER, 0}, pmu_get_chipversion},
++};
++
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(clock_info); tmp ++) {
++            if (clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (clock_info[tmp].clock_fun) {
++                clock_info[tmp].clock.value = clock_info[tmp].clock_fun();
++                ftpmu010_deregister_attr(&clock_info[tmp].clock);
++                ret = ftpmu010_register_attr(&clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++#ifdef CONFIG_GPIO_FTGPIO010
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++#endif
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++    /* disable MAC clock, wait insmod MAC driver and enable it */
++    gmac_fd = ftpmu010_register_reg(&gmac_clk_info);
++    if (unlikely(gmac_fd < 0)){
++        printk("GMAC registers to PMU fail! \n");
++    }
++    ftpmu010_deregister_reg(gmac_fd);
++        
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM-SMP/platform-GM8220/timer_fixup.c b/arch/arm/mach-GM-SMP/platform-GM8220/timer_fixup.c
+new file mode 100644
+index 00000000..434de659
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/platform-GM8220/timer_fixup.c
+@@ -0,0 +1,126 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/ftpmu010.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/fiq.h>
++#include <mach/platform/board.h>
++
++#define CONFIG_MAX_TICK     0xffffffff
++static int timer_init_ready = 0;
++
++/*
++ * Get the max ms the this timer
++ */
++unsigned int video_gettime_max_ms(void)
++{
++    return (CONFIG_MAX_TICK / APB_CLK_IN) * 1000;
++}
++
++/* calculate the max hz in max_ms
++ */
++unsigned int video_gettime_max_hz(void)
++{
++    unsigned int max_hz;
++    
++    /* calculate the max hz in max_ms */
++    max_hz = (video_gettime_max_ms() * APB_CLK_IN) / 1000;
++    
++    return max_hz;
++}
++
++unsigned int video_gettime_ms(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++unsigned int video_gettime_us(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++/*
++ * Entry Point of this module. It may be declared by arch_initcall section
++ */
++static int __init fixup_timer_init(void)
++{
++    //use timer3, 42s will overflow in AHB clock 200HZ
++    unsigned int ft_apb_clk = APB_CLK_IN;
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++    unsigned int max_tick;
++    
++    if (*(unsigned int *)(timer_base + 0x30) & (0x1 << 6))
++    {
++        printk("Timer3 is alredy been used!\n");
++        return 0;
++    }
++
++    max_tick = video_gettime_max_ms() * (ft_apb_clk / 1000);    //the max hz count in TmxCounter
++    
++    printk("Video Timer(timer3) Max %dms in 0x%x HZ.\n", video_gettime_max_ms(), max_tick);
++    
++    /* the following configuration is for TIMER3 */
++    *(volatile unsigned int *)(timer_base + 0x20) = CONFIG_MAX_TICK - max_tick; //keep the start count in start counter
++    *(volatile unsigned int *)(timer_base + 0x24) = CONFIG_MAX_TICK - max_tick; //reLoad counter
++    *(volatile unsigned int *)(timer_base + 0x38) |= (0x7 << 6);   //IRQ disable
++    *(volatile unsigned int *)(timer_base + 0x30) |= ((0x1 << 6) | (0x1 << 11));    //enable timer3, count up
++    timer_init_ready = 1;
++    
++    return 0;
++}
++
++static void fixup_timer_exit(void)
++{
++    if (timer_init_ready == 1)
++    {
++        unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        *(volatile unsigned int *)(timer_base + 0x30) &= ~(0x1 << 6);//disable timer2, count up
++        timer_init_ready = 0;
++    }
++	printk("%s: cleaning up\n",__func__);
++}
++
++module_init(fixup_timer_init);
++module_exit(fixup_timer_exit);
++
++EXPORT_SYMBOL(video_gettime_ms);
++EXPORT_SYMBOL(video_gettime_us);
++EXPORT_SYMBOL(video_gettime_max_ms);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("FIXUP timer driver");
+diff --git a/arch/arm/mach-GM-SMP/platsmp.c b/arch/arm/mach-GM-SMP/platsmp.c
+new file mode 100644
+index 00000000..9aaf4ce8
+--- /dev/null
++++ b/arch/arm/mach-GM-SMP/platsmp.c
+@@ -0,0 +1,188 @@
++/*
++ *  linux/arch/arm/mach-realview/platsmp.c
++ *
++ *  Copyright (C) 2002 ARM Ltd.
++ *  All Rights Reserved
++ *
++ * 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 <linux/init.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/jiffies.h>
++#include <linux/smp.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++
++#include <asm/cacheflush.h>
++#include <mach/hardware.h>
++#include <asm/hardware/gic.h>
++#include <asm/mach-types.h>
++#include <asm/smp_scu.h>
++#include <asm/smp_plat.h>
++
++//#include <mach/board-a320.h>
++//#include <mach/board-a369.h>
++//#include <mach/board-a380.h>
++//#include <mach/board-haps.h>
++
++//#include "core.h"
++
++extern void platform_secondary_startup(void);
++
++/*
++ * control for which core is the next to come out of the secondary
++ * boot "holding pen"
++ */
++volatile int __cpuinitdata pen_release = -1;
++
++/*
++ * Write pen_release in a way that is guaranteed to be visible to all
++ * observers, irrespective of whether they're taking part in coherency
++ * or not.  This is necessary for the hotplug code to work reliably.
++ */
++static void __cpuinit write_pen_release(int val)
++{
++	pen_release = val;
++	smp_wmb();
++	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
++	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
++}
++
++static void __iomem *scu_base_addr(void)
++{
++#ifdef CONFIG_CPU_CA7
++	return __io(0x0);
++#else
++	return __io(PLATFORM_SCU_VA_BASE);
++#endif
++}
++
++static DEFINE_SPINLOCK(boot_lock);
++
++void __cpuinit platform_secondary_init(unsigned int cpu)
++{
++	/*
++	 * if any interrupts are already enabled for the primary
++	 * core (e.g. timer irq), then they will not have been enabled
++	 * for us: do so
++	 */
++	gic_secondary_init(0);
++
++	/*
++	 * let the primary processor know we're out of the
++	 * pen, then head off into the C entry point
++	 */
++	write_pen_release(-1);
++
++	/*
++	 * Synchronise with the boot thread.
++	 */
++	spin_lock(&boot_lock);
++	spin_unlock(&boot_lock);
++}
++
++int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++	unsigned long timeout;
++
++	/*
++	 * set synchronisation state between this boot processor
++	 * and the secondary one
++	 */
++	spin_lock(&boot_lock);
++
++	/*
++	 * The secondary processor is waiting to be released from
++	 * the holding pen - release it, then wait for it to flag
++	 * that it has been released by resetting pen_release.
++	 *
++	 * Note that "pen_release" is the hardware CPU ID, whereas
++	 * "cpu" is Linux's internal ID.
++	 */
++	write_pen_release(cpu_logical_map(cpu));
++
++	/*
++	 * Send the secondary CPU a soft interrupt, thereby causing
++	 * the boot monitor to read the system wide flags register,
++	 * and branch to the address found there.
++	 */
++	printk("gic_raise_softirq %d\n", cpu);
++	gic_raise_softirq(cpumask_of(cpu), 1);
++
++	timeout = jiffies + (1 * HZ);
++	while (time_before(jiffies, timeout)) {
++		smp_rmb();
++		if (pen_release == -1)
++			break;
++
++		udelay(10);
++	}
++	printk("ok\n");
++
++	/*
++	 * now the secondary core is starting up let it run its
++	 * calibrations, then wait for it to finish
++	 */
++	spin_unlock(&boot_lock);
++
++	return pen_release != -1 ? -ENOSYS : 0;
++}
++
++/*
++ * Initialise the CPU possible map early - this describes the CPUs
++ * which may be present or become present in the system.
++ */
++void __init smp_init_cpus(void)
++{
++	void __iomem *scu_base = scu_base_addr();
++	unsigned int i, ncores;
++
++	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
++#ifdef CONFIG_CPU_CA7
++	/* Read current CP15 Cache Size ID Register */
++	asm volatile ("mrc p15, 1, %0, c9, c0, 2" : "=r" (ncores));
++	ncores = ((ncores >> 24) & 0x3) + 1;
++#endif
++
++	/* sanity check */
++	if (ncores > nr_cpu_ids) {
++		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
++			ncores, nr_cpu_ids);
++		ncores = nr_cpu_ids;
++	}
++
++	for (i = 0; i < ncores; i++)
++		set_cpu_possible(i, true);
++
++	set_smp_cross_call(gic_raise_softirq);
++
++#ifdef CONFIG_ACP
++	/* Always enable SCU if we are using ACP */
++#ifdef CONFIG_CPU_CA9
++	scu_enable(scu_base);
++#endif
++#endif
++}
++
++void __init platform_smp_prepare_cpus(unsigned int max_cpus)
++{
++#ifdef CONFIG_CPU_CA9
++	scu_enable(scu_base_addr());
++#endif
++
++	/*
++	 * Write the address of secondary startup into the
++	 * system-wide flags register. The BootMonitor waits
++	 * until it receives a soft interrupt, and then the
++	 * secondary CPU branches to this address.
++	 */
++#ifdef CONFIG_PLATFORM_A380
++	__raw_writel(1, A380_FTEMC030_0_VA_BASE + 0x3400);
++#endif
++	__raw_writel(virt_to_phys(platform_secondary_startup),
++		     SYS_FLAGSS_BASE + SYS_FLAGSS_OFFSET);
++}
+diff --git a/arch/arm/mach-GM/Kconfig b/arch/arm/mach-GM/Kconfig
+new file mode 100644
+index 00000000..5f4da43c
+--- /dev/null
++++ b/arch/arm/mach-GM/Kconfig
+@@ -0,0 +1,67 @@
++#
++# arch/arm/mach-GM/Kconfig
++#
++
++#
++# GM Platform Types Selection
++#
++choice
++	prompt "Platform Selection"
++	default PLATFORM_GM8126
++	depends on ARCH_GM
++
++
++config PLATFORM_GM8126
++	bool "GM8126 series platform"
++    select FIQ
++    help
++      GM GM8126 is a platform based on GM's ARM9 compatible processor
++
++config PLATFORM_GM8287
++	bool "GM8287 series platform"
++    help
++      GM GM8287 is a platform based on GM's ARM9 compatible processor
++
++config PLATFORM_GM8139
++	bool "GM8139 series platform"
++    help
++      GM GM8139 is a platform based on GM's ARM9 compatible processor
++
++config PLATFORM_GM8136
++	bool "GM8136 series platform"
++    help
++      GM GM8136 is a platform based on GM's ARM9 compatible processor
++
++endchoice
++
++config FORCE_MAX_ZONEORDER
++    int
++    depends on ARCH_GM
++    default "12"
++
++config FTDMAC020
++    tristate "Supports DMAC020 controller"
++    select DMA_ENGINE
++    default y
++
++config FTAPBB020
++    tristate "Supports APB DMA"
++    select DMA_ENGINE
++    default n
++
++
++#
++# Platform dependent options
++#
++menu "GM Platform Options"
++    depends on ARCH_GM
++
++source "arch/arm/mach-GM/platform-GM8126/Kconfig"
++source "arch/arm/mach-GM/platform-GM8287/Kconfig"
++source "arch/arm/mach-GM/platform-GM8139/Kconfig"
++source "arch/arm/mach-GM/platform-GM8136/Kconfig"
++    
++endmenu    
++
++
++
+diff --git a/arch/arm/mach-GM/Makefile b/arch/arm/mach-GM/Makefile
+new file mode 100644
+index 00000000..a777d82f
+--- /dev/null
++++ b/arch/arm/mach-GM/Makefile
+@@ -0,0 +1,52 @@
++#
++# Makefile for the linux kernel.
++
++# obj-y += xxx.o
++obj-y += ftpmu010.o fttmr010.o fmem.o gm_jiffies.o
++obj-$(CONFIG_FTDMAC020) += ftdmac020.o dma_gm.o
++obj-$(CONFIG_FTAPBB020) += ftapbb020.o dma_gm.o
++
++obj-$(CONFIG_PLATFORM_GM8126)   += ftintc010.o
++obj-$(CONFIG_PLATFORM_GM8287)   += ftintc030.o
++obj-$(CONFIG_PLATFORM_GM8139)   += ftintc030.o
++obj-$(CONFIG_PLATFORM_GM8136)   += ftintc030.o
++GM-platform-$(CONFIG_PLATFORM_GM8126)       := platform-GM8126
++GM-platform-$(CONFIG_PLATFORM_GM8287)       := platform-GM8287
++GM-platform-$(CONFIG_PLATFORM_GM8139)       := platform-GM8139
++GM-platform-$(CONFIG_PLATFORM_GM8136)       := platform-GM8136
++
++ifeq ($(CONFIG_CPU_FREQ),y)
++obj-$(CONFIG_PLATFORM_GM8139)		+= cpufreq.o
++obj-$(CONFIG_PLATFORM_GM8136)		+= cpufreq.o
++endif
++
++#
++#Default platform directory set to GM8181
++#TODO: Make this an error, should never happen unless the Kconfig or Makefile is wrong
++#
++ifeq ($(GM-platform-y),)
++GM-platform-y := platform-GM8126
++endif
++
++PLATFORM_DIR   := $(GM-platform-y)
++
++core-y      +=  arch/arm/mach-GM/$(PLATFORM_DIR)/
++
++define create-platform-symlink
++  mkdir -p arch/arm/mach-GM/include/mach;                 \
++  if [ -L $@ ]; then                              \
++    platformlink=`readlink $@`;                     \
++  fi;												\
++  if [ ! -e $@ ] || [ $$platformlink != $(PLATFORM_DIR) ]; then           \
++	 touch arch/arm/mach-GM/include/mach/$(PLATFORM_DIR)/*;      \
++  fi;															\
++  echo '  SYMLINK $@ -> arch/arm/mach-GM/include/mach/$(PLATFORM_DIR)';   \
++  ln -fsn $(PLATFORM_DIR) $@;
++endef
++
++arch/arm/mach-GM/include/mach/platform: FORCE
++	 $(Q)$(create-platform-symlink)
++
++prepare: arch/arm/mach-GM/include/mach/platform	 
++
++
+diff --git a/arch/arm/mach-GM/Makefile.boot b/arch/arm/mach-GM/Makefile.boot
+new file mode 100644
+index 00000000..4b292e3b
+--- /dev/null
++++ b/arch/arm/mach-GM/Makefile.boot
+@@ -0,0 +1,4 @@
++   zreladdr-y	:= 0x00008000
++params_phys-y	:= 0x00000100
++initrd_phys-y	:= 0x00900000
++
+diff --git a/arch/arm/mach-GM/cpufreq.c b/arch/arm/mach-GM/cpufreq.c
+new file mode 100644
+index 00000000..85c5e31f
+--- /dev/null
++++ b/arch/arm/mach-GM/cpufreq.c
+@@ -0,0 +1,232 @@
++/*
++ * linux/arch/arm/mach-GM/cpufreq.c
++ *
++ * Copyright (C) 2014 Grain Media
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/cpufreq.h>
++#include <linux/slab.h>
++#include <mach/ftpmu010.h>
++
++static int cpu_freq_fd;
++static unsigned int cpu_frequency;
++static unsigned int cpu_max_speed;
++
++struct gm_freq_info {
++	unsigned int cpufreq_mhz;
++	unsigned int membus;
++	unsigned int cccr;
++	unsigned int div2;
++};
++
++static struct cpufreq_frequency_table *gm_freq_table;
++
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x14, (0xFFFFFFFF << 0), (0xFFFFFFFF << 0), (0x0 << 0), (0xFFFFFFFF << 0)},   /* AHB clock gate */
++};
++
++static pmuRegInfo_t	pmu_reg_info = {
++    "CPU_Freq",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++static void update_pwm_freq(unsigned int clk)
++{
++	unsigned int value = 0xFFFF;
++
++    if (clk == gm_freq_table[0].frequency)
++        value = 0xFFFF;
++    else if (clk == gm_freq_table[1].frequency)
++        value = 0xAAAA;
++    else if (clk == gm_freq_table[2].frequency)
++        value = 0x1111;
++    else if (clk == gm_freq_table[3].frequency)
++        value = 0x0101;
++    else
++    	printk(KERN_ERR "Not this kind of clock definition\n");
++
++#ifdef CONFIG_PLATFORM_GM8139
++ 	ftpmu010_write_reg(cpu_freq_fd, 0x14, (value << 15), (0xFFFF << 15));
++#else
++ 	ftpmu010_write_reg(cpu_freq_fd, 0x14, (value << 16), (0xFFFF << 16));
++#endif 	
++	ftpmu010_write_reg(cpu_freq_fd, 0x14, (0x3 << 0), (0x3 << 0));
++}
++
++int enter_low_freq(void)
++{
++	unsigned int value = 0x0001, data;
++
++	data = ftpmu010_read_reg(0x14);
++
++#ifdef CONFIG_PLATFORM_GM8139
++	data >>= 15;
++ 	ftpmu010_write_reg(cpu_freq_fd, 0x14, (value << 15), (0xFFFF << 15));
++#else
++	data >>= 16;
++ 	ftpmu010_write_reg(cpu_freq_fd, 0x14, (value << 16), (0xFFFF << 16));
++#endif 	
++	ftpmu010_write_reg(cpu_freq_fd, 0x14, (0x3 << 0), (0x3 << 0));
++
++	return data;
++}
++EXPORT_SYMBOL(enter_low_freq);
++
++void exit_low_freq(int value)
++{
++#ifdef CONFIG_PLATFORM_GM8139
++ 	ftpmu010_write_reg(cpu_freq_fd, 0x14, (value << 15), (0xFFFF << 15));
++#else
++ 	ftpmu010_write_reg(cpu_freq_fd, 0x14, (value << 16), (0xFFFF << 16));
++#endif 	
++	ftpmu010_write_reg(cpu_freq_fd, 0x14, (0x3 << 0), (0x3 << 0));
++}
++EXPORT_SYMBOL(exit_low_freq);
++
++static int gm_cpufreq_verify(struct cpufreq_policy *policy)
++{
++    return cpufreq_frequency_table_verify(policy, gm_freq_table);
++}
++
++static unsigned int gm_cpufreq_get(unsigned int cpu)
++{
++	return cpu_frequency;//REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);, clk_ctrl.pll ? 200000 : 6000; ???
++}
++
++static int gm_cpufreq_set(struct cpufreq_policy *policy,
++			      unsigned int target_freq,
++			      unsigned int relation)
++{
++	struct cpufreq_freqs freqs;
++	int idx;
++
++	if (policy->cpu != 0)
++		return -EINVAL;
++
++	/* Lookup the next frequency */
++	if (cpufreq_frequency_table_target(policy, gm_freq_table,
++				target_freq, relation, &idx))
++		return -EINVAL;
++
++	freqs.old = policy->cur;
++	freqs.new = cpu_frequency = gm_freq_table[idx].frequency;
++	freqs.cpu = policy->cpu;
++#if 0
++	printk(KERN_DEBUG "CPU freq %d to %d MHz%s\n",
++			freqs.old, freqs.new,
++			(freqs.old == freqs.new) ? " (skip)" : "");
++#endif
++	if (freqs.old == target_freq)
++		return 0;
++
++	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
++
++	//local_irq_save(flags);
++	update_pwm_freq(cpu_frequency);
++	//local_irq_restore(flags);
++	
++	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
++
++	return 0;
++}
++
++static int gm_cpufreq_init(struct cpufreq_policy *policy)
++{
++	int ret = -EINVAL;
++	int i, j, num, new_speed;
++	
++	printk(KERN_INFO "GM CPU frequency driver\n");
++
++    cpu_freq_fd = ftpmu010_register_reg(&pmu_reg_info);
++    if (cpu_freq_fd < 0)
++        printk(KERN_ERR "cpu freq register PMU fail");
++
++	/* set default policy and cpuinfo */
++	cpu_max_speed = ftpmu010_get_attr(ATTR_TYPE_CPU) / 1000000;
++	//printk("cpu_speed = %d\n", cpu_max_speed);
++	cpu_frequency = cpu_max_speed;
++	policy->max = policy->cpuinfo.max_freq = cpu_max_speed;
++	
++	if(cpu_max_speed > 700)
++        num = 4;
++	else
++        num = 3;
++
++    gm_freq_table = kzalloc((num + 1) * sizeof(*gm_freq_table), GFP_KERNEL);
++    if (gm_freq_table == NULL)
++    	return -ENOMEM;
++    
++    for (i = 0; i < num; i++) {
++        new_speed = cpu_max_speed;
++        
++        for(j = 0; j < i; j++)
++            new_speed /= 2;
++            
++    	gm_freq_table[i].index = i;
++    	gm_freq_table[i].frequency = new_speed;
++    	//printk("a%d = %d,%d\n", i, gm_freq_table[i].index, gm_freq_table[i].frequency);
++    }
++    		
++	policy->min = policy->cpuinfo.min_freq = 100000;
++	policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
++	policy->cur = policy->min = policy->max;
++	
++	gm_freq_table[num].index = 0;
++	gm_freq_table[num].frequency = CPUFREQ_TABLE_END;
++    
++	ret = cpufreq_frequency_table_cpuinfo(policy, gm_freq_table);
++
++	if (ret) {
++		pr_err("failed to setup frequency table\n");
++		return ret;
++	}
++    cpufreq_frequency_table_get_attr(gm_freq_table, policy->cpu);
++	pr_info("CPUFREQ support for gm initialized\n");
++	return 0;
++}
++
++static int gm_cpufreq_exit(struct cpufreq_policy *policy)
++{
++    cpufreq_frequency_table_put_attr(policy->cpu);
++    
++    return 0;
++}
++
++static struct freq_attr *gm_cpufreq_attr[] = {
++	&cpufreq_freq_attr_scaling_available_freqs,
++	NULL,
++};
++
++static struct cpufreq_driver gm_cpufreq_driver = {	
++	.flags		= CPUFREQ_STICKY,	
++	.verify		= gm_cpufreq_verify,
++	.target		= gm_cpufreq_set,
++	.init		= gm_cpufreq_init,
++	.exit       = gm_cpufreq_exit,
++	.get		= gm_cpufreq_get,
++	.name		= "GM-cpufreq",
++	.attr		= gm_cpufreq_attr,
++};
++
++static int __init cpufreq_init(void)
++{
++	return cpufreq_register_driver(&gm_cpufreq_driver);
++}
++module_init(cpufreq_init);
++
++static void __exit cpufreq_exit(void)
++{
++	cpufreq_unregister_driver(&gm_cpufreq_driver);
++}
++module_exit(cpufreq_exit);
++
++MODULE_DESCRIPTION("CPU frequency scaling driver for GM");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM/dma_gm.c b/arch/arm/mach-GM/dma_gm.c
+new file mode 100644
+index 00000000..ece24fee
+--- /dev/null
++++ b/arch/arm/mach-GM/dma_gm.c
+@@ -0,0 +1,252 @@
++/*
++ * GM DMA memory operation (MEM_TO_MEM)
++ *
++ * Copyright (C) 2012 Faraday Technology Corp.
++ *
++ * Author : Shuao-kai Li <easonli@faraday-tech.com>
++ *
++ * 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; version 2 of the License.
++ */
++#include <linux/dmaengine.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/dma-mapping.h>
++#include <linux/hardirq.h>
++#include <linux/export.h>
++#include <mach/ftapbb020.h>
++#include <mach/ftdmac020.h>
++#ifdef CONFIG_FTDMAC030
++#include <mach/ftdmac030.h>
++#endif
++#include <mach/dma_gm.h>
++
++struct dma_gm {
++	struct dma_chan	*chan;
++	struct dma_async_tx_descriptor *desc;
++//	struct dma_slave_config slave; /* It's useless now */
++	enum dma_status dma_st;
++	dma_cap_mask_t mask;
++	dma_cookie_t cookie;
++	wait_queue_head_t dma_wait_queue;
++};
++
++#define err(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ##args)
++
++static void dma_callback(void *param)
++{
++	struct dma_gm *gm = (struct dma_gm *)param;
++	gm->dma_st = DMA_SUCCESS;
++    wake_up(&gm->dma_wait_queue);
++}
++
++static void dma_wait(struct dma_gm *gm)
++{
++	int status;
++
++    status = wait_event_timeout(gm->dma_wait_queue,
++						gm->dma_st == DMA_SUCCESS,
++						60 * HZ);
++	if (status == 0) {
++		err("Timeout in DMA\n");
++	}
++}
++
++int dma_memcpy(enum dma_kind style, dma_addr_t dest, dma_addr_t src, size_t len)
++{
++	struct dma_gm gm_chan;
++	int ret = 0, flag = 0;
++
++	if (in_interrupt())
++		panic("Fatal exception in interrupt");
++
++	memset(&gm_chan, 0, sizeof(gm_chan));
++	init_waitqueue_head(&gm_chan.dma_wait_queue);
++	dma_cap_zero(gm_chan.mask);
++	dma_cap_set(DMA_MEMCPY, gm_chan.mask);
++
++	switch (style) {
++#if defined(CONFIG_FTAPBB020)
++		case APB_DMA:
++		{
++			struct ftapbb020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.common.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			slave.common.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftapbb020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC020)
++		case AHB_DMA:
++		{
++			struct ftdmac020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.handshake = -1;
++
++			/* Use BUS 1 for shared cpu bus loading */
++			slave.src_sel = 1;
++			slave.dst_sel = 1;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC030)
++		case AXI_DMA:
++		{
++			struct ftdmac030_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.handshake = -1;
++
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac030_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++		default:
++			err("No such DMA bus\n");
++			return -ENXIO;
++		break;
++	}
++
++	/* filter fn has already set dma_slave_config. */
++	//dmaengine_slave_config(gm_chan.chan, &gm_chan.slave);
++
++	flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	gm_chan.desc = dmaengine_prep_dma_memcpy(gm_chan.chan, dest, src, len, flag);
++	if (!gm_chan.desc) {
++		err("Set DMA failed!!\n");
++		ret = -EIO;
++		goto fail;
++	}
++	gm_chan.cookie = dmaengine_submit(gm_chan.desc);
++	if (dma_submit_error(gm_chan.cookie)) {
++		err("DMA submit failed\n");
++		dmaengine_terminate_all(gm_chan.chan);
++		ret = -EIO;
++		goto fail;
++	}
++	gm_chan.desc->callback = dma_callback;
++	gm_chan.desc->callback_param = &gm_chan;
++	gm_chan.dma_st = DMA_IN_PROGRESS;
++	dma_async_issue_pending(gm_chan.chan);
++	dma_wait(&gm_chan);
++fail:
++	dma_release_channel(gm_chan.chan);
++	return ret;
++}
++EXPORT_SYMBOL(dma_memcpy);
++
++int dma_memset(enum dma_kind style, dma_addr_t dest, int value, size_t len)
++{
++	struct dma_gm gm_chan;
++	int ret = 0, flag = 0;
++
++	if (in_interrupt())
++		panic("Fatal exception in interrupt");
++
++	memset(&gm_chan, 0, sizeof(gm_chan));
++	init_waitqueue_head(&gm_chan.dma_wait_queue);
++	dma_cap_zero(gm_chan.mask);
++	dma_cap_set(DMA_MEMSET, gm_chan.mask);
++
++	switch (style) {
++#if defined(CONFIG_FTAPBB020)
++		case APB_DMA:
++		{
++			struct ftapbb020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.common.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			slave.common.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftapbb020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC020)
++		case AHB_DMA:
++		{
++			struct ftdmac020_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.id = 0;
++			slave.handshake = -1;
++
++			/* Use BUS 1 for shared cpu bus loading */
++			slave.src_sel = 1;
++			slave.dst_sel = 1;
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac020_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++#if defined(CONFIG_FTDMAC030)
++		case AXI_DMA:
++		{
++			struct ftdmac030_dma_slave slave;
++			memset(&slave, 0, sizeof(slave));
++			slave.handshake = -1;
++
++			gm_chan.chan = dma_request_channel(gm_chan.mask, ftdmac030_chan_filter, (void *)&slave);
++			if (!gm_chan.chan) {
++				//err("dma_chan is NULL\n");
++				return -ENXIO;
++			}
++		}
++		break;
++#endif
++		default:
++			err("No such DMA bus\n");
++			return -ENXIO;
++		break;
++	}
++
++	/* filter fn has already set dma_slave_config. */
++	//dmaengine_slave_config(gm_chan.chan, &gm_chan.slave);
++
++flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	gm_chan.desc = dmaengine_prep_dma_memset(gm_chan.chan, dest, value, len, flag);
++	if (!gm_chan.desc) {
++		err("Set DMA failed!!\n");
++		ret = -EIO;
++		goto fail;
++	}
++
++	gm_chan.cookie = dmaengine_submit(gm_chan.desc);
++	if (dma_submit_error(gm_chan.cookie)) {
++		err("DMA submit failed\n");
++		dmaengine_terminate_all(gm_chan.chan);
++		ret = -EIO;
++		goto fail;
++	}
++
++	gm_chan.desc->callback = dma_callback;
++	gm_chan.desc->callback_param = &gm_chan;
++	gm_chan.dma_st = DMA_IN_PROGRESS;
++	dma_async_issue_pending(gm_chan.chan);
++	dma_wait(&gm_chan);
++fail:
++	dma_release_channel(gm_chan.chan);
++	return ret;
++}
++EXPORT_SYMBOL(dma_memset);
+diff --git a/arch/arm/mach-GM/fmem.c b/arch/arm/mach-GM/fmem.c
+new file mode 100644
+index 00000000..9ebb4fcc
+--- /dev/null
++++ b/arch/arm/mach-GM/fmem.c
+@@ -0,0 +1,1130 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/sort.h>
++#include <linux/mmzone.h>
++#include <linux/memory.h>
++#include <linux/kallsyms.h>
++#include <linux/nodemask.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <asm/setup.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++#include <asm/tlbflush.h>
++#include <asm/glue-cache.h>
++#include <asm/outercache.h>
++#include <linux/proc_fs.h>
++#include <linux/kthread.h>
++#include <linux/platform_device.h>
++#include <mach/fmem.h>
++#include <mach/platform/board.h>
++#include <mach/ftpmu010.h>
++#include <mach/gm_jiffies.h>
++
++void debug_printk(const char *f, ...);
++static int __init sanity_check_memhole(u32 *base);
++
++/* MACROs defintion
++ */
++#define ALLOC_BSZ         SZ_8M
++#define POOL_LIST(x)      g_page_info.list[x]
++#define POOL_NODE_SZ(x)   g_page_info.node_sz[x]
++#define POOL_PHY_START(x) g_page_info.phy_start[x]
++#define MAX_PAGE_NUM      128 /* 1G bytes */
++#define CACHE_ALIGN_MASK  0x1F  //cache line with 32 bytes
++
++/*
++ * Local variables declaration
++ */
++static struct task_struct *idle_thread = NULL;
++static g_page_info_t    g_page_info;
++static struct meminfo mem_info, gmmem_info;
++u32 page_array[2][MAX_PAGE_NUM] __initdata;
++u32 reserve_blk_cnt[2] __initdata;
++u32 nonlinear_cpuaddr_flush = 0;
++u32 cpuaddr_flush = 0;
++u32 va_not_32align = 0, length_not_32align = 0;
++u32 debug_counter = 0;
++
++#define DEBUG_WRONG_CACHE_API   0x0
++#define DEBUG_WRONG_CACHE_VA    0x1
++#define DEBUG_WRONG_CACHE_LEN   0x2
++
++/* proc function
++ */
++static struct proc_dir_entry *fmem_proc_root = NULL;
++static struct proc_dir_entry *resolve_proc = NULL;
++static struct proc_dir_entry *counter_proc = NULL;
++
++/* counter info
++ */
++static int proc_read_counter(char *page, char **start, off_t off, int count, int *eof,
++                                    void *data)
++{
++    int len = 0;
++
++    len += sprintf(page + len, "linear cpu_addr flush: %d \n", cpuaddr_flush);
++    len += sprintf(page + len, "non-linear cpu_addr flush: %d \n", nonlinear_cpuaddr_flush);
++    len += sprintf(page + len, "vaddr not cache alignment: %d \n", va_not_32align);
++    len += sprintf(page + len, "len not cache alignment: %d \n", length_not_32align);
++    len += sprintf(page + len, "debug_counter = 0x%x \n", debug_counter);
++
++    return len;
++}
++
++/* debug counter */
++int proc_write_debug_counter(struct file *file, const char *buffer, unsigned long count, void *data)
++{
++    unsigned char value[30];
++
++    if (copy_from_user(value, buffer, count))
++        return 0;
++
++    sscanf(value, "%x\n", &debug_counter);
++
++
++    printk("debug counter: 0x%x \n", debug_counter);
++
++    return count;
++}
++
++/* address resolve
++ */
++int proc_resolve_pa(struct file *file, const char *buffer, unsigned long count, void *data)
++{
++    unsigned char value[30];
++    unsigned int vaddr;
++    phys_addr_t  paddr;
++
++    if (copy_from_user(value, buffer, count))
++        return 0;
++
++    sscanf(value, "%x\n", &vaddr);
++    paddr = fmem_lookup_pa(vaddr);
++
++    printk("Resolve vaddr: 0x%x ---> paddr: 0x%x \n", vaddr, paddr);
++
++    return count;
++}
++
++void fmem_proc_init(void)
++{
++    struct proc_dir_entry *p;
++
++    p = create_proc_entry("fmem", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (p == NULL) {
++        printk("%s, fail! \n", __func__);
++        return;
++    }
++
++    fmem_proc_root = p;
++
++    /* resolve, va->pa
++     */
++    resolve_proc = create_proc_entry("resolve", S_IRUGO, fmem_proc_root);
++    if (resolve_proc == NULL)
++        panic("FMEM: Fail to create proc resolve_proc!\n");
++    resolve_proc->read_proc = NULL;
++    resolve_proc->write_proc = proc_resolve_pa;
++
++    /* counter
++     */
++    counter_proc = create_proc_entry("counter", S_IRUGO, fmem_proc_root);
++    if (counter_proc == NULL)
++        panic("FMEM: Fail to create proc counter_proc!\n");
++    counter_proc->read_proc = (read_proc_t *)proc_read_counter;
++    counter_proc->write_proc = proc_write_debug_counter;
++}
++
++/*
++ * PAGE Functions
++ */
++static int __init page_array_cmp(const void *_a, const void *_b)
++{
++    u32 data_a, data_b;
++	int cmp;
++
++	data_a = *(u32 *)_a;    /* the address of page */
++	data_b = *(u32 *)_b;
++
++	cmp = page_to_phys((struct page *)data_a) - page_to_phys((struct page *)data_b);
++
++	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
++}
++
++static int __init meminfo_cmp(const void *_a, const void *_b)
++{
++	const struct membank *a = _a, *b = _b;
++	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
++
++	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
++}
++
++/* Parse early memory
++ */
++static void __init parse_early_mem(char *p)
++{
++	unsigned long size, nr_bank;
++	phys_addr_t start;
++	char *endp;
++
++	start = PHYS_OFFSET;
++	size  = memparse(p, &endp);
++	if (*endp == '@')
++		start = memparse(endp + 1, NULL);
++
++    nr_bank = mem_info.nr_banks;
++    mem_info.bank[nr_bank].start = start;
++    mem_info.bank[nr_bank].size  = size;
++    mem_info.nr_banks ++;
++}
++
++/* Parse early GM memory
++ */
++static void __init parse_early_gmmem(char *p)
++{
++	unsigned long size, nr_bank;
++	char *endp;
++
++	size  = memparse(p, &endp);
++    nr_bank = gmmem_info.nr_banks;
++    gmmem_info.bank[nr_bank].size  = size;
++
++    gmmem_info.nr_banks ++;
++}
++
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++/* This function calculates the max MAX_PHYSMEM_BITS in memory.h
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required to address
++ * the last byte of memory.
++ */
++unsigned int fmem_max_physmem_bits(void)
++{
++    unsigned int max_physmem_bits;
++    unsigned long phyaddr;
++    int nr_banks;
++
++    nr_banks = mem_info.nr_banks;
++	phyaddr = bank_pfn_end(&mem_info.bank[nr_banks - 1]) << PAGE_SHIFT;
++
++	max_physmem_bits = get_order(phyaddr) + PAGE_SHIFT;
++
++
++    return max_physmem_bits;
++}
++#endif /* CONFIG_ARCH_SPARSEMEM_ENABLE */
++
++/* calculate how many blocks in the page array
++ */
++static int __init get_early_memblk_count(u32 *page_array)
++{
++    int i = 0;
++
++    do {
++        if (!page_array[i])
++            break;
++        i ++;
++    } while (1);
++
++    return i;
++}
++
++/* Purpose: to get whole pages from buddy system as possible for the 2nd DDR.
++ * This function is called early once the buddy system is ready.
++ */
++void __init fmem_early_init(void)
++{
++    struct page *page;
++    dma_addr_t  pfn;
++    int i, idx, order, size, ddr0_cnt;
++
++    memset(&reserve_blk_cnt[0], 0, sizeof(reserve_blk_cnt));
++
++    order = get_order(ALLOC_BSZ);
++
++    if (order > MAX_ORDER)
++        panic("%s, max order: %d, alloc order: %d \n", __func__, MAX_ORDER, order);
++
++    /* do nothing for single bank */
++    if (mem_info.nr_banks == 1)
++        goto ddr0_alloc;
++
++    idx = 1;
++    i = 0;
++    do {
++        /* allocate the first page and store all page pointer inside */
++        page = alloc_pages_node(1, GFP_ATOMIC, order);
++        if (!page)
++            panic("%s, get null page for ddr%d! \n", __func__, idx);
++
++        page_array[idx][i] = (u32)page;
++        /* check if the physical of the allocated page is smaller than the 2nd bank */
++        pfn = __phys_to_pfn(page_to_phys(page));
++        if (pfn < bank_pfn_start(&mem_info.bank[1])) {
++            page_array[idx][i] = 0x0;
++            __free_pages(page, order);
++            break;
++        }
++        /* keep page pointer */
++        page_array[idx][i] = (u32)page;
++
++        i ++;
++        if (i >= MAX_PAGE_NUM)
++            panic("%s, MAX_PAGE_NUM: %d is too small for ddr%d! \n", __func__, MAX_PAGE_NUM, idx);
++    } while (1);
++
++    //keep total blocks
++    reserve_blk_cnt[idx] = i;
++
++    /* sort the pages in ascendant order */
++    sort(page_array[idx], i, sizeof(u32), page_array_cmp, NULL);
++
++ddr0_alloc:
++    idx = 0;
++    /* allocate memory for node 0 */
++    size = gmmem_info.bank[0].size ? gmmem_info.bank[0].size : DDR0_FMEM_SIZE;
++    ddr0_cnt = (size + ALLOC_BSZ - 1) >> (order + PAGE_SHIFT);
++    //keep total blocks
++    reserve_blk_cnt[idx] = ddr0_cnt;
++
++    i = 0;
++    do {
++        page = alloc_pages_node(0, GFP_ATOMIC, order);
++        if (page == NULL) {
++            page_array[idx][i] = 0x0;
++            printk("%s, requested memory size: 0x%x is too large! \n", __func__, size);
++            break;
++        }
++
++        page_array[idx][i] = (u32)page;
++        i ++;
++        if (i >= MAX_PAGE_NUM)
++            panic("%s, MAX_PAGE_NUM: %d is too small for ddr%d! \n", __func__, MAX_PAGE_NUM, idx);
++    } while (-- ddr0_cnt);
++
++    /* sort the pages */
++    sort(page_array[idx], i, sizeof(u32), page_array_cmp, NULL);
++
++    return;
++}
++
++/*
++ * Parse the memory tag from command line
++ */
++void __init fmem_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    char key[] = "mem=", *from, *command_line = NULL;
++    struct tag  *t = tag;
++    char gm_key[] = "gmmem=";
++    int  i, tag_found = 0;
++
++    memset(&mem_info, 0, sizeof(mem_info));
++    memset(&gmmem_info, 0, sizeof(gmmem_info));
++
++    if (tag->hdr.tag == ATAG_CORE) {
++        for (; t->hdr.size; t = tag_next(t)) {
++            if (t->hdr.tag == ATAG_CMDLINE) {
++                command_line = &t->u.cmdline.cmdline[0];
++                from = command_line;
++                tag_found = 1;
++                break;
++            }
++        }
++    }
++
++    /* not found the boot argument parameters from UBOOT */
++    if (!tag_found) {
++        command_line = *cmdline;
++        from = *cmdline;
++    }
++
++    for (i = 0; i < strlen(command_line) - strlen(key); i ++) {
++        if (memcmp(from, key, strlen(key)) == 0) {
++			from += strlen(key);
++			parse_early_mem(from);
++		}
++		else if (memcmp(from, gm_key, strlen(gm_key)) == 0)	{
++		    from += strlen(gm_key);
++			parse_early_gmmem(from);
++		}
++		else
++			from ++;
++    }
++
++
++    sort(&mem_info.bank, mem_info.nr_banks, sizeof(mem_info.bank[0]), meminfo_cmp, NULL);
++}
++
++/*
++ * @brief get the page with largest physical address and the page with smallest physical address.
++ * @function void get_first_last_page(struct list_head *glist, page_node_t ** small_page,
++                         page_node_t ** large_page)
++ * @return None.
++ */
++void get_first_last_page(struct list_head *glist, page_node_t ** small_page,
++                         page_node_t ** large_page)
++{
++    struct list_head *list;
++    /* the list was sorted in ascendant sequence.
++     * Get the page node with the smallest physical address
++     */
++    list = glist->next;
++    *small_page = (page_node_t *)list_entry(list, page_node_t, list);
++    /* get the page node with the largest physical address */
++    list = glist->prev;
++    *large_page = (page_node_t *)list_entry(list, page_node_t, list);
++}
++
++/*
++ * @brief return the memory to the kernel from frammap
++ *
++ * @function int fmem_give_pages(int node_id, unsigned int give_sz)
++ * @param node_id is the real node id instead of chunk id
++ * @param node_id is the size you want to return to the kernel
++ * @return the real size that gives to the kernel
++ */
++int fmem_give_pages(int bank, unsigned int give_sz)
++{
++    unsigned int ret_sz, size, tmp_sz;
++    page_node_t *large_page, *small_page;
++    struct page *page;
++    u32 phyaddr;
++
++    if (give_sz == 0)
++        return 0;
++
++    ret_sz = 0;
++
++    do {
++        get_first_last_page(&POOL_LIST(bank), &small_page, &large_page);
++        size = (give_sz > large_page->size) ? large_page->size : give_sz;
++        tmp_sz = size;
++
++        /* calculate the last page. Because the page address is embedded in section. So
++         * I am not sure whether we can get the page address by shift.
++         */
++        phyaddr = page_to_phys(large_page->page) + large_page->size - PAGE_SIZE;
++
++        do {
++            page = phys_to_page(phyaddr);
++            ClearPageReserved(page);
++            __free_page(page);
++
++            /* No matter wether the page is freed, we need to decrease the page size
++             */
++            large_page->size -= PAGE_SIZE;
++            phyaddr -= PAGE_SIZE;
++        } while (tmp_sz -= PAGE_SIZE);
++
++        /* free memory */
++        if (!large_page->size) {
++            list_del(&large_page->list);
++            kfree(large_page);
++        }
++
++        give_sz -= size;
++        POOL_NODE_SZ(bank) -= size;
++        ret_sz += size;
++    } while (give_sz != 0);
++
++    return ret_sz;
++}
++EXPORT_SYMBOL(fmem_give_pages);
++
++static int fmem_idle_function(void *private)
++{
++    unsigned long begin_jiffies, end_jiffies;
++    long diff;
++
++    printk("FMEM Idle Process Up. \n");
++
++    do {
++        begin_jiffies = get_gm_jiffies();
++        msleep(400);
++        end_jiffies = get_gm_jiffies();
++        diff = (long)end_jiffies - (long)begin_jiffies;
++        if (diff > 2000)
++            printk("%s, cpu is locked over %d msec!!!!! \n", __func__, (u32)diff);
++    } while (1);
++
++    return 0;
++}
++
++void fmem_idle_init(void)
++{
++    if (idle_thread)
++        return;
++
++    idle_thread = kthread_create(fmem_idle_function, 0, "FMEM_IDLE");
++    if (IS_ERR(idle_thread)) {
++        printk("FMEM: Error in creating kernel thread! \n");
++        idle_thread = NULL;
++    } else {
++        wake_up_process(idle_thread);
++    }
++}
++
++/*
++ * @brief This function allocates ahead the memory in advance before fragementation happen
++ *
++ * @function int __init fmem_init(void)
++ * @param none
++ * @return none
++ */
++int __init fmem_init(void)
++{
++    int i, bank, order;
++    struct page *page;
++    page_node_t *page_node;
++    u32 mem_sz[2], size, phyaddr;
++    u32 phys_end;
++
++    if (phys_end)   {}
++    /* sanity check */
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        if (bank_phys_start(&mem_info.bank[bank]) & ((0x1 << SECTION_SIZE_BITS) - 1)) {
++            panic("%s, the start address 0x%x in bank%d is not aligned to section size: 0x%x! \n",
++                __func__, bank_phys_start(&mem_info.bank[bank]), bank, (0x1 << SECTION_SIZE_BITS));
++        }
++    }
++    bank = mem_info.nr_banks - 1;
++    phys_end = bank_phys_end(&mem_info.bank[bank]);
++    if ((get_order(phys_end) + PAGE_SHIFT) != MAX_PHYSMEM_BITS)
++        panic("%s, the memory end address is 0x%x, MAX_PHYSMEM_BITS should be %d(current: %d)! \n",
++            __func__, phys_end, get_order(phys_end) + PAGE_SHIFT, MAX_PHYSMEM_BITS);
++#endif
++
++    /* macro test */
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        phyaddr = bank_phys_start(&mem_info.bank[bank]);
++        if (phyaddr != (__virt_to_phys(__phys_to_virt(phyaddr))))
++            panic("%s, macro porting has bug! \n", __func__);
++    }
++
++    order = get_order(ALLOC_BSZ);
++
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        sanity_check_memhole(page_array[bank]);
++        /* count the active node */
++        g_page_info.nr_node++;
++
++        /*
++         * Note: The arguments from boot command line is higher than the MACRO defintion in memory.h.
++         */
++        mem_sz[bank] = gmmem_info.bank[bank].size ?
++                        gmmem_info.bank[bank].size : bank > 0 ? DDR1_FMEM_SIZE : DDR0_FMEM_SIZE;
++
++        /* update 2nd DDR information.
++         * If DDR1_FMEM_SIZE = -1 which means to allocate whole memory.
++         */
++        if ((bank > 0) && (DDR1_FMEM_SIZE == -1) && (mem_sz[bank] == DDR1_FMEM_SIZE))
++            mem_sz[bank] = get_early_memblk_count(page_array[bank]) * ALLOC_BSZ;
++    }
++
++    for (bank = 0; bank < mem_info.nr_banks; bank ++) {
++        INIT_LIST_HEAD(&POOL_LIST(bank));
++        POOL_NODE_SZ(bank) = 0;
++
++        /* allocate page_node for each page
++         */
++        for (i = 0; i < reserve_blk_cnt[bank]; i++) {
++            page_node = (page_node_t *)kzalloc(sizeof(page_node_t), GFP_KERNEL);
++            if (page_node == NULL)
++                panic("%s: No memory for kmalloc! \n", __func__);
++            INIT_LIST_HEAD(&page_node->list);
++            page_node->page = (struct page *)page_array[bank][i];
++            page_node->phy_start = page_to_phys(page_node->page);
++            page_node->size = ALLOC_BSZ;
++
++            /* can't be swap out and mmap issue which can be mapped to reserved pages only */
++            page = page_node->page;
++            size = page_node->size;
++            phyaddr = page_node->phy_start;
++            do {
++                /* seperate the group pages into individual page and do the reservation prevent
++                 * those pages from being swapped out.
++                 */
++                init_page_count(page);
++                SetPageReserved(page);
++                phyaddr += PAGE_SIZE;
++                page = phys_to_page(phyaddr);
++            } while (size -= PAGE_SIZE);
++
++            POOL_NODE_SZ(bank) += page_node->size;
++
++            /* add to the global DDR list */
++            list_add_tail(&page_node->list, &POOL_LIST(bank));
++        }
++
++        /* free the rest memory */
++        if (reserve_blk_cnt[bank]) {
++            int ret;
++            u32 free_sz;
++
++            //record the start address of this pool
++            POOL_PHY_START(bank) = page_to_phys((struct page *)page_array[bank][0]);
++            free_sz = reserve_blk_cnt[bank] * ALLOC_BSZ - mem_sz[bank];
++            if (free_sz != 0) {
++                ret = fmem_give_pages(bank, free_sz);
++                if (ret != free_sz)
++                    panic("%s, bug in bank%d! \n", __func__, bank);
++            }
++            printk("FMEM: %d pages(0x%x bytes) from bank%d are reserved for Frammap. \n",
++                mem_sz[bank] >> PAGE_SHIFT, mem_sz[bank], bank);
++        }
++    }
++
++    printk("FMEM: Logical memory ends up at 0x%x, init_mm:0x%x(0x%x), PAGE_OFFSET:0x%x(0x%x), \n",
++                (u32)high_memory, (u32)init_mm.pgd, (u32)__pa((void *)init_mm.pgd),
++                (u32)PAGE_OFFSET, (u32)__pa((void *)PAGE_OFFSET));
++
++#ifdef __enabled_CONFIG_CPU_FA726TE
++    if (1) {
++        volatile unsigned int val;
++
++        __asm__ __volatile__ ("mrc p15, 0, %0, c15, c0, 0\t\n":"=r"(val));
++        printk("FMEM: FA726 Test and Debug Register: 0x%x \n", val);
++    }
++#endif
++
++#ifdef CONFIG_ARCH_SPARSEMEM_ENABLE
++    printk("FMEM: SECTION_SIZE_BITS: %d, MAX_PHYSMEM_BITS: %d \n", SECTION_SIZE_BITS, MAX_PHYSMEM_BITS);
++    if (MAX_PHYSMEM_BITS != fmem_max_physmem_bits())
++        panic("%s, the correct MAX_PHYSMEM_BITS(%d) should be changed to %d! \n", __func__,
++                MAX_PHYSMEM_BITS, fmem_max_physmem_bits());
++#endif
++
++    fmem_proc_init();
++    fmem_idle_init();
++    return 0;
++}
++
++core_initcall(fmem_init);
++
++/*
++ * @brief check if the address contains holes
++ *
++ * @function static sanity_check_memhole
++ *
++ * @param base of the first page
++ * @return 0 on success, !0 on error
++ */
++static int __init sanity_check_memhole(u32 *base)
++{
++    struct page *page;
++    dma_addr_t phy_addr, next_phy_addr;
++    int i = 0;
++
++    /* get first page */
++    page = (struct page *)base[0];
++    phy_addr = page_to_phys(page);
++    next_phy_addr = phy_addr + ALLOC_BSZ;
++
++    do {
++        i ++;
++        page = (struct page *)base[i];
++        if (page == NULL)
++            break;
++
++        phy_addr = page_to_phys(page);
++        if (phy_addr != next_phy_addr) {
++            /* dump the content */
++            printk("%s, the expected physical is 0x%x, but get 0x%x \n", __func__, next_phy_addr,
++                    phy_addr);
++            panic("%s, physical address has holes! \n", __func__);
++        }
++        next_phy_addr = phy_addr + ALLOC_BSZ;
++    } while (1);
++
++    return 0;
++}
++
++/*
++ * @brief allocate the memory from linux kernel.
++ * @function void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id)
++ * @parameter size indicates the memory size going to allocate
++ * @parameter dma_handle indicates the physical address
++ * @parameter flags indicates type of this allocated memory is cachable or non-cacheable or ....
++ * @parameter ddr_id indicates which DDR the users want to allocate.
++ * @return virutal memory if success or NULL for fail.
++ */
++void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id)
++{
++    struct page *page;
++    void *cpu_addr = NULL;
++    struct page *end;
++
++    if (ddr_id >= mem_info.nr_banks)
++        return NULL;
++
++    size = PAGE_ALIGN(size);
++    if (size > ALLOC_BSZ) {
++        printk("The allocated memory size 0x%x exceeds 0x%x bytes! \n", size, ALLOC_BSZ);
++        return NULL;
++    }
++
++    page = alloc_pages_node(ddr_id, GFP_KERNEL, get_order(size));
++    if (!page) {
++        printk("alloc_pages fail! (requested %#x)", size);
++        goto no_page;
++    }
++
++    *dma_handle = page_to_phys(page);
++    if ((*dma_handle < bank_phys_start(&mem_info.bank[ddr_id])) ||
++            (*dma_handle > bank_phys_end(&mem_info.bank[ddr_id]))) {
++        __free_pages(page, get_order(size));
++        goto no_page;
++    }
++
++    if ((flags == PAGE_COPY) || (flags == PAGE_SHARED))
++        //cpu_addr = ioremap_cached(*dma_handle, size);
++        cpu_addr = __va(*dma_handle);
++    else if (flags == pgprot_writecombine(pgprot_kernel))
++        cpu_addr = ioremap_wc(*dma_handle, size);
++    else
++        cpu_addr = ioremap_nocache(*dma_handle, size);
++
++    if (cpu_addr) {
++        end = page + (1 << get_order(size));
++        do {
++            init_page_count(page);
++            SetPageReserved(page);
++            page++;
++            size -= PAGE_SIZE;
++        } while (size != 0);
++
++        /*
++         * Free the otherwise unused pages.
++         */
++        while (page < end) {
++            init_page_count(page);
++            if (!PageReserved(page) && put_page_testzero(page))
++                __free_page(page);
++            page++;
++        }
++    } else {
++        __free_pages(page, get_order(size));
++        printk("__ioremap fail! (phy %#x)", *dma_handle);
++    }
++
++  no_page:
++    return cpu_addr;
++}
++EXPORT_SYMBOL(fmem_alloc_ex);
++
++/*
++ * @brief free the memory which was allocated by fmem_alloc_ex().
++ * @function void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle)
++ * @parameter size indicates the memory size going to free
++ * @parameter cpu_addr indicates the virtual memory going to free
++ * @parameter handle indicates the physical memory going to free
++ * @return None.
++ */
++void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle)
++{
++    struct page *page = pfn_to_page(handle >> PAGE_SHIFT);
++    struct page *pg;
++    unsigned int sz;
++
++    pg = page;
++    sz = size;
++
++    if ((u32)__va(handle) != (u32)cpu_addr)
++        __iounmap(cpu_addr);
++
++    size = PAGE_ALIGN(size);
++
++    do {
++        ClearPageReserved(page);
++        if (!PageReserved(page) && put_page_testzero(page))
++            __free_page(page);
++        page++;
++    } while (size -= PAGE_SIZE);
++}
++EXPORT_SYMBOL(fmem_free_ex);
++
++/**
++ * @brief to resolve the virtual address (including direct mapping, ioremap or user space address to
++ *      its real physical address.
++ *
++ * @parm vaddr indicates any virtual address
++ *
++ * @return  >= 0 for success, 0xFFFFFFFF for fail
++ */
++phys_addr_t fmem_lookup_pa(unsigned int vaddr)
++{
++    pgd_t *pgdp;
++    pmd_t *pmdp;
++    pud_t *pudp;
++    pte_t *ptep;
++    phys_addr_t paddr = 0xFFFFFFFF;
++
++    /* for speed up */
++    if (virt_addr_valid(vaddr))
++        return (phys_addr_t)__pa(vaddr);
++
++    /*
++     * The pgd is never bad, and a pmd always exists(as it's folded into the pgd entry)
++     */
++    if (vaddr >= TASK_SIZE) /* use init_mm as mmu to look up in kernel mode */
++        pgdp = pgd_offset_k(vaddr);
++    else
++        pgdp = pgd_offset(current->mm, vaddr);
++
++    if (unlikely(pgd_none(*pgdp))) {
++        printk("fmem: 0x%x not mapped in pgd table! \n", vaddr);
++        goto err;
++    }
++
++    /* because we don't have 3-level MMU, so pud = pgd. Here we are in order to meet generic Linux
++     * version, pud is listed here.
++     */
++    pudp = pud_offset(pgdp, vaddr);
++    if (unlikely(pud_none(*pudp))) {
++        printk(KERN_INFO"fmem: 0x%x not mapped in pud table! \n", vaddr);
++        goto err;
++    }
++
++    pmdp = pmd_offset(pudp, vaddr);
++    if (unlikely(pmd_none(*pmdp))) {
++        printk(KERN_INFO"fmem: 0x%x not mapped in pmd 0x%x! \n", vaddr, (u32)pmdp);
++        goto err;
++    }
++
++    if (!pmd_bad(*pmdp)) {
++        u32 v_addr;
++
++        /* page mapping */
++        ptep = pte_offset_kernel(pmdp, vaddr);
++        if (pte_none(*ptep)) {
++            printk(KERN_ERR"fmem: 0x%x not mapped in pte! \n", vaddr);
++            goto err;
++        }
++
++        v_addr = (unsigned int)page_address(pte_page(*ptep)) + (vaddr & (PAGE_SIZE - 1));
++        paddr = __pa(v_addr);
++    } else {
++        /* section mapping. The cases are:
++         * 1. DDR direct mapping
++         * 2. ioremap's vaddr, size and paddr all are 2M alignment.
++         */
++        if (vaddr & SECTION_SIZE)
++            pmdp ++; /* move to pmd[1] */
++        paddr = (pmd_val(*pmdp) & SECTION_MASK) | (vaddr & ~SECTION_MASK);
++    }
++err:
++    return paddr;
++}
++EXPORT_SYMBOL(fmem_lookup_pa);
++
++/*
++ * @brief get the memory data information from frammap
++ *
++ * @function fmem_get_pageinfo(g_page_info_t **pg_info)
++ * @param pg_info is the pointer wants to be assigned the info
++ * @return none
++ */
++void fmem_get_pageinfo(g_page_info_t ** pg_info)
++{
++    *pg_info = &g_page_info;
++
++    return;
++}
++EXPORT_SYMBOL(fmem_get_pageinfo);
++
++/* __virt_to_phys macro porting arch/arm/include/mach/memory.h */
++unsigned long fmem_virt_to_phys(unsigned int vaddr)
++{
++    unsigned long phys;
++
++    if (mem_info.nr_banks == 0) {
++        phys = vaddr - PAGE_OFFSET + PHYS_OFFSET;
++
++        printk("%s, someone calls va2pa early............................. \n", __func__);
++
++        return phys;
++    }
++
++    if (mem_info.nr_banks == 1) {
++        phys = vaddr - PAGE_OFFSET + PHYS_OFFSET;
++    } else {
++        u32 end_vaddr;
++
++        end_vaddr = PAGE_OFFSET + bank_phys_size(&mem_info.bank[0]);
++        phys = vaddr >= end_vaddr ? (vaddr - end_vaddr) + bank_phys_start(&mem_info.bank[1]) :
++            (vaddr - PAGE_OFFSET) + bank_phys_start(&mem_info.bank[0]);
++    }
++
++    return phys;
++}
++
++/* __phys_to_virt macro porting in arch/arm/include/mach/memory.h */
++unsigned int fmem_phys_to_virt(unsigned long phys)
++{
++    u32 vaddr;
++
++    if (mem_info.nr_banks == 0) {
++         vaddr = phys - PHYS_OFFSET + PAGE_OFFSET;
++         printk("%s, someone calls pa2va early............................. \n", __func__);
++         return vaddr;
++    }
++
++    if (mem_info.nr_banks == 1) {
++        vaddr = phys - PHYS_OFFSET + PAGE_OFFSET;
++    } else {
++        vaddr = (phys >= bank_phys_start(&mem_info.bank[1])) ?
++            PAGE_OFFSET + bank_phys_size(&mem_info.bank[0]) + (phys - bank_phys_start(&mem_info.bank[1])) :
++            PAGE_OFFSET + (phys - PHYS_OFFSET);
++    }
++
++    return vaddr;
++}
++
++/*
++ * @This function is used to read CPU id and pci id
++ * @Return value: 0 for success, -1 for fail
++ */
++int fmem_get_identifier(fmem_pci_id_t *pci_id, fmem_cpu_id_t *cpu_id)
++{
++    int ret = 0;
++    u32 value;
++
++
++    /* Read CR0-0 Identification Code Register(ID)
++     * [31:24] IMP, [23:16]ARCH, [15:4] PART, [3:0] VER
++     */
++    __asm__ __volatile__ ("mrc p15, 0, %0, c0, c0, 0\t\n": "=r"(value));
++
++    switch ((value >> 0x4) & 0xFFF) {
++      case 0x626:
++        /* the code should be 0x66056261 */
++        *cpu_id = FMEM_CPU_FA626;
++
++#if __enabled_CONFIG_CPU_FA726TE
++        panic("This driver compiled in FA726 environment CANNOT be executed in FA626! \n");
++        ret = -1;
++#endif
++        break;
++      case 0x726:
++        *cpu_id = FMEM_CPU_FA726;
++#if __enabled_CONFIG_CPU_FA626TE
++        panic("This driver compiled in FA626 environment CANNOT be executed in FA726! \n");
++        ret = -1;
++#endif
++        break;
++      default:
++        *cpu_id = FMEM_CPU_UNKNOWN;
++        panic("Unknow cpu id: 0x%x \n", value);
++        break;
++    }
++
++    *pci_id = FMEM_PCI_HOST;
++
++    return ret;
++}
++EXPORT_SYMBOL(fmem_get_identifier);
++
++static void dev_release(struct device *dev) { return; }
++#define DRIVER_NAME "fmem_sync"
++static struct platform_device pseudo_dev = {
++	.name = DRIVER_NAME,
++	.id   = 0,
++	.num_resources = 0,
++	.dev  = {
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++		.release = dev_release,
++	}
++};
++
++/* process outer cache */
++static inline void __fmem_sync_outer_cache(void *vaddr, u32 len, enum dma_data_direction dir)
++{
++#ifdef CONFIG_OUTER_CACHE
++    phys_addr_t  paddr;
++
++    paddr = fmem_lookup_pa((unsigned int)vaddr);
++    if (paddr == 0xFFFFFFFF)
++        return;
++
++    switch (dir) {
++      case DMA_BIDIRECTIONAL:
++        outer_flush_range(paddr, paddr + len);
++        break;
++      case DMA_TO_DEVICE:
++        outer_clean_range(paddr, paddr + len);
++        break;
++      case DMA_FROM_DEVICE:
++        outer_inv_range(paddr, paddr + len);
++        break;
++      case DMA_NONE:
++        break;
++    }
++#endif
++}
++
++/* @this function is a data cache operation function,
++ * @parm: vaddr: any virtual address
++ * @parm: dir will be:
++ * DMA_BIDIRECTIONAL = 0, it means flush operation.
++ * DMA_TO_DEVICE = 1, it means clean operation.
++ * DMA_FROM_DEVICE = 2, it means invalidate operation.
++ * DMA_NONE = 3,
++ */
++void fmem_dcache_sync(void *vaddr, u32 len, enum dma_data_direction dir)
++{
++    struct device *dev = &pseudo_dev.dev;
++
++    if (!valid_dma_direction(dir))
++        panic("%s, invalid direction: %d \n", __func__, dir);
++
++    /* kernel buffer may not cache line alignment, it only can use both clean/inv
++     * for safe. Others we regard them as warning cases in coding.
++     */
++    if (dir != DMA_BIDIRECTIONAL) {
++        if ((u32)vaddr & CACHE_ALIGN_MASK) {
++            va_not_32align ++;
++            if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_VA)) {
++                printk("%s, warning, vaddr: 0x%x not cache alignment! \n", __func__, (u32)vaddr);
++                dump_stack();
++            }
++        }
++
++        if (len & CACHE_ALIGN_MASK) {
++            length_not_32align ++;
++            if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_LEN)) {
++                printk("%s, warning, len: %d not cache alignment! \n", __func__, len);
++                dump_stack();
++            }
++        }
++    }
++
++    if (virt_addr_valid(vaddr) && virt_addr_valid(vaddr + len - 1)) {
++        switch (dir) {
++          case DMA_BIDIRECTIONAL:
++            dma_map_single(dev, vaddr, len, DMA_BIDIRECTIONAL);
++            /* the purpose is for outer cache sync. dma_map_single() only did
++             * outer_clean_range() in arch/arm/mm/dma-mapping.c (#554), why?
++             */
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            //dma_unmap_single(dev, __pa(vaddr), len, DMA_FROM_DEVICE);
++            break;
++          case DMA_TO_DEVICE:
++            dma_map_single(dev, vaddr, len, DMA_TO_DEVICE);
++            /* outer cache will invoke clean function. */
++            break;
++          case DMA_FROM_DEVICE:
++            dma_map_single(dev, vaddr, len, DMA_FROM_DEVICE);
++            /* outer cache will invoke invalidate function. */
++            break;
++          case DMA_NONE:
++            break;
++        }
++        cpuaddr_flush ++;
++    } else {
++        switch (dir) {
++          case DMA_BIDIRECTIONAL:
++            dmac_flush_range(vaddr, vaddr + len);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_TO_DEVICE:
++            dmac_map_area(vaddr, len, DMA_TO_DEVICE);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_FROM_DEVICE:
++            dmac_map_area(vaddr, len, DMA_FROM_DEVICE);
++            __fmem_sync_outer_cache(vaddr, len, dir);
++            break;
++          case DMA_NONE:
++            break;
++        }
++        nonlinear_cpuaddr_flush ++;
++        if (debug_counter & (0x1 << DEBUG_WRONG_CACHE_API)) {
++            printk("%s, warning, memory addr 0x%x not direct mapped! \n", __func__, (u32)vaddr);
++            dump_stack();
++        }
++    }
++}
++EXPORT_SYMBOL(fmem_dcache_sync);
++
++/* The following functions are valid in GM8210 and adopted by videgraph.
++ */
++int fmem_set_ep_outbound_win(u32 phy_addr, u32 size) { return 0; }
++EXPORT_SYMBOL(fmem_set_ep_outbound_win);
++
++u32 fmem_get_pcie_addr(u32 axi_phy_addr) { return axi_phy_addr; }
++EXPORT_SYMBOL(fmem_get_pcie_addr);
++
++u32 fmem_get_axi_addr(u32 pcie_phy_addr) { return pcie_phy_addr; }
++EXPORT_SYMBOL(fmem_get_axi_addr);
++
++void CheckTxStatus(unsigned int port)
++{
++		// wait until Tx ready
++    while (!(*(volatile unsigned int *)(port + 0x14) & 0x20));
++      udelay(1);
++}
++
++static void _putchar(char Ch)
++{
++    if(Ch != '\0'){
++        CheckTxStatus(UART_FTUART010_0_VA_BASE);
++        *(volatile unsigned int *)(UART_FTUART010_0_VA_BASE) = Ch;
++    }
++
++    if (Ch == '\n'){
++        CheckTxStatus(UART_FTUART010_0_VA_BASE);
++        *(volatile unsigned int *)(UART_FTUART010_0_VA_BASE) = '\r';
++    }
++}
++
++static int debug_init = 0;
++/* If we want to use this API, please enable arch/arm/kernel/head.S
++ * GM_CONSOLE_PRINT definition
++*/
++void debug_printk(const char *f, ...)
++{
++    volatile unsigned int i;
++    va_list arg_ptr;
++    char buffer[256];
++
++    if (0) { //!debug_init) {
++        volatile unsigned int val, ttbr;
++        debug_init = 1;
++
++        __asm__ __volatile__ ("mrc p15, 0, %0, c2, c0, 0\t\n":"=r"(ttbr));
++
++        ttbr = PAGE_OFFSET + (ttbr - PHYS_OFFSET);  //because the __va can't work at this moment (mem_info[] no data yet)
++        val = *(u32 *)(ttbr + (UART_FTUART010_0_VA_BASE >> 18));
++        //uart temp mapping
++        if (!val) {
++            *(u32 *)(ttbr + (UART_FTUART010_0_VA_BASE >> 18)) = (UART_FTUART010_0_PA_BASE | 0xC12);
++
++            //neet to flush dcache and tlb?
++            __asm__ __volatile__ ("mov r0, #0\n"
++                                  "mcr p15, 0, r0, c7, c10, 3\n"    /* Test and Clean DCache */
++                                  "mcr p15, 0, r0, c7, c10, 4\n"    /* drain WB */
++                                  "mcr p15, 0, r0, c8, c7, 0");	    /* invalidate TLB all */
++        }
++    }
++
++    va_start(arg_ptr, f);
++    vsprintf(&buffer[0], f, arg_ptr);
++    va_end(arg_ptr);
++
++      //output the buffer
++    i = 0;
++    while (buffer[i]){
++          _putchar(buffer[i]);
++          i++;
++    }
++}
++
++EXPORT_SYMBOL(debug_printk);
++EXPORT_SYMBOL(fmem_virt_to_phys);
++EXPORT_SYMBOL(fmem_phys_to_virt);
++
+diff --git a/arch/arm/mach-GM/ftapbb020.c b/arch/arm/mach-GM/ftapbb020.c
+new file mode 100644
+index 00000000..40e2d641
+--- /dev/null
++++ b/arch/arm/mach-GM/ftapbb020.c
+@@ -0,0 +1,1374 @@
++/*
++ * Faraday FTAPBB020 DMA engine driver
++ *
++ * (C) Copyright 2010 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <asm/io.h>
++
++#include <mach/ftapbb020.h>
++
++#define DRV_NAME	"ftapbb020"
++#define CHANNEL_NR	4
++
++/*
++ * This value must be multiple of 32-bits to prevent from changing the
++ * alignment of child descriptors.
++ */
++#define MAX_CYCLE_PER_BLOCK		0x00800000
++#if (MAX_CYCLE_PER_BLOCK > FTAPBB020_CYC_MASK) || (MAX_CYCLE_PER_BLOCK & 0x3)
++#error invalid MAX_CYCLE_PER_BLOCK
++#endif
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 64;
++module_param(init_nr_desc_per_channel, uint, 0644);
++MODULE_PARM_DESC(init_nr_desc_per_channel,
++		 "initial descriptors per channel (default: 64)");
++
++/**
++ * struct ftapbb020_desc - async transaction descriptor.
++ * @txd: support for the async_tx api
++ * @node: node on the descriptors list
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @cmd: command register content
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @value: buf value for memset usage
++ * @len: length in bytes
++ */
++struct ftapbb020_desc {
++	struct dma_async_tx_descriptor txd;
++	struct list_head node;
++	struct list_head child_list;
++	struct ftapbb020_chan *ftchan;
++	unsigned int cmd;
++	dma_addr_t src;
++	dma_addr_t dst;
++	unsigned int cycle;
++	unsigned int value;
++	size_t len;
++};
++
++/**
++ * struct ftapbb020_chan - internal representation of an ftapbb020 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @pending_list: list of descriptors dmaengine which is wating to run
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftapbb020: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftapbb020_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head pending_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftapbb020 *ftapbb020;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++};
++
++/**
++ * struct ftapbb020 - internal representation of an ftapbb020 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @irq: irq number
++ * @channel: channel table
++ */
++struct ftapbb020 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	unsigned int irq;
++	struct ftapbb020_chan channel[CHANNEL_NR];
++};
++
++static dma_cookie_t ftapbb020_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftapbb020_stop_channel(struct ftapbb020_chan *ftchan)
++{
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	iowrite32(0, base + FTAPBB020_OFFSET_CMD(chan_id));
++}
++
++static void ftapbb020_stop_all_channels(struct ftapbb020 *ftapbb020)
++{
++	void __iomem *base = ftapbb020->base;
++	int i;
++
++	for (i = 0; i < CHANNEL_NR; i++)
++		iowrite32(0, base + FTAPBB020_OFFSET_CMD(i));
++}
++
++static int ftapbb020_chan_is_enabled(struct ftapbb020_chan *ftchan)
++{
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++	unsigned int cmd;
++
++	cmd = ioread32(base + FTAPBB020_OFFSET_CMD(chan_id));
++	return cmd & FTAPBB020_CMD_ENABLE;
++}
++
++/**
++ * ftapbb020_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftapbb020_desc *ftapbb020_alloc_desc(struct ftapbb020_chan
++						   *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = kzalloc(sizeof(*desc), gfp_flags);
++	if (desc) {
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftapbb020_tx_submit;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftapbb020_free_desc(struct ftapbb020_desc *desc)
++{
++	struct dma_chan *chan = &desc->ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	kfree(desc);
++}
++
++/**
++ * ftapbb020_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftapbb020_desc *ftapbb020_desc_get(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc = NULL;
++
++	spin_lock_bh(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++					struct ftapbb020_desc, node);
++
++		list_del(&desc->node);
++	}
++	spin_unlock_bh(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftapbb020_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			spin_lock_bh(&ftchan->lock);
++			ftchan->descs_allocated++;
++			spin_unlock_bh(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftapbb020_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftapbb020_desc_put(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *child;
++
++	spin_lock_bh(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++static void ftapbb020_unmap_desc(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->dst, desc->len,
++					 DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->dst, desc->len,
++				       DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->src, desc->len,
++					 DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->src, desc->len,
++				       DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftapbb020_remove_chain(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *child;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->node, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftapbb020_unmap_desc(child);
++		ftapbb020_desc_put(child);
++	}
++
++	ftapbb020_unmap_desc(desc);
++	ftapbb020_desc_put(desc);
++}
++
++/**
++ * ftapbb020_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * @cmd: command register content
++ */
++static struct ftapbb020_desc *
++ftapbb020_create_chain(struct ftapbb020_chan *ftchan,
++			struct ftapbb020_desc *first,
++			dma_addr_t src,	dma_addr_t dest,
++			size_t len, unsigned int shift,
++			int fixed_src, int fixed_dest, unsigned int cmd)
++{
++	struct dma_chan *chan = &ftchan->common;
++	size_t offset;
++	unsigned int cycle;
++	bool is_memset = false;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, shift %d)\n",
++		__func__, src, dest, len, shift);
++
++	/* Check for memset */
++	if (cmd ==
++	    (FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB |
++	     FTAPBB020_CMD_SRC_MODE_FIXED | FTAPBB020_CMD_WIDTH_WORD |
++	     FTAPBB020_CMD_DST_MODE_WORD_INC)) {
++		is_memset = true;
++	}
++
++	if ((shift == 2 && ((src | dest | len) & 3)) ||
++	    (shift == 1 && ((src | dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	for (offset = 0; offset < len; offset += cycle << shift) {
++		struct ftapbb020_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> shift,
++			      MAX_CYCLE_PER_BLOCK);
++
++		cycle &= FTAPBB020_CYC_MASK;
++
++		desc = ftapbb020_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		if (is_memset) {
++			/* use fixed_dest as value */
++			desc->value = fixed_dest;
++			src = __pa(&(desc->value));
++		}
++
++		if (fixed_src)
++			desc->src = src;
++		else
++			desc->src = src + offset;
++
++		if (fixed_dest && !is_memset)
++			desc->dst = dest;
++		else
++			desc->dst = dest + offset;
++
++		desc->cmd = cmd;
++		desc->len = cycle << shift;
++		desc->cycle = cycle;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++	}
++
++	return first;
++err:
++	if (first)
++		ftapbb020_remove_chain(first);
++	return NULL;
++}
++
++static void ftapbb020_start_desc(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	unsigned int cmd = desc->cmd;
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	cmd |= FTAPBB020_CMD_ENABLE
++	    | FTAPBB020_CMD_FININT_E | FTAPBB020_CMD_ERRINT_E;
++
++	dev_dbg(chan2dev(chan), "\t[SAR %d] = %x\n", chan_id, desc->src);
++	iowrite32(desc->src, base + FTAPBB020_OFFSET_SAR(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DAR %d] = %x\n", chan_id, desc->dst);
++	iowrite32(desc->dst, base + FTAPBB020_OFFSET_DAR(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	iowrite32(desc->cycle, base + FTAPBB020_OFFSET_CYC(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CMD %d] = %x\n", chan_id, cmd);
++	iowrite32(cmd, base + FTAPBB020_OFFSET_CMD(chan_id));
++}
++
++static void ftapbb020_activate_chain(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	/* move new transfer chain to active list */
++	list_add_tail(&desc->node, &ftchan->active_list);
++	list_splice_tail_init(&desc->child_list, &ftchan->active_list);
++
++	/* start first descriptor */
++	ftapbb020_start_desc(desc);
++}
++
++static void ftapbb020_start_next_chain(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *new;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->pending_list))
++		return;
++
++	new = list_first_entry(&ftchan->pending_list, struct ftapbb020_desc,
++			       node);
++	list_del(&new->node);
++
++	ftapbb020_activate_chain(new);
++}
++
++static void ftapbb020_invoke_callback(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	ftchan->completed_cookie = desc->txd.cookie;
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback)
++		desc->txd.callback(desc->txd.callback_param);
++}
++
++static void ftapbb020_finish_all_pending_chains(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->pending_list, node) {
++		list_del(&desc->node);
++		ftapbb020_invoke_callback(desc);
++		ftapbb020_remove_chain(desc);
++	}
++}
++
++static void ftapbb020_finish_active_chain(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftapbb020_desc,
++				node);
++	/* first descriptor in the active list has callback fields */
++	ftapbb020_invoke_callback(desc);
++
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftapbb020_unmap_desc(desc);
++		ftapbb020_desc_put(desc);
++	}
++}
++
++static void ftapbb020_finish_all_chains(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftapbb020_finish_active_chain(ftchan);
++	ftapbb020_finish_all_pending_chains(ftchan);
++}
++
++static dma_cookie_t ftapbb020_new_cookie(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftapbb020_chan_filter(struct dma_chan * chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftapbb020_dma_slave *slave = data;
++
++	if (strncmp(DRV_NAME, drv_name, sizeof(DRV_NAME))) {
++		printk(KERN_DEBUG"driver name: %s wrong!\n", drv_name);
++		return false;
++	}
++
++#if 0 /* Let channels be controlled by dma subsystem, by eason */
++	if ((slave->channels & (1 << chan->chan_id)) == 0) {
++		printk(KERN_WARNING"channel doesn't match!\n");
++		return false;
++	}
++#endif
++
++	chan->private = slave;
++	return true;
++}
++
++EXPORT_SYMBOL_GPL(ftapbb020_chan_filter);
++
++/******************************************************************************
++ * tasklet - called after we finished one chunk
++ *****************************************************************************/
++static void ftapbb020_tasklet(unsigned long data)
++{
++	struct ftapbb020_chan *ftchan = (struct ftapbb020_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	BUG_ON(list_empty(&ftchan->active_list));
++
++	spin_lock_bh(&ftchan->lock);
++
++	/* remove already finished descriptor */
++	desc = list_first_entry(&ftchan->active_list, struct ftapbb020_desc,
++				node);
++	list_del(&desc->node);
++
++	if (list_empty(&ftchan->active_list)) {
++		ftapbb020_invoke_callback(desc);
++		ftapbb020_start_next_chain(ftchan);
++	} else {
++		struct ftapbb020_desc *next;
++
++		/* Do next descriptor in the trasnfer chain */
++		next = list_first_entry(&ftchan->active_list,
++					struct ftapbb020_desc, node);
++
++		/*
++		 * Always keep the txd fields in the first descriptor in the
++		 * active list.
++		 */
++		next->txd.cookie = desc->txd.cookie;
++		next->txd.flags = desc->txd.flags;
++		next->txd.callback = desc->txd.callback;
++		next->txd.callback_param = desc->txd.callback_param;
++
++		ftapbb020_start_desc(next);
++	}
++
++	ftapbb020_unmap_desc(desc);
++	spin_unlock_bh(&ftchan->lock);
++	ftapbb020_desc_put(desc);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftapbb020_interrupt(int irq, void *dev_id)
++{
++	struct ftapbb020 *ftapbb020 = dev_id;
++	struct device *dev = ftapbb020->dma.dev;
++	irqreturn_t ret = IRQ_NONE;
++	unsigned int sr;
++	int i;
++
++	sr = ioread32(ftapbb020->base + FTAPBB020_OFFSET_SR);
++	if (sr & FTAPBB020_SR_BWERRINT) {
++		dev_info(dev, "bufferable write error\n");
++		ret = IRQ_HANDLED;
++	}
++
++	/* clear SR */
++	iowrite32(sr, ftapbb020->base + FTAPBB020_OFFSET_SR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++		void __iomem *base = ftchan->ftapbb020->base;
++		int chan_id = ftchan->common.chan_id;
++		unsigned int cmd;
++
++		/*
++		 * status bits in command register?
++		 * what a brain-damaged design.
++		 */
++		cmd = ioread32(base + FTAPBB020_OFFSET_CMD(chan_id));
++
++		if (cmd & FTAPBB020_CMD_FININT_S) {
++			tasklet_schedule(&ftchan->tasklet);
++			ret = IRQ_HANDLED;
++		} else if (cmd & FTAPBB020_CMD_ERRINT_S) {
++			dev_err(chan2dev(chan), "error happened\n");
++			ret = IRQ_HANDLED;
++		}
++
++		if (cmd & (FTAPBB020_CMD_FININT_S | FTAPBB020_CMD_ERRINT_S)) {
++			/* clear interrupt status */
++			cmd &=
++			    ~(FTAPBB020_CMD_FININT_S | FTAPBB020_CMD_ERRINT_S);
++			iowrite32(cmd, base + FTAPBB020_OFFSET_CMD(chan_id));
++		}
++	}
++
++	return ret;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftapbb020_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftapbb020_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++
++	desc = container_of(txd, struct ftapbb020_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	spin_lock_bh(&ftchan->lock);
++
++	cookie = ftapbb020_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list)) {
++#if 0				/* Just add desc into active_list, not start doing tx */
++		ftapbb020_activate_chain(desc);
++#else
++		list_add_tail(&desc->node, &ftchan->active_list);
++		list_splice_tail_init(&desc->child_list, &ftchan->active_list);
++#endif
++	} else {
++		list_add_tail(&desc->node, &ftchan->pending_list);
++	}
++
++	spin_unlock_bh(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftapbb020_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftapbb020_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftapbb020_desc *desc;
++
++		desc = ftapbb020_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	spin_lock_bh(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list);
++	ftchan->completed_cookie = chan->cookie = 1;
++	spin_unlock_bh(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftapbb020_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftapbb020_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++	struct ftapbb020 *ftapbb020;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++	ftapbb020 = ftchan->ftapbb020;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(!list_empty(&ftchan->pending_list));
++	BUG_ON(ftapbb020_chan_is_enabled(ftchan));
++
++	spin_lock_bh(&ftchan->lock);
++	ftapbb020_stop_channel(ftchan);
++	ftapbb020_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftapbb020_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/**
++ * ftapbb020_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++			dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	unsigned int shift;
++	unsigned int cmd;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	/* Assume RAM is on AHB bus. */
++	cmd = FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB;
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++		cmd |= FTAPBB020_CMD_WIDTH_WORD
++		    | FTAPBB020_CMD_DST_MODE_WORD_INC
++		    | FTAPBB020_CMD_SRC_MODE_WORD_INC;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++		cmd |= FTAPBB020_CMD_WIDTH_HALF
++		    | FTAPBB020_CMD_DST_MODE_HALF_INC
++		    | FTAPBB020_CMD_SRC_MODE_HALF_INC;
++	} else {
++		shift = 0;
++		cmd |= FTAPBB020_CMD_WIDTH_BYTE
++		    | FTAPBB020_CMD_DST_MODE_BYTE_INC
++		    | FTAPBB020_CMD_SRC_MODE_BYTE_INC;
++	}
++
++	desc =
++	    ftapbb020_create_chain(ftchan, NULL, src, dest, len, shift, 0, 0,
++				   cmd);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	desc->cmd = cmd;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftapbb020_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @value: the given value for memset used
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest,
++			int value, size_t len, unsigned long flags)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	unsigned int shift;
++	unsigned int cmd;
++
++	dev_dbg(chan2dev(chan), "%s(dest %x, value %x, len %x)\n",
++		__func__, dest, value, len);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(len & 3)) {
++		dev_info(chan2dev(chan), "%s: length isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(dest & 3)) {
++		dev_info(chan2dev(chan), "%s: dest addr isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	/* Assume RAM is on AHB bus. */
++	cmd = FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB;
++
++	/* src address is from mem buf */
++	cmd |= FTAPBB020_CMD_SRC_MODE_FIXED;
++
++	/* dst address should be word align */
++	shift = 2;
++	cmd |= FTAPBB020_CMD_WIDTH_WORD | FTAPBB020_CMD_DST_MODE_WORD_INC;
++
++	desc =
++	    ftapbb020_create_chain(ftchan, NULL, 0, dest, len, shift, 1, value,
++				   cmd);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	desc->cmd = cmd;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftapbb020_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++			unsigned int sg_len,
++			enum dma_transfer_direction direction,
++			unsigned long flags)
++{
++	struct ftapbb020_dma_slave *slave = chan->private;
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int cmd;
++	unsigned int shift;
++	unsigned int i;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (direction) {
++	case DMA_MEM_TO_DEV:
++		cmd = FTAPBB020_CMD_DST_MODE_FIXED
++		    | FTAPBB020_CMD_DST_HANDSHAKE(slave->handshake);
++
++		/* Assume RAM is on AHB bus. */
++		cmd |= FTAPBB020_CMD_SRC_TYPE_AHB;
++
++		switch (slave->type) {
++		case FTAPBB020_BUS_TYPE_AHB:
++			cmd |= FTAPBB020_CMD_DST_TYPE_AHB;
++			break;
++		case FTAPBB020_BUS_TYPE_APB:
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect bus type\n",
++				__func__);
++			BUG();
++		}
++
++		switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			shift = 0;
++			cmd |= FTAPBB020_CMD_WIDTH_BYTE
++			    | FTAPBB020_CMD_SRC_MODE_BYTE_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			shift = 1;
++			cmd |= FTAPBB020_CMD_WIDTH_HALF
++			    | FTAPBB020_CMD_SRC_MODE_HALF_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			shift = 2;
++			cmd |= FTAPBB020_CMD_WIDTH_WORD
++			    | FTAPBB020_CMD_SRC_MODE_WORD_INC;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++				__func__);
++			BUG();
++		}
++
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftapbb020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftapbb020_create_chain(ftchan, desc,
++						     mem,
++						     slave->common.dst_addr,
++						     len, shift, 0, 1, cmd);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++		break;
++	case DMA_DEV_TO_MEM:
++		cmd = FTAPBB020_CMD_SRC_MODE_FIXED
++		    | FTAPBB020_CMD_SRC_HANDSHAKE(slave->handshake);
++
++		/* Assume RAM is on AHB bus. */
++		cmd |= FTAPBB020_CMD_DST_TYPE_AHB;
++
++		switch (slave->type) {
++		case FTAPBB020_BUS_TYPE_AHB:
++			cmd |= FTAPBB020_CMD_SRC_TYPE_AHB;
++			break;
++		case FTAPBB020_BUS_TYPE_APB:
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect bus type\n",
++				__func__);
++			BUG();
++		}
++
++		switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			shift = 0;
++			cmd |= FTAPBB020_CMD_WIDTH_BYTE
++			    | FTAPBB020_CMD_DST_MODE_BYTE_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			shift = 1;
++			cmd |= FTAPBB020_CMD_WIDTH_HALF
++			    | FTAPBB020_CMD_DST_MODE_HALF_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			shift = 2;
++			cmd |= FTAPBB020_CMD_WIDTH_WORD
++			    | FTAPBB020_CMD_DST_MODE_WORD_INC;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++				__func__);
++			BUG();
++		}
++
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftapbb020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftapbb020_create_chain(ftchan, desc,
++						     slave->common.src_addr,
++						     mem, len, shift, 1, 0,
++						     cmd);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n", __func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftapbb020_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++			     unsigned long arg)
++{
++	struct ftapbb020_chan *ftchan;
++	int ret = -ENXIO;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (cmd == DMA_SLAVE_CONFIG) {
++		struct dma_slave_config *slave_config = (struct dma_slave_config *)arg;
++		struct ftapbb020_dma_slave  *dma_slave;
++
++		dma_slave = container_of(slave_config, struct ftapbb020_dma_slave, common);
++		chan->private = dma_slave;
++		ret = 0;
++	} 
++
++	if (cmd == DMA_TERMINATE_ALL) {
++		/*
++		 * This is only called when something went wrong elsewhere, so
++		 * we don't really care about the data. Just disable the channel.
++		 */
++		spin_lock_bh(&ftchan->lock);
++		ftapbb020_stop_channel(ftchan);
++		ftapbb020_finish_all_chains(ftchan);
++		spin_unlock_bh(&ftchan->lock);
++	}
++
++	return ret;
++}
++
++/**
++ * ftapbb020_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftapbb020_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		    struct dma_tx_state *txstate)
++{
++	struct ftapbb020_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftapbb020_issue_pending - try to finish work
++ * @chan: target DMA channel
++ */
++static void ftapbb020_issue_pending(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (list_empty(&ftchan->active_list)) {
++		spin_lock_bh(&ftchan->lock);
++		ftapbb020_start_next_chain(ftchan);
++		spin_unlock_bh(&ftchan->lock);
++	} else {		/* Disable starting tx in tx_submit, start here */
++		desc =
++		    list_first_entry(&ftchan->active_list,
++				     struct ftapbb020_desc, node);
++		ftapbb020_start_desc(desc);
++	}
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftapbb020_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftapbb020 *ftapbb020;
++	struct dma_device *dma;
++	int irq;
++	int i;
++	int err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftapbb020 = kzalloc(sizeof(*ftapbb020), GFP_KERNEL);
++	if (!ftapbb020) {
++		return -ENOMEM;
++	}
++
++	dma = &ftapbb020->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftapbb020);
++
++	/* map io memory */
++
++	ftapbb020->res =
++	    request_mem_region(res->start, res->end - res->start + 1,
++			       dev_name(&pdev->dev));
++	if (ftapbb020->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftapbb020->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftapbb020->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* force dma off, just in case */
++	ftapbb020_stop_all_channels(ftapbb020);
++
++	/* initialize channels */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->pending_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device = dma;
++		ftchan->common.cookie = DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftapbb020 = ftapbb020;
++		ftchan->completed_cookie = DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftapbb020_tasklet,
++			     (unsigned long)ftchan);
++
++		list_add_tail(&ftchan->common.device_node, &dma->channels);
++	}
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftapbb020_alloc_chan_resources;
++	dma->device_free_chan_resources = ftapbb020_free_chan_resources;
++	dma->device_prep_dma_memcpy = ftapbb020_prep_dma_memcpy;
++	dma->device_prep_dma_memset = ftapbb020_prep_dma_memset;
++	dma->device_prep_slave_sg = ftapbb020_prep_slave_sg;
++	dma->device_control = ftapbb020_control;
++	dma->device_tx_status = ftapbb020_tx_status;
++	dma->device_issue_pending = ftapbb020_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
++	dma_cap_set(DMA_MEMSET, dma->cap_mask);
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);
++
++	err = request_irq(irq, ftapbb020_interrupt, IRQF_SHARED, pdev->name,
++			  ftapbb020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_irq;
++	}
++
++	ftapbb020->irq = irq;
++
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	dev_info(&pdev->dev, "DMA engine driver: irq %d, mapped at %p\n",
++		 irq, ftapbb020->base);
++
++	return 0;
++
++err_register:
++	free_irq(irq, ftapbb020);
++err_irq:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftapbb020->base);
++err_ioremap:
++	release_resource(ftapbb020->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftapbb020);
++	return err;
++}
++
++static int __exit ftapbb020_remove(struct platform_device *pdev)
++{
++	struct ftapbb020 *ftapbb020;
++	int i;
++
++	ftapbb020 = platform_get_drvdata(pdev);
++
++	dma_async_device_unregister(&ftapbb020->dma);
++
++	free_irq(ftapbb020->irq, ftapbb020);
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftapbb020->base);
++	release_resource(ftapbb020->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftapbb020);
++	return 0;
++}
++
++/*
++ * FTAPBB020
++ */
++static struct resource ftapbb020_resources[] = {
++	{
++	 .start = APBBRG_FTAPBBRG020S_PA_BASE,
++	 .end = APBBRG_FTAPBBRG020S_PA_LIMIT,
++	 .flags = IORESOURCE_MEM,
++	 }, {
++	     .start = APBBRG_FTAPBBRG020S_IRQ,
++	     .end = APBBRG_FTAPBBRG020S_IRQ,
++	     .flags = IORESOURCE_IRQ,
++	     }
++};
++
++static struct platform_device ftapbb020_device = {
++	.name = "ftapbb020",
++	.id = 0,
++	.dev = {
++		.coherent_dma_mask = DMA_BIT_MASK(32),
++		},
++	.num_resources = ARRAY_SIZE(ftapbb020_resources),
++	.resource = ftapbb020_resources,
++};
++
++static struct platform_driver ftapbb020_driver = {
++	.probe = ftapbb020_probe,
++	.remove = __exit_p(ftapbb020_remove),
++	.driver = {
++		   .name = DRV_NAME,
++		   .owner = THIS_MODULE,
++		   },
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftapbb020_init(void)
++{
++	/* add platform device */
++	if (platform_device_register(&ftapbb020_device)) {
++		printk("failed to register FTAPBB020 device\n");
++		return -ENODEV;
++	}
++	return platform_driver_register(&ftapbb020_driver);
++}
++
++static void __exit ftapbb020_exit(void)
++{
++	platform_driver_unregister(&ftapbb020_driver);
++	platform_device_unregister(&ftapbb020_device);
++}
++
++module_init(ftapbb020_init);
++module_exit(ftapbb020_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTAPBB020 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM/ftdmac020.c b/arch/arm/mach-GM/ftdmac020.c
+new file mode 100644
+index 00000000..923ebf27
+--- /dev/null
++++ b/arch/arm/mach-GM/ftdmac020.c
+@@ -0,0 +1,1789 @@
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/dmapool.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++//#include <asm/io.h>
++#include <mach/ftdmac020.h>
++
++#define CHANNEL_NR	8
++#define MAX_CYCLE_PER_BLOCK	0x3FF000    //3.xM, TOT_SIZE[21:0]
++//#define DEBUG
++//#define REG_DUMP
++
++#define USE_IRQ_LOCK    /* SSP ALSA will call these functions while disabling irq */
++
++#ifdef USE_IRQ_LOCK
++#define DMAC020_LOCK(x)     spin_lock_irqsave(x, flags)
++#define DMAC020_UNLOCK(x)   spin_unlock_irqrestore(x, flags)
++#else
++#define DMAC020_LOCK(x)     spin_lock_bh(x)
++#define DMAC020_UNLOCK(x)   spin_unlock_bh(x)
++#endif
++
++/* platform dependent */
++static int (*platform_chan_filter)(int chan_id) = NULL;
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 24;
++
++/*
++ * driver/dma/at_hdmac.c can be the template
++ */
++/**
++ * struct ftdmac020_desc - async transaction descriptor.
++ * @lld: hardware descriptor, MUST be the first member
++ * @value: value for MEMSET (Must be fixed here)
++ * @ccr: value for channel control register
++ * @cfg: value for channel configuration register
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the first link list descriptor (2nd block)
++ * @cycle: transfer size
++ * @txd: support for the async_tx api
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @node: node on the descriptors list
++ * @len: length in bytes
++ *
++ * For a chained transfer, software has to set channel-specific hardware
++ * registers to describe the first block and link list descriptors to describe
++ * other blocks. Because of this unbelievable brain-damaged design, the
++ * software descriptor and driver became unnecessarily complex.
++ *
++ * Sure, we can reuse src, dst, next and cycle in lld to save some space.
++ * The reason I do not do that is not to make you confused.
++ */
++struct ftdmac020_desc {
++	/* not used by the first block */
++	struct ftdmac020_lld lld;
++
++	/* used only by the first block. This is per channel configuration */
++	unsigned int value; /* for MEMSET */
++	unsigned int ccr;   /* Cn_CSR */
++	unsigned int cfg;   /* Cn_CFG */
++	dma_addr_t src;     /* Cn_SrcAddr */
++	dma_addr_t dst;     /* Cn_DstAddr */
++	dma_addr_t next;    /* Cn_LLP */
++	unsigned int cycle; /* Cn_SIZE */
++
++	struct dma_async_tx_descriptor txd;
++	struct list_head child_list;
++
++	/* used by all blocks */
++	struct ftdmac020_chan *ftchan;
++	struct list_head node;
++	size_t len;
++};
++
++/**
++ * struct ftdmac020_chan - internal representation of an ftdmac020 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftdmac020: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftdmac020_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftdmac020 *ftdmac020;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++	enum dma_transaction_type transaction_type;
++};
++
++/**
++ * struct ftdmac020 - internal representation of an ftdmac020 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @id: id for each device
++ * @tc_irq: terminal count irq number
++ * @ea_irq: error and abort irq number
++ * @channel: channel table
++ */
++struct ftdmac020 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	int id;
++	unsigned int irq;
++	struct dma_pool *dma_desc_pool;
++	struct ftdmac020_chan channel[CHANNEL_NR];
++};
++
++static const char *ftdmac020_name[] = {"ftdmac020", "ftdmac020"};
++static dma_cookie_t ftdmac020_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftdmac020_enable(struct ftdmac020 *ftdmac020)
++{
++	void __iomem *base = ftdmac020->base;
++
++	iowrite32(FTDMAC020_CR_ENABLE, base + FTDMAC020_OFFSET_CR);
++}
++
++static void ftdmac020_disable(struct ftdmac020 *ftdmac020)
++{
++	void __iomem *base = ftdmac020->base;
++
++	iowrite32(0, base + FTDMAC020_OFFSET_CR);
++}
++
++static int ftdmac020_chan_is_enabled(struct ftdmac020_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++	unsigned int enabled;
++
++	enabled = ioread32(base + FTDMAC020_OFFSET_CH_ENABLED);
++	return enabled & (1 << chan_id);
++}
++
++static void ftdmac020_abort_channel(struct ftdmac020_chan *ftchan)
++{
++    unsigned long flags;
++    int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++	volatile u32 value, i;
++
++    if (ftchan->transaction_type != DMA_CYCLIC)
++        return;
++
++    spin_lock_irqsave(&ftchan->lock, flags);
++    /* 1. set ABT */
++    value = ioread32(base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++    value |= (0x1 << 15);   /* ABT */
++    iowrite32(value, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++
++    /* 2. wait dmaint INT_ABT to assert */
++    i = 0;
++    do {
++        udelay(1);
++        value = ioread32(base + FTDMAC020_OFFSET_EAISR);    /* 0xC */
++        i ++;
++        if (i > 1000000) {
++            printk("%s, error 1 ################################# \n", __func__);
++            break;
++        }
++    } while (!(value & (0x1 << (16 + chan_id))));
++
++    /* 3. wait ABT to confirm which channel has been aborted */
++    i = 0;
++    do {
++        udelay(1);
++        value = ioread32(base + FTDMAC020_OFFSET_EARAW);    /* 0x18 */
++        i ++;
++        if (i > 1000000) {
++            printk("%s, error 2 ################################# \n", __func__);
++            break;
++        }
++    } while (!(value & (0x1 << (16 + chan_id))));
++
++    /* 4. Set ABT_CLR to clear ABT. The channel ca be reuse again */
++    iowrite32(0x1 << (16 + chan_id), base + FTDMAC020_OFFSET_EAICR);
++
++    spin_unlock_irqrestore(&ftchan->lock, flags);
++}
++
++static void ftdmac020_stop_channel(struct ftdmac020_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++    volatile u32 i = 0;
++
++    if (ftchan->transaction_type == DMA_CYCLIC) {
++        /* ring DMA needs to use ABT to stop the DMA. CANNOT disable channel directly, it may cause DMAC die */
++        ftdmac020_abort_channel(ftchan);
++    } else {
++        /* Normal path. Wait DMA to finish a complete transaction.
++         */
++        while (ftdmac020_chan_is_enabled(ftchan)) {
++            /* someone may call terminate all to force exit. In this case we must wait dma to complete */
++            udelay(50);
++            i ++;
++            if (i > 1000)
++                break;
++        }
++        if (i > 1000)
++            printk("%s, error in dmac020 ch%d enabled! \n", __func__, chan_id);
++
++        /* disable dmach in IDLE state. */
++	    iowrite32(0, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++    }
++}
++
++/**
++ * ftdmac020_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftdmac020_desc *ftdmac020_alloc_desc(
++		struct ftdmac020_chan *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020 *ftdmac020 = ftchan->ftdmac020;
++	struct ftdmac020_desc *desc;
++	dma_addr_t phys;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = dma_pool_alloc(ftdmac020->dma_desc_pool, gfp_flags, &phys);
++	if (desc) {
++		memset(desc, 0, sizeof(*desc));
++
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftdmac020_tx_submit;
++		desc->txd.phys = phys;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftdmac020_free_desc(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &desc->ftchan->common;
++	struct ftdmac020 *ftdmac020 = ftchan->ftdmac020;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	dma_pool_free(ftdmac020->dma_desc_pool, desc, desc->txd.phys);
++}
++
++/**
++ * ftdmac020_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftdmac020_desc *ftdmac020_desc_get(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc = NULL;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	DMAC020_LOCK(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++			struct ftdmac020_desc, node);
++
++		list_del(&desc->node);
++	}
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftdmac020_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			DMAC020_LOCK(&ftchan->lock);
++			ftchan->descs_allocated++;
++			DMAC020_UNLOCK(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftdmac020_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftdmac020_desc_put(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *child;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	DMAC020_LOCK(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++static void ftdmac020_unmap_desc(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftdmac020_remove_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *child;
++	struct ftdmac020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->child_list, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftdmac020_unmap_desc(child);
++		ftdmac020_desc_put(child);
++	}
++
++	ftdmac020_unmap_desc(desc);
++	ftdmac020_desc_put(desc);
++}
++
++/**
++ * ftdmac020_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @src_shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @dst_shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * 		when MEMSET, it's the set value
++ */
++static struct ftdmac020_desc *ftdmac020_create_chain(
++		struct ftdmac020_chan *ftchan,
++		struct ftdmac020_desc *first,
++		dma_addr_t src, dma_addr_t dest, size_t len,
++		unsigned int src_shift, unsigned int dst_shift, int fixed_src, int fixed_dest)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_dma_slave *slave = chan->private;
++	struct ftdmac020_desc *prev = NULL;
++	unsigned int ccr;
++	unsigned int lld_ctrl;
++	size_t offset;
++	unsigned int cycle;
++	bool is_memset = false;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, src_shift %d, dst_shift %d)\n",
++		__func__, src, dest, len, src_shift, dst_shift);
++	if ((src_shift == 2 && ((src | len) & 3)) ||
++	    (src_shift == 1 && ((src | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or src data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++    if ((dst_shift == 2 && ((dest | len) & 3)) ||
++	    (dst_shift == 1 && ((dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or dst data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	/* When using memset, src is set to zero */
++	if (src == 0 && fixed_src)
++		is_memset = true;
++
++	if (first) {
++		if (list_empty(&first->child_list))
++			prev = first;
++		else
++			prev = list_entry(first->child_list.prev,
++				struct ftdmac020_desc, node);
++	}
++
++	ccr = FTDMAC020_CCR_ENABLE
++	    | ((slave->src_size & 0x7) << 16)
++	    | FTDMAC020_CCR_PRIO_0
++	    | FTDMAC020_CCR_FIFOTH_1;
++
++	lld_ctrl = FTDMAC020_LLD_CTRL_FIFOTH_1;
++
++    switch (src_shift) {
++	case 2:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_32;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_32;
++		break;
++	case 1:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_16;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_16;
++		break;
++	case 0:
++		ccr |= FTDMAC020_CCR_SRC_WIDTH_8;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	switch (dst_shift) {
++	case 2:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_32;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_32;
++		break;
++	case 1:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_16;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_16;
++		break;
++	case 0:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_8;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	if (slave && slave->handshake >= 0)
++		ccr |= FTDMAC020_CCR_HANDSHAKE;
++
++	if (fixed_src) {
++		ccr |= FTDMAC020_CCR_SRC_FIXED;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_FIXED;
++	} else {
++		ccr |= FTDMAC020_CCR_SRC_INC;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_INC;
++	}
++
++	if (fixed_dest && !is_memset) {
++		ccr |= FTDMAC020_CCR_DST_FIXED;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_FIXED;
++	} else {
++		ccr |= FTDMAC020_CCR_DST_INC;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_INC;
++	}
++
++	ccr |= ((slave->src_sel & 0x1) << 2);  /* SRC_SEL */
++	ccr |= ((slave->dst_sel & 0x1) << 1);  /* DST_SEL */
++	lld_ctrl |= ((slave->src_sel & 0x1) << 17);  /* SRC_SEL */
++	lld_ctrl |= ((slave->dst_sel & 0x1) << 16);  /* DST_SEL */
++
++	/* we must seperate the len into multiple descriptors. Because len may be a bigger one */
++	for (offset = 0; offset < len; offset += cycle << src_shift) {
++		struct ftdmac020_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> src_shift,
++				MAX_CYCLE_PER_BLOCK);
++
++		desc = ftdmac020_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		/*
++		 * Importatnt: 1. fixed_dest is viewed as memset value
++		 *             2. src is defined as the place of "int value" in ftdmac020_desc
++		 */
++		if (is_memset) {
++			desc->value = fixed_dest;
++			src = desc->txd.phys + sizeof(struct ftdmac020_lld);
++		}
++
++		if (fixed_src) {
++			desc->src = desc->lld.src = src;
++		} else {
++			desc->src = desc->lld.src = src + offset;
++		}
++
++		if (fixed_dest && !is_memset) {
++			desc->dst = desc->lld.dst = dest;
++		} else {
++			desc->dst = desc->lld.dst = dest + offset;
++		}
++
++		desc->next	= 0;
++		desc->cycle	= cycle & FTDMAC020_CYC_MASK;
++		desc->ccr	= ccr;
++		desc->cfg	= 0;
++		desc->len	= cycle << src_shift;
++
++		desc->lld.next	= 0;
++		desc->lld.cycle	= cycle & FTDMAC020_LLD_CYCLE_MASK;
++		desc->lld.ctrl	= lld_ctrl;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/*
++			 * Mask terminal count interrupt for this descriptor.
++			 * What an inconvenient stupid design.
++			 */
++            if (ftchan->transaction_type != DMA_CYCLIC) {
++                prev->ccr	|= FTDMAC020_CCR_MASK_TC;
++                prev->lld.ctrl	|= FTDMAC020_LLD_CTRL_MASK_TC;
++            }
++
++			/* hardware link list pointer */
++			prev->next	= FTDMAC020_LLP_ADDR(desc->txd.phys);
++			prev->lld.next	= desc->txd.phys;
++#if defined (CONFIG_PLATFORM_GM8287) || defined (CONFIG_PLATFORM_GM8139) || defined (CONFIG_PLATFORM_GM8136)
++			prev->next |= 0x1; // load next LLP from AHB MASTER1
++			prev->lld.next |= 0x1;
++#endif
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++		prev = desc;
++	}
++
++	/*
++	 * Here just create the chain only. When submit function is called, this desc will be added to
++	 * ftchan->active_list.
++	 */
++	return first;
++err:
++	if (first)
++		ftdmac020_remove_chain(first);
++	return NULL;
++}
++
++static void ftdmac020_start_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	void __iomem *base = ftchan->ftdmac020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++
++#ifdef REG_DUMP
++	printk("\t[SRC %d] = %x\n", chan_id, desc->src);
++	printk("\t[DST %d] = %x\n", chan_id, desc->dst);
++	printk("\t[LLP %d] = %x\n", chan_id, desc->next);
++	printk("\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	printk("\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	printk("\t[CCR %d] = %x\n", chan_id, desc->ccr);
++#endif
++	/*
++	 * The first transfer block is not described by hardware lld.
++	 * Instead, we should fill some hardware registers.
++	 * What a stupid weird design.
++	 */
++	dev_dbg(chan2dev(chan), "\t[SRC %d] = %x\n", chan_id, desc->src);
++	iowrite32(desc->src, base + FTDMAC020_OFFSET_SRC_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DST %d] = %x\n", chan_id, desc->dst);
++	iowrite32(desc->dst, base + FTDMAC020_OFFSET_DST_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[LLP %d] = %x\n", chan_id, desc->next);
++	iowrite32(desc->next, base + FTDMAC020_OFFSET_LLP_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	iowrite32(desc->cycle, base + FTDMAC020_OFFSET_CYC_CH(chan_id));
++
++	/* go */
++	dev_dbg(chan2dev(chan), "\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	iowrite32(desc->cfg, base + FTDMAC020_OFFSET_CFG_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CCR %d] = %x\n", chan_id, desc->ccr);
++	iowrite32(desc->ccr, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++
++}
++
++static void ftdmac020_start_new_chain(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++	ftdmac020_start_chain(desc);
++}
++
++static void ftdmac020_finish_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	DMAC020_LOCK(&ftchan->lock);
++	ftchan->completed_cookie = desc->txd.cookie;
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback) {
++	    /* If this channel is terminated by manual, we dont need to callback */
++	    if (ftchan->transaction_type != DMA_TX_TYPE_END)
++		    desc->txd.callback(desc->txd.callback_param);
++    }
++
++	ftdmac020_remove_chain(desc);
++}
++
++static void ftdmac020_finish_all_chains(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftdmac020_finish_chain(desc);
++	}
++}
++
++static dma_cookie_t ftdmac020_new_cookie(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftdmac020_chan_filter(struct dma_chan *chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftdmac020_dma_slave *slave = data;
++	const char *ftdmac020_drv_name = *(ftdmac020_name + slave->id);
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020 *ftdmac020;
++
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++	ftdmac020 = ftchan->ftdmac020;
++
++	if (strncmp(ftdmac020_drv_name, drv_name, sizeof("ftdmac020")))
++		return false;
++
++	/* When you have more than 2 dma controller's, it checks id */
++	if (slave->id >= 0 && slave->id != ftdmac020->id)
++		return false;
++
++    /* this is platform dependent. Some platform only can use some channels instead of all. */
++    if (platform_chan_filter && platform_chan_filter((int)chan->chan_id))
++        return false;
++
++	chan->private = slave;
++	return true;
++}
++EXPORT_SYMBOL_GPL(ftdmac020_chan_filter);
++
++/**
++ * atc_handle_cyclic - at the end of a period, run callback function
++ * @atchan: channel used for cyclic operations
++ *
++ * Called with atchan->lock held and bh disabled
++ */
++static void ftdmac020_handle_cyclic(struct ftdmac020_chan *ftchan)
++{
++    struct ftdmac020_desc	*first = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++	struct dma_async_tx_descriptor	*txd = &first->txd;
++	dma_async_tx_callback   callback = txd->callback;
++	void			*param = txd->callback_param;
++    struct dma_chan *chan = &ftchan->common;
++
++    dev_dbg(chan2dev(chan), "%s\n", __func__);
++
++	if (callback)
++		callback(param);
++}
++
++/******************************************************************************
++ * tasklet - called after we finished one chain
++ *****************************************************************************/
++static void ftdmac020_tasklet(unsigned long data)
++{
++	struct ftdmac020_chan *ftchan = (struct ftdmac020_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++    if (ftchan->transaction_type == DMA_TX_TYPE_END) {
++        if (!list_empty(&ftchan->active_list))
++            panic("%s, active_list should be empty due to terminate_all! \n", __func__);
++
++        return;
++    }
++
++    if (ftchan->transaction_type == DMA_CYCLIC) {
++        dev_dbg(chan2dev(chan), "%s, DMA_CYCLIC \n", __func__);
++
++        DMAC020_LOCK(&ftchan->lock);
++	    if (list_empty(&ftchan->active_list))
++            printk("%s, active_list is empty in DMA_CYCLIC! \n", __func__);
++        BUG_ON(list_empty(&ftchan->active_list));
++        ftdmac020_handle_cyclic(ftchan);
++        DMAC020_UNLOCK(&ftchan->lock);
++    } else {
++        /*
++         * DMA_SLAVE, DMA_MEMCPY
++         */
++        dev_dbg(chan2dev(chan), "%s, DMA_SLAVE / MEMCPY\n", __func__);
++
++	    DMAC020_LOCK(&ftchan->lock);
++	    if (list_empty(&ftchan->active_list))
++            panic("%s, active_list is empty in DMA_SLAVE / MEMCPY! \n", __func__);
++
++    	/* remove already finished descriptor */
++    	desc = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++    	list_del(&desc->node);
++
++    	/* check if there were another transfer to do */
++    	ftdmac020_start_new_chain(ftchan);
++
++    	DMAC020_UNLOCK(&ftchan->lock);
++    	ftdmac020_finish_chain(desc);
++    }
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftdmac020_interrupt(int irq, void *dev_id)
++{
++	struct ftdmac020 *ftdmac020 = dev_id;
++	unsigned int status;
++	int i;
++
++	status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_TCISR);
++	if (!status) {
++	    /* read error status */
++	    status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_EAISR);    /* 0xC */
++    	if (!status)
++    		return IRQ_NONE;
++
++        /* clear status */
++	    iowrite32(status, ftdmac020->base + FTDMAC020_OFFSET_EAICR);
++
++	    for (i = 0; i < CHANNEL_NR; i++) {
++    		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++    		struct dma_chan *chan = &ftchan->common;
++
++    		if (status & FTDMAC020_EA_ERR_CH(i))
++    			dev_info(chan2dev(chan), "error happened\n");
++
++    		if (status & FTDMAC020_EA_ABT_CH(i))
++    			dev_dbg(chan2dev(chan), "transfer aborted\n");
++	    }
++
++	    return IRQ_HANDLED;
++	}
++
++	/* clear status */
++	iowrite32(status, ftdmac020->base + FTDMAC020_OFFSET_TCICR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (status & (1 << i)) {
++			dev_dbg(chan2dev(chan), "terminal count\n");
++			tasklet_schedule(&ftchan->tasklet);
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftdmac020_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftdmac020_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++	bool busy;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	desc = container_of(txd, struct ftdmac020_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	DMAC020_LOCK(&ftchan->lock);
++
++	cookie = ftdmac020_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list))
++		busy = false;
++	else
++		busy = true;
++
++	list_add_tail(&desc->node, &ftchan->active_list);
++
++#if 0   /* Harry, move to issue pending. If we start the transaction here, it will have potential
++         * chance to lose the LLP due to race condition between CPU and hardware.
++         */
++	/* start ASAP */
++	if (!busy)
++		ftdmac020_start_chain(desc);
++#endif
++
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftdmac020_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftdmac020_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++	unsigned long       flags;
++
++    if (flags)  {}
++
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftdmac020_desc *desc;
++
++		desc = ftdmac020_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	DMAC020_LOCK(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list); /* add tmp_list to free_list */
++	ftchan->completed_cookie = chan->cookie = 1;
++	DMAC020_UNLOCK(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftdmac020_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftdmac020_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_desc *tmp;
++	struct ftdmac020 *ftdmac020;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++	ftdmac020 = ftchan->ftdmac020;
++
++	/* channel must be idle */
++        if (ftdmac020_chan_is_enabled(ftchan)) {
++	    dump_stack();
++	    panic("%s, chan is enabled! \n", __func__);
++   	}
++
++	if (!list_empty(&ftchan->active_list)) {
++	    dump_stack();
++	    panic("%s, ftchan->active_list is not empty! \n", __func__);
++	}
++
++	DMAC020_LOCK(&ftchan->lock);
++	ftdmac020_stop_channel(ftchan);
++	ftdmac020_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftdmac020_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++/**
++ * ftdmac020_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++		dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((src >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect src physical address 0x%x \n", __func__, src);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++	} else {
++		shift = 0;
++	}
++
++	desc = ftdmac020_create_chain(ftchan, NULL, src, dest, len,
++		shift, shift, 0, 0);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMCPY;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac020_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @value: the given value for memset used
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest,
++		int value, size_t len, unsigned long flags)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(dest %x, value %x, len %x)\n",
++		__func__, dest, value, len);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(len & 3)) {
++		dev_info(chan2dev(chan), "%s: length isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(dest & 3)) {
++		dev_info(chan2dev(chan), "%s: dest addr isn't word-align!\n",
++			 __func__);
++		return NULL;
++	}
++
++	if (unlikely(!pfn_valid((dest >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect dest physical address 0x%x \n", __func__, dest);
++		return NULL;
++	}
++
++	shift = 2;
++
++	desc = ftdmac020_create_chain(ftchan, NULL, 0, dest, len,
++		shift, shift, 1, value);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	ftchan->transaction_type = DMA_MEMSET;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * atc_prep_dma_cyclic - prepare the cyclic DMA transfer
++ * @chan: the DMA channel to prepare
++ * @buf_addr: physical DMA address where the buffer starts
++ * @buf_len: total number of bytes for the entire buffer
++ * @period_len: number of bytes for each period
++ * @direction: transfer direction, to or from device
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
++		size_t period_len, enum dma_transfer_direction direction)
++{
++	struct ftdmac020_dma_slave  *slave = chan->private;
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc = NULL, *child, *last;
++	dma_addr_t  src_addr, dst_addr;
++	int i, src_shift, dst_shift, periods = buf_len / period_len;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s, please call dmaengine_slave_config() first! \n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!list_empty(&ftchan->active_list))) {
++		dev_err(chan2dev(chan), "%s, chan%d, active list is not empty! \n", __func__, ftchan->common.chan_id);
++		return NULL;
++	}
++
++	if (unlikely(!buf_len || !period_len)) {
++		dev_dbg(chan2dev(chan), "prep_dma_cyclic: length is zero!\n");
++		return NULL;
++	}
++
++	if ((direction != DMA_MEM_TO_DEV) && (direction != DMA_DEV_TO_MEM)) {
++		dev_err(chan2dev(chan), "%s: incorrect direction %d \n", __func__, direction);
++		return NULL;
++	}
++
++	if (buf_len % period_len) {
++		dev_err(chan2dev(chan), "%s: incorrect length %d \n", __func__, buf_len);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			src_shift = 0;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			src_shift = 1;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			src_shift = 2;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++					__func__);
++			return NULL;
++	}
++
++    switch (slave->common.dst_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			dst_shift = 0;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			dst_shift = 1;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			dst_shift = 2;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++					__func__);
++			return NULL;
++	}
++
++#ifdef REG_DUMP
++    printk("%s, src_shift: %d, dst_shift: %d, slave->src_size: %d\n", __func__,
++                    src_shift, dst_shift, slave->src_size);
++#endif
++
++	if (slave->src_size > FTDMAC020_BURST_SZ_256 || slave->src_size < FTDMAC020_BURST_SZ_1) {
++		dev_err(chan2dev(chan), "%s: incorrect src_size %d\n", __func__, slave->src_size);
++		return NULL;
++	}
++
++    if (direction == DMA_MEM_TO_DEV) {
++        if (buf_addr != slave->common.src_addr) {
++            dev_err(chan2dev(chan), "%s: inconsistent src address %x \n", __func__, buf_addr);
++                      return NULL;
++        }
++    } else {
++        if (buf_addr != slave->common.dst_addr) {
++            dev_err(chan2dev(chan), "%s: inconsistent dst address %x \n", __func__, buf_addr);
++                      return NULL;
++        }
++    }
++
++	if (unlikely(!pfn_valid((buf_addr >> PAGE_SHIFT)))) {
++		dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, buf_addr);
++		return NULL;
++	}
++
++	if (direction != slave->common.direction) {
++		dev_err(chan2dev(chan), "%s: inconsistent direction %d\n", __func__, direction);
++		return NULL;
++	}
++
++	src_addr = slave->common.src_addr;
++	dst_addr = slave->common.dst_addr;
++
++    /* tell ftdmac020_create_chain() that LLP is used for DMA_CYCLIC */
++	ftchan->transaction_type = DMA_CYCLIC;
++
++	/* create chain */
++	for (i = 0; i < periods; i ++) {
++		struct ftdmac020_desc *tmp;
++		int fixed_src, fixed_dst;
++
++		if (direction == DMA_MEM_TO_DEV) {
++			fixed_src = 0;  /* INC */
++			fixed_dst = 1;
++		} else {
++			fixed_src = 1;
++			fixed_dst = 0;
++		}
++
++		tmp = ftdmac020_create_chain(ftchan, desc,
++				src_addr, dst_addr, period_len,
++				src_shift, dst_shift, fixed_src, fixed_dst);
++
++		/* increase the address */
++		if (fixed_src == 0)
++			src_addr += period_len;
++		if (fixed_dst == 0)
++			dst_addr += period_len;
++
++		if (!tmp)
++			return NULL;
++		if (!desc)  /* all childs are chained to the first active node */
++			desc = tmp;
++
++		if (direction == DMA_MEM_TO_DEV) {
++			if (slave->handshake >= 0)
++				tmp->cfg = FTDMAC020_CFG_DST_HANDSHAKE_EN
++					| FTDMAC020_CFG_DST_HANDSHAKE(slave->handshake);
++		} else {
++			if (slave->handshake >= 0)
++				tmp->cfg = FTDMAC020_CFG_SRC_HANDSHAKE_EN
++					| FTDMAC020_CFG_SRC_HANDSHAKE(slave->handshake);
++		}
++	}
++
++	/* walk through the whole list and update TC_MASK to issue interrupt
++	*/
++	list_for_each_entry(child, &desc->child_list, node) {
++		child->ccr &= ~FTDMAC020_CCR_MASK_TC;
++		child->ccr |= FTDMAC020_CCR_PRIO_3; /* audio needs high priority */
++		child->lld.ctrl &= ~FTDMAC020_LLD_CTRL_MASK_TC;
++	}
++
++	/* form hardware link list pointer ring */
++	last = list_entry(desc->child_list.prev, struct ftdmac020_desc, node);
++    last->next	= FTDMAC020_LLP_ADDR(desc->txd.phys);
++	last->lld.next	= desc->txd.phys;
++#if defined (CONFIG_PLATFORM_GM8287) || defined (CONFIG_PLATFORM_GM8139) || defined (CONFIG_PLATFORM_GM8136)
++	last->next |= 0x1; // load next LLP from AHB MASTER1
++	last->lld.next |= 0x1;
++#endif
++
++#ifdef REG_DUMP   //dump register
++	child = desc;
++	printk("(0x%x)child->ccr: 0x%x, cfg: 0x%x, src:0x%x, dst:0x%x, lld.src:0x%x, lld.dst:0x%x, lld.next:0x%x, lld.cycle:0x%x, lld.ctrl:0x%x \n",
++			child->txd.phys, child->ccr, child->cfg, child->src, child->dst,
++			child->lld.src, child->lld.dst, child->lld.next, child->lld.cycle, child->lld.ctrl);
++
++	list_for_each_entry(child, &desc->child_list, node) {
++		printk("(0x%x)child->ccr:0x%x, cfg:0x%x, src:0x%x, dst:0x%x, lld.src:0x%x, lld.dst:0x%x, lld.next:0x%x, lld.cycle:0x%x, lld.ctrl:0x%x \n",
++				child->txd.phys, child->ccr, child->cfg, child->src, child->dst,
++				child->lld.src, child->lld.dst, child->lld.next, child->lld.cycle, child->lld.ctrl);
++	}
++#endif
++
++	/* Update the tc_mask to issue interrupt per element in the chain */
++	desc->txd.cookie = -EBUSY;
++	desc->txd.flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++	chan->private = NULL;   /* got the parameter already, so free it */
++
++	return &desc->txd;
++}
++
++
++/**
++ * ftdmac020_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++		unsigned int sg_len, enum dma_transfer_direction direction,
++		unsigned long flags)
++{
++	struct ftdmac020_dma_slave *slave = chan->private;
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int src_shift, dst_shift;
++	unsigned int i;
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s, please call dmaengine_slave_config() first! \n", __func__);
++		return NULL;
++	}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		src_shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		src_shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		src_shift = 2;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++    switch (slave->common.dst_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		dst_shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		dst_shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		dst_shift = 2;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++	if (slave->src_size > FTDMAC020_BURST_SZ_256 || slave->src_size < FTDMAC020_BURST_SZ_1) {
++		dev_err(chan2dev(chan), "%s: incorrect src_size %d\n", __func__, slave->src_size);
++		BUG();
++	}
++
++	switch (direction) {
++	case DMA_MEM_TO_DEV:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++            if (unlikely(!pfn_valid((mem >> PAGE_SHIFT)))) {
++                dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, mem);
++                goto err;
++            }
++			tmp = ftdmac020_create_chain(ftchan, desc,
++				mem, slave->common.dst_addr, len,
++				src_shift, dst_shift, 0, 1);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC020_CFG_DST_HANDSHAKE_EN
++				| FTDMAC020_CFG_DST_HANDSHAKE(slave->handshake);
++		break;
++	case DMA_DEV_TO_MEM:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++            if (unlikely(!pfn_valid((mem >> PAGE_SHIFT)))) {
++                dev_err(chan2dev(chan), "%s: incorrect physical address 0x%x \n", __func__, mem);
++                goto err;
++            }
++
++			tmp = ftdmac020_create_chain(ftchan, desc,
++				slave->common.src_addr, mem, len,
++				src_shift, dst_shift, 1, 0);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC020_CFG_SRC_HANDSHAKE_EN
++				| FTDMAC020_CFG_SRC_HANDSHAKE(slave->handshake);
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n",
++			__func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++	chan->private = NULL;   /* got the parameter already, so free it */
++	ftchan->transaction_type = DMA_SLAVE;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftdmac020_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++		unsigned long arg)
++{
++	struct ftdmac020_chan *ftchan;
++	unsigned long       flags;
++	int ret = -ENXIO;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (cmd == DMA_SLAVE_CONFIG) {
++		struct dma_slave_config *slave_config = (struct dma_slave_config *)arg;
++		struct ftdmac020_dma_slave  *dma_slave;
++
++		dma_slave = container_of(slave_config, struct ftdmac020_dma_slave, common);
++		chan->private = dma_slave;
++		ret = 0;
++	}
++
++	if (cmd == DMA_TERMINATE_ALL) {
++		/*
++		 * This is only called when something went wrong elsewhere, so
++		 * we don't really care about the data. Just disable the channel.
++		 */
++		DMAC020_LOCK(&ftchan->lock);
++		ftdmac020_stop_channel(ftchan);
++		ftchan->transaction_type = DMA_TX_TYPE_END;
++		ftdmac020_finish_all_chains(ftchan);
++        /* self test again */
++		if (!list_empty(&ftchan->active_list))
++	        panic("%s, ftchan->active_list is not empty2! \n", __func__);
++        DMAC020_UNLOCK(&ftchan->lock);
++	}
++
++	return ret;
++}
++
++/**
++ * ftdmac020_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftdmac020_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		struct dma_tx_state *txstate)
++{
++	struct ftdmac020_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftdmac020_issue_pending - try to active work
++ * @chan: target DMA channel
++ */
++static void ftdmac020_issue_pending(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++    unsigned long       flags;
++
++    if (flags)  {}
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	DMAC020_LOCK(&ftchan->lock);
++	if (list_empty(&ftchan->active_list))
++	    printk("%s, ftchan->active_list is empty! \n", __func__);
++    BUG_ON(list_empty(&ftchan->active_list));
++	/* get first descriptor and go */
++	ftdmac020_start_new_chain(ftchan);
++	DMAC020_UNLOCK(&ftchan->lock);
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftdmac020_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftdmac020 *ftdmac020;
++	struct dma_device *dma;
++	int irq, i , err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftdmac020 = kzalloc(sizeof(*ftdmac020), GFP_KERNEL);
++	if (!ftdmac020) {
++		return -ENOMEM;
++	}
++
++	dma = &ftdmac020->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftdmac020);
++	ftdmac020->id = pdev->id;
++
++	/* map io memory */
++	ftdmac020->res = request_mem_region(res->start, res->end - res->start + 1,
++			dev_name(&pdev->dev));
++	if (ftdmac020->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftdmac020->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftdmac020->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* create a pool of consistent memory blocks for hardware descriptors */
++	ftdmac020->dma_desc_pool = dma_pool_create("ftdmac020_desc_pool",
++			&pdev->dev, sizeof(struct ftdmac020_desc),
++			8 /* double word alignment */, 0);
++	if (!ftdmac020->dma_desc_pool) {
++		dev_err(&pdev->dev, "No memory for descriptor pool\n");
++		err = -ENOMEM;
++		goto err_pool_create;
++	}
++
++	/* force dma off, just in case */
++	ftdmac020_disable(ftdmac020);
++
++	/* initialize channels and create tasklet per channel */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device	= dma;
++		ftchan->common.cookie	= DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftdmac020		= ftdmac020;
++		ftchan->completed_cookie	= DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftdmac020_tasklet, (unsigned long)ftchan);
++		list_add_tail(&ftchan->common.device_node /*new*/, &dma->channels /*head*/);
++	}
++
++	/* clear all pending interrupts */
++	iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_TCICR);
++	iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_EAICR);
++
++    /* sync dma_req */
++    iowrite32(0xFF, ftdmac020->base + FTDMAC020_OFFSET_SYNC);	
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftdmac020_alloc_chan_resources;
++	dma->device_free_chan_resources	= ftdmac020_free_chan_resources;
++	dma->device_prep_dma_memcpy	= ftdmac020_prep_dma_memcpy;
++	dma->device_prep_dma_memset 	= ftdmac020_prep_dma_memset;
++	dma->device_prep_slave_sg	= ftdmac020_prep_slave_sg;
++	dma->device_prep_dma_cyclic = ftdmac020_prep_dma_cyclic;
++	dma->device_control		    = ftdmac020_control;
++	dma->device_tx_status		= ftdmac020_tx_status;
++	dma->device_issue_pending	= ftdmac020_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask); //for replacing memcpy by DMA
++	dma_cap_set(DMA_MEMSET, dma->cap_mask); //for replacing memset by DMA
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);  //for normal DMA IO
++	dma_cap_set(DMA_CYCLIC, dma->cap_mask); //for audio
++
++	err = request_irq(irq, ftdmac020_interrupt, 0, pdev->name, ftdmac020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_irq;
++	}
++
++	ftdmac020->irq = irq;
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	ftdmac020_enable(ftdmac020);
++	dev_info(&pdev->dev,
++		"DMA engine driver: irq %d, mapped at 0x%p\n",
++		irq, ftdmac020->base);
++
++	return 0;
++
++err_register:
++	free_irq(irq, ftdmac020);
++err_irq:
++	dma_pool_destroy(ftdmac020->dma_desc_pool);
++err_pool_create:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftdmac020->base);
++err_ioremap:
++	release_resource(ftdmac020->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac020);
++	return err;
++}
++
++static int __exit ftdmac020_remove(struct platform_device *pdev)
++{
++	struct ftdmac020 *ftdmac020;
++	int i;
++
++	ftdmac020 = platform_get_drvdata(pdev);
++
++	ftdmac020_disable(ftdmac020);
++	dma_async_device_unregister(&ftdmac020->dma);
++
++	free_irq(ftdmac020->irq, ftdmac020);
++	dma_pool_destroy(ftdmac020->dma_desc_pool);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftdmac020->base);
++	release_resource(ftdmac020->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac020);
++
++	return 0;
++}
++
++/**
++ * ftdmac020_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac020_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac020_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id))
++{
++    if (platform_chan_filter != NULL) {
++        printk("%s, platform_chan_filter was registered already! \n", __func__);
++        return -1;
++    }
++
++    platform_chan_filter = chan_filter_fn;
++
++    return 0;
++}
++
++static struct platform_driver ftdmac020_driver = {
++	.probe		= ftdmac020_probe,
++	.remove		= __exit_p(ftdmac020_remove),
++	.driver		= {
++		.name	= "ftdmac020",
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftdmac020_init(void)
++{
++	int ret = 0;
++	if (MAX_CYCLE_PER_BLOCK & ~FTDMAC020_CYC_MASK)
++		panic("%s, invalid MAX_CYCLE_PER_BLOCK: 0x%x \n", __func__, MAX_CYCLE_PER_BLOCK);
++
++	if ((ret = platform_driver_register(&ftdmac020_driver))) {
++		printk("failed to register DMAC020 driver\n");
++		return ret;
++	}
++	return ret;
++}
++
++static void __exit ftdmac020_exit(void)
++{
++	platform_driver_unregister(&ftdmac020_driver);
++}
++
++module_init(ftdmac020_init);
++module_exit(ftdmac020_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTDMAC020 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM/ftintc010.c b/arch/arm/mach-GM/ftintc010.c
+new file mode 100644
+index 00000000..c07d89c3
+--- /dev/null
++++ b/arch/arm/mach-GM/ftintc010.c
+@@ -0,0 +1,444 @@
++/*
++ *  linux/arch/arm/mach-GM/ftintc010.c
++ *
++ *  Faraday FTINTC010 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++
++#include <asm/mach/irq.h>
++#include <mach/ftintc010.h>
++
++struct ftintc010_chip_data {
++	unsigned int irq_offset;
++	void __iomem *base;
++};
++
++#ifndef MAX_FTINTC010_NR
++#define MAX_FTINTC010_NR	1
++#endif
++
++static struct ftintc010_chip_data ftintc010_data[MAX_FTINTC010_NR];
++static DEFINE_SPINLOCK(ftintc010_lock);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline void __iomem *ftintc010_base(unsigned int irq)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_chip_data(irq);
++	
++	return chip_data->base;
++}
++
++/*
++ * return hardware irq number
++ */
++static inline unsigned int ftintc010_irq(unsigned int irq)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_chip_data(irq);
++	
++	return irq - chip_data->irq_offset;
++}
++
++static inline void ftintc010_clear_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	if (hw_irq < 32) {
++		mask = 1 << hw_irq;
++
++		writel(mask, base + FTINTC010_OFFSET_IRQCLEAR);
++	} else {
++		mask = 1 << (hw_irq - 32);
++		writel(mask, base + FTINTC010_OFFSET_IRQCLEAREX);
++	}
++}
++
++static inline void ftintc010_mask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	if (hw_irq < 32) {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASK);
++		mask &= ~(1 << hw_irq);
++		writel(mask, base + FTINTC010_OFFSET_IRQMASK);
++	} else {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASKEX);
++		mask &= ~(1 << (hw_irq - 32));
++		writel(mask, base + FTINTC010_OFFSET_IRQMASKEX);
++	}
++}
++
++static inline void ftintc010_unmask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	if (hw_irq < 32) {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASK);
++		mask |= 1 << hw_irq;
++		writel(mask, base + FTINTC010_OFFSET_IRQMASK);
++	} else {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASKEX);
++		mask |= 1 << (hw_irq - 32);
++		writel(mask, base + FTINTC010_OFFSET_IRQMASKEX);
++	}
++}
++
++/******************************************************************************
++ * struct irq_chip functions
++ *****************************************************************************/
++static inline void ftintc010_set_trig_mode(void __iomem *base, unsigned int hw_irq, int mode)
++{
++	unsigned int irqmode, fiqmode;
++
++	/*
++	 * 0: level trigger
++	 * 1: edge trigger
++	 */
++	if (hw_irq < 32) {
++		irqmode = readl(base + FTINTC010_OFFSET_IRQMODE);
++		if (mode)
++			irqmode |= 1 << hw_irq;
++		else
++			irqmode &= ~(1 << hw_irq);
++		writel(irqmode, base + FTINTC010_OFFSET_IRQMODE);
++	} else {
++		irqmode = readl(base + FTINTC010_OFFSET_IRQMODEEX);
++		if (mode)
++			irqmode |= 1 << (hw_irq - 32);
++		else
++			irqmode &= ~(1 << (hw_irq - 32));
++		writel(irqmode, base + FTINTC010_OFFSET_IRQMODEEX);
++	}
++	
++	/* fiq */
++	if (hw_irq < 32) {
++	    fiqmode = readl(base + FTINTC010_OFFSET_FIQMODE);
++		if (mode)
++			fiqmode |= 1 << hw_irq;
++		else
++			fiqmode &= ~(1 << hw_irq);
++		writel(fiqmode, base + FTINTC010_OFFSET_FIQMODE);
++	} else {
++	    fiqmode = readl(base + FTINTC010_OFFSET_FIQMODEEX);
++		if (mode)
++			fiqmode |= 1 << (hw_irq - 32);
++		else
++			fiqmode &= ~(1 << (hw_irq - 32));
++		writel(fiqmode, base + FTINTC010_OFFSET_FIQMODEEX);
++	}
++}
++
++static inline void ftintc010_set_trig_level(void __iomem *base, unsigned int hw_irq, int level)
++{
++	unsigned int irqlevel, fiqlevel;
++
++	/*
++	 * 0: active-high level trigger / rising edge trigger
++	 * 1: active-low level trigger / falling edge trigger
++	 */
++	if (hw_irq < 32) {
++		irqlevel = readl(base + FTINTC010_OFFSET_IRQLEVEL);
++		if (level)
++			irqlevel |= 1 << hw_irq;
++		else
++			irqlevel &= ~(1 << hw_irq);
++		writel(irqlevel, base + FTINTC010_OFFSET_IRQLEVEL);
++	} else {
++		irqlevel = readl(base + FTINTC010_OFFSET_IRQLEVELEX);
++		if (level)
++			irqlevel |= 1 << (hw_irq - 32);
++		else
++			irqlevel &= ~(1 << (hw_irq - 32));
++		writel(irqlevel, base + FTINTC010_OFFSET_IRQLEVELEX);
++	}
++	
++	/* fiq */
++	if (hw_irq < 32) {
++		fiqlevel = readl(base + FTINTC010_OFFSET_FIQLEVEL);
++		if (level)
++			fiqlevel |= 1 << hw_irq;
++		else
++			fiqlevel &= ~(1 << hw_irq);
++		writel(irqlevel, base + FTINTC010_OFFSET_FIQLEVEL);
++	} else {
++		fiqlevel = readl(base + FTINTC010_OFFSET_FIQLEVELEX);
++		if (level)
++			fiqlevel |= 1 << (hw_irq - 32);
++		else
++			irqlevel &= ~(1 << (hw_irq - 32));
++		writel(fiqlevel, base + FTINTC010_OFFSET_FIQLEVELEX);
++	}
++}
++
++static int ftintc010_set_type(struct irq_data *data, unsigned int type)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++	int mode = 0;
++	int level = 0;
++
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_LEVEL_HIGH:
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_EDGE_RISING:
++		mode = 1;
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_set_trig_mode(base, hw_irq, mode);
++	ftintc010_set_trig_level(base, hw_irq, level);
++	spin_unlock(&ftintc010_lock);
++	return 0;
++}
++/*
++ * Edge trigger IRQ chip methods
++ */
++static void ftintc010_edge_ack(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_clear_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static void ftintc010_mask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_mask_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static void ftintc010_unmask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_unmask_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static struct irq_chip ftintc010_edge_chip = {
++	.irq_ack	= ftintc010_edge_ack,
++	.irq_mask	= ftintc010_mask,
++	.irq_unmask	= ftintc010_unmask,
++	.irq_set_type	= ftintc010_set_type,
++};
++
++/*
++ * Level trigger IRQ chip methods
++ */
++static void ftintc010_level_ack(struct irq_data *data)
++{
++	/* do nothing */
++	if (data)   {}
++}
++
++static struct irq_chip ftintc010_level_chip = {
++	.irq_ack	= ftintc010_level_ack,
++	.irq_mask	= ftintc010_mask,
++	.irq_unmask	= ftintc010_unmask,
++	.irq_set_type	= ftintc010_set_type,
++};
++
++/******************************************************************************
++ * initialization functions
++ *****************************************************************************/
++static void ftintc010_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_handler_data(irq);
++	struct irq_chip *chip = irq_get_chip(irq);
++	unsigned int cascade_irq, hw_irq;
++	unsigned long status;
++
++	/* defined in asm/mach/irq.h. 
++	 * mask the primary's irq.
++	 */
++	chained_irq_enter(chip, desc);
++
++	status = readl(chip_data->base + FTINTC010_OFFSET_IRQSTATUS);
++
++	if (status) {
++		hw_irq = ffs(status) - 1;
++	} else {
++		status = readl(chip_data->base + FTINTC010_OFFSET_IRQSTATUSEX);
++
++		if (!status)
++			goto out;
++
++		hw_irq = ffs(status) - 1 + 32;
++	}
++
++	cascade_irq = hw_irq + chip_data->irq_offset;
++	generic_handle_irq(cascade_irq);
++
++out:
++	/* primary controller unmasking */
++	chained_irq_exit(chip, desc);
++}
++
++void __init ftintc010_cascade_irq(unsigned int ftintc010_nr, unsigned int irq)
++{
++	if (ftintc010_nr >= MAX_FTINTC010_NR)
++		BUG();
++		
++	if (irq_set_handler_data(irq, &ftintc010_data[ftintc010_nr]) != 0)
++		BUG();
++
++	irq_set_chained_handler(irq, ftintc010_handle_cascade_irq);
++}
++
++/* reconfigure the irq type. Maybe the original is edge trigger, now change to level trigger 
++ * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
++ */
++int ftintc010_set_irq_type(unsigned int irq, unsigned int type)
++{            
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++	case IRQ_TYPE_LEVEL_HIGH:
++		irq_set_chip(irq, &ftintc010_level_chip);
++		irq_set_handler(irq, handle_level_irq);
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++	case IRQ_TYPE_EDGE_RISING:
++		irq_set_chip(irq, &ftintc010_edge_chip);
++		irq_set_handler(irq, handle_edge_irq);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++    
++    /* kernel function */
++	return irq_set_irq_type(irq, type);
++}
++
++/*
++ * Initialization of master interrupt controller, after this INTC is
++ * enabled, the rest of Linux initialization codes can then be completed.
++ * For example, timer interrupts and UART interrupts must be enabled during
++ * the boot process.
++ */
++void __init ftintc010_init(unsigned int ftintc010_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc010_trigger_type *trigger_type)
++{
++	int irq;
++	int i;
++
++	if (ftintc010_nr >= MAX_FTINTC010_NR)
++		BUG();
++    
++	ftintc010_data[ftintc010_nr].base = base;
++	ftintc010_data[ftintc010_nr].irq_offset = irq_start;
++
++	/*
++	 * mask all interrupts
++	 */
++	writel(0, base + FTINTC010_OFFSET_IRQMASK);
++	writel(0, base + FTINTC010_OFFSET_FIQMASK);
++	writel(~0, base + FTINTC010_OFFSET_IRQCLEAR);
++	writel(~0, base + FTINTC010_OFFSET_FIQCLEAR);
++
++	writel(0, base + FTINTC010_OFFSET_IRQMASKEX);
++	writel(~0, base + FTINTC010_OFFSET_IRQCLEAREX);
++	writel(0, base + FTINTC010_OFFSET_FIQMASKEX);
++	writel(~0, base + FTINTC010_OFFSET_FIQCLEAREX);
++
++	/*
++	 * setup trigger mode and level
++	 */
++	writel(trigger_type->irqmode, base + FTINTC010_OFFSET_IRQMODE);
++	writel(trigger_type->irqlevel, base + FTINTC010_OFFSET_IRQLEVEL);
++	writel(trigger_type->fiqmode, base + FTINTC010_OFFSET_FIQMODE);
++	writel(trigger_type->fiqlevel, base + FTINTC010_OFFSET_FIQLEVEL);
++
++	writel(trigger_type->irqmodeex, base + FTINTC010_OFFSET_IRQMODEEX);
++	writel(trigger_type->irqlevelex, base + FTINTC010_OFFSET_IRQLEVELEX);
++	writel(trigger_type->fiqmodeex, base + FTINTC010_OFFSET_FIQMODEEX);
++	writel(trigger_type->fiqlevelex, base + FTINTC010_OFFSET_FIQLEVELEX);
++
++
++	/*
++	 * setup the linux irq subsystem. 
++	 * Note: for FIQ subsystem, it not supported in linux. Instead, we have own FIQ subsystem.
++	 */
++	irq = irq_start;
++	for (i = 0; i < 32; i++) {
++		if (trigger_type->irqmode & (1 << i)) {
++		    irq_set_chip(irq, &ftintc010_edge_chip);
++			irq_set_handler(irq, handle_edge_irq);
++		} else {
++		    irq_set_chip(irq, &ftintc010_level_chip);
++			irq_set_handler(irq, handle_level_irq);
++		}
++
++		irq_set_chip_data(irq, &ftintc010_data[ftintc010_nr]);
++		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++		irq++;
++	}
++
++
++    /* keep irq number counting up */
++	for (i = 0; i < 32; i++) {
++		if (trigger_type->irqmodeex & (1 << i)) {
++			irq_set_chip(irq, &ftintc010_edge_chip);
++			irq_set_handler(irq, handle_edge_irq);
++		} else {
++			irq_set_chip(irq, &ftintc010_level_chip);
++			irq_set_handler(irq, handle_level_irq);
++		}
++
++		irq_set_chip_data(irq, &ftintc010_data[ftintc010_nr]);
++		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++		irq++;
++	}
++}
+diff --git a/arch/arm/mach-GM/ftintc030.c b/arch/arm/mach-GM/ftintc030.c
+new file mode 100644
+index 00000000..25883665
+--- /dev/null
++++ b/arch/arm/mach-GM/ftintc030.c
+@@ -0,0 +1,368 @@
++/*
++ *  linux/arch/arm/mach-GM-Duo/FTINTC030.c
++ *
++ *  Faraday FTINTC030 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++
++#include <asm/mach/irq.h>
++#include <mach/ftintc030.h>
++
++struct ftintc030_chip_data {
++	unsigned int irq_offset;
++	void __iomem *base;
++};
++
++#ifndef MAX_FTINTC030_NR
++#define MAX_FTINTC030_NR	1
++#endif
++
++static struct ftintc030_chip_data ftintc030_data[MAX_FTINTC030_NR];
++static DEFINE_SPINLOCK(ftintc030_lock);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline void __iomem *ftintc030_base(unsigned int irq)
++{
++	struct ftintc030_chip_data *chip_data = irq_get_chip_data(irq);
++
++	return chip_data->base;
++}
++
++/*
++ * return hardware irq number
++ */
++static inline unsigned int ftintc030_irq(unsigned int irq)
++{
++	struct ftintc030_chip_data *chip_data = irq_get_chip_data(irq);
++
++	return irq - chip_data->irq_offset;
++}
++
++static inline void ftintc030_clear_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	mask = 1 << (hw_irq % 32);
++	if (hw_irq < 64)
++		writel(mask, base + FTINTC030_OFFSET_IRQCLEAR + (0x20 * (hw_irq / 32)));
++	else
++		writel(mask, base + FTINTC030_OFFSET_IRQCLEAR + (0x20 * ((hw_irq / 32) + 1)));
++}
++
++static inline void ftintc030_mask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	volatile unsigned int target_base, value;
++    int i = 0;
++    
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++    target_base = (u32)base + FTINTC030_OFFSET_IRQTARGET + (hw_irq >> 5) * 4;
++    value = readl(target_base);
++    value &= ~(1 << (hw_irq & 0x1F));
++    writel(value, target_base);
++    
++    /* FIXME: work around for IC bug */
++    while (readl(target_base) != value) {
++        writel(value, target_base);
++        i ++;
++        if (i > 10) {
++            printk("%s, ERROR! \n", __func__);
++            break;
++        }
++    }
++}
++
++static inline void ftintc030_unmask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	volatile unsigned int target_base, value;
++    int i = 0;
++    
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	target_base = (u32)base + FTINTC030_OFFSET_IRQTARGET + (hw_irq >> 5) * 4;
++    value = readl(target_base);
++    value |= (1 << (hw_irq & 0x1F));
++    writel(value, target_base);
++    
++    /* FIXME: work around for IC bug */
++    while (readl(target_base) != value) {
++        writel(value, target_base);
++        i ++;
++        if (i > 10) {
++            printk("%s, ERROR! \n", __func__);
++            break;
++        }
++    }
++}
++
++/******************************************************************************
++ * struct irq_chip functions
++ *****************************************************************************/
++static inline void ftintc030_set_trig_mode(void __iomem *base, unsigned int hw_irq, int mode)
++{
++	unsigned int irqmode, reg_offset;
++
++	/*
++	 * 0: level trigger
++	 * 1: edge trigger
++	 */
++	if (hw_irq < 64)
++	    reg_offset = 0x20 * (hw_irq >> 5);
++	else
++	    reg_offset = 0x20 * ((hw_irq >> 5) + 1);
++	    	 
++	irqmode = readl(base + FTINTC030_OFFSET_IRQMODE + reg_offset);
++
++	if(mode)
++    	irqmode |= 1 << (hw_irq % 32);
++    else
++    	irqmode &= ~(1 << (hw_irq % 32));
++
++	writel(irqmode, base + FTINTC030_OFFSET_IRQMODE + reg_offset);
++}
++
++static inline void ftintc030_set_trig_level(void __iomem *base, unsigned int hw_irq, int level)
++{
++	unsigned int irqlevel, reg_offset;
++
++	/*
++	 * 0: active-high level trigger / rising edge trigger
++	 * 1: active-low level trigger / falling edge trigger
++	 */
++	if (hw_irq < 64)
++	    reg_offset = 0x20 * (hw_irq >> 5);
++	else
++	    reg_offset = 0x20 * ((hw_irq >> 5) + 1);
++	        	    
++	irqlevel = readl(base + FTINTC030_OFFSET_IRQLEVEL + reg_offset);
++	
++	if(level)
++    	irqlevel |= 1 << (hw_irq % 32);
++    else
++    	irqlevel &= ~(1 << (hw_irq % 32));
++    	
++	writel(irqlevel, base + FTINTC030_OFFSET_IRQLEVEL + reg_offset);
++}
++
++static int ftintc030_set_type(struct irq_data *data, unsigned int type)
++{
++	unsigned int hw_irq = ftintc030_irq(data->irq);
++	void __iomem *base = ftintc030_base(data->irq);
++	int mode = 0;
++	int level = 0;
++
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_LEVEL_HIGH:
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_EDGE_RISING:
++		mode = 1;
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	spin_lock(&ftintc030_lock);
++	ftintc030_set_trig_mode(base, hw_irq, mode);
++	ftintc030_set_trig_level(base, hw_irq, level);
++	spin_unlock(&ftintc030_lock);
++	return 0;
++}
++/*
++ * Edge trigger IRQ chip methods
++ */
++static void ftintc030_edge_ack(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc030_irq(data->irq);
++	void __iomem *base = ftintc030_base(data->irq);
++
++	spin_lock(&ftintc030_lock);
++	ftintc030_clear_irq(base, hw_irq);
++	spin_unlock(&ftintc030_lock);
++}
++
++static void ftintc030_mask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc030_irq(data->irq);
++	void __iomem *base = ftintc030_base(data->irq);
++
++	spin_lock(&ftintc030_lock);
++	ftintc030_mask_irq(base, hw_irq);
++	spin_unlock(&ftintc030_lock);
++}
++
++static void ftintc030_unmask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc030_irq(data->irq);
++	void __iomem *base = ftintc030_base(data->irq);
++
++	spin_lock(&ftintc030_lock);
++	ftintc030_unmask_irq(base, hw_irq);
++	spin_unlock(&ftintc030_lock);
++}
++
++static struct irq_chip ftintc030_edge_chip = {
++	.irq_ack	= ftintc030_edge_ack,
++	.irq_mask	= ftintc030_mask,
++	.irq_unmask	= ftintc030_unmask,
++	.irq_set_type	= ftintc030_set_type,
++};
++
++/*
++ * Level trigger IRQ chip methods
++ */
++static void ftintc030_level_ack(struct irq_data *data)
++{
++	/* do nothing */
++	if (data)   {}
++}
++
++static struct irq_chip ftintc030_level_chip = {
++	.irq_ack	= ftintc030_level_ack,
++	.irq_mask	= ftintc030_mask,
++	.irq_unmask	= ftintc030_unmask,
++	.irq_set_type	= ftintc030_set_type,
++};
++
++/******************************************************************************
++ * initialization functions
++ *****************************************************************************/
++/* reconfigure the irq type. Maybe the original is edge trigger, now change to level trigger
++ * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
++ */
++int ftintc030_set_irq_type(unsigned int irq, unsigned int type)
++{
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++	case IRQ_TYPE_LEVEL_HIGH:
++		irq_set_chip(irq, &ftintc030_level_chip);
++		irq_set_handler(irq, handle_level_irq);
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++	case IRQ_TYPE_EDGE_RISING:
++		irq_set_chip(irq, &ftintc030_edge_chip);
++		irq_set_handler(irq, handle_edge_irq);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++    /* kernel function */
++	return irq_set_irq_type(irq, type);
++}
++
++/*
++ * Initialization of master interrupt controller, after this INTC is
++ * enabled, the rest of Linux initialization codes can then be completed.
++ * For example, timer interrupts and UART interrupts must be enabled during
++ * the boot process.
++ */
++void __init ftintc030_init(unsigned int ftintc030_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc030_trigger_type *trigger_type)
++{
++	int irq;
++	int i, j, offset;
++
++	if (ftintc030_nr >= MAX_FTINTC030_NR)
++		BUG();
++
++	ftintc030_data[ftintc030_nr].base = base;
++	ftintc030_data[ftintc030_nr].irq_offset = irq_start;
++
++	irq = irq_start;
++	/*
++	 * mask all interrupts
++	 */
++	for(i = 0; i < PLATFORM_IRQ_TOTALCOUNT / 32; i++) {
++	    if(i >= 2)
++		    offset = 0x20 * (i + 1);
++	    else
++		    offset = 0x20 * i;
++
++#ifndef CONFIG_PLATFORM_GM8210_S //only allow master cpu to configure this
++	    writel(0xFFFFFFFF, base + FTINTC030_OFFSET_IRQENABLE + offset);   //ENABLE register
++	    writel(~0, base + FTINTC030_OFFSET_IRQCLEAR + offset);
++
++	    /*
++	     * setup trigger mode and level
++	     */
++  	    writel(trigger_type->irqmode[i], base + FTINTC030_OFFSET_IRQMODE + offset);
++  	    writel(trigger_type->irqlevel[i], base + FTINTC030_OFFSET_IRQLEVEL + offset);
++  	    writel(trigger_type->fiqmode[i], base + FTINTC030_OFFSET_IRQMODE + offset);
++  	    writel(trigger_type->fiqlevel[i], base + FTINTC030_OFFSET_IRQLEVEL + offset);
++#endif
++  	    /*
++  	     * setup the linux irq subsystem.
++  	     * Note: for FIQ subsystem, it not supported in linux. Instead, we have own FIQ subsystem.
++  	     */
++
++  	    for (j = 0; j < 32; j++) {
++    		if (trigger_type->irqmode[i] & (1 << j)) {
++    		    irq_set_chip(irq, &ftintc030_edge_chip);
++    			irq_set_handler(irq, handle_edge_irq);
++    		} else {
++    		    irq_set_chip(irq, &ftintc030_level_chip);
++    			irq_set_handler(irq, handle_level_irq);
++    		}
++
++    		irq_set_chip_data(irq, &ftintc030_data[ftintc030_nr]);
++    		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++    		irq++;
++	    }
++	}
++}
++
++/*
++ * Set a highlevel chained flow handler for a given IRQ.
++ * ftintc030_nr: INTC030 index
++ * irq: which irq number is the cascade irq
++ * handler: the handler function of this cascade irq
++ * handler_data: private data of the handler
++ */
++void ftintc030_setup_chain_irq(unsigned int ftintc030_nr, unsigned int irq, void *handler, void *handler_data)
++{
++    if (ftintc030_nr) {}
++
++    if (irq_set_handler_data(irq, handler_data) != 0)
++		panic("%s fail! \n", __func__);
++
++    irq_set_chained_handler(irq, handler);
++}
+diff --git a/arch/arm/mach-GM/ftpmu010.c b/arch/arm/mach-GM/ftpmu010.c
+new file mode 100644
+index 00000000..0351df84
+--- /dev/null
++++ b/arch/arm/mach-GM/ftpmu010.c
+@@ -0,0 +1,1115 @@
++/*
++ *  Copyright (C) 2010 Grain-Media Technology.
++ *
++ * 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 <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/hardirq.h>
++#include <linux/semaphore.h>
++#include <linux/sched.h>
++#include <asm/io.h>
++#include <linux/proc_fs.h>
++#include <mach/ftpmu010.h>
++
++#define  REG_ARRAY_SZ   30      //Max value for register array
++
++/* Local Variables
++ */
++static u32 fd = 1;
++static struct proc_dir_entry *pmu_proc_root = NULL;
++static struct proc_dir_entry *attribute_proc = NULL;
++static struct proc_dir_entry *regInfo_proc = NULL;
++static struct proc_dir_entry *chipver_proc = NULL;
++
++static ftpmu010_gate_clk_t *pmu_clkgate_tbl = NULL;
++static int (*pmu_ctrl_handler) (u32 cmd, u32 data1, u32 data2) = NULL;
++
++/* Local Functions
++ */
++static int ftpmu010_proc_init(void);
++
++/* MACROs
++ */
++#define ATTR_LIST               ftpmu10.attr_list
++#define REGINFO_LIST            ftpmu10.reginfo_list
++#define LIST_LOCK               spin_lock_irqsave(&ftpmu10.spinlock, flags)
++#define LIST_UNLOCK             spin_unlock_irqrestore(&ftpmu10.spinlock, flags)
++#define REGINFO_OFFSET(x,y)     (x)->pmuReg_info.pRegArray[(y)].reg_off
++#define REGINFO_BITSMASK(x,y)   (x)->pmuReg_info.pRegArray[(y)].bits_mask
++#define REGINFO_LOCKBITS(x,y)   (x)->pmuReg_info.pRegArray[(y)].lock_bits
++#define REGINFO_NAME(x)         (x)->pmuReg_info.name
++#define REGINFO_REGCNT(x)       (x)->pmuReg_info.num
++#define REGINFO_CLKSRC          (x)->pmuReg_info.clock_src
++
++typedef struct {
++    attrInfo_t attr_info;
++    struct list_head list;
++} attrInfo_node_t;
++
++typedef struct {
++    u32 fd;                     /* unique number */
++    pmuRegInfo_t pmuReg_info;
++    struct list_head list;
++    wait_queue_head_t wait_queue;       /* wait queue */
++    int waiting;
++    int ref_cnt;
++} pmuRegInfo_node_t;
++
++/* main structure
++ */
++static struct ftpmu10_s {
++    void __iomem *base;
++#ifdef USE_SEMA
++    struct semaphore sema;
++#else
++    spinlock_t spinlock;
++#endif
++    /* attribute list */
++    struct list_head attr_list;
++    /* register list */
++    struct list_head reginfo_list;
++} ftpmu10;
++
++/* Register a clok node.
++ * return value: 0 for success, < 0 for fail.
++ */
++int ftpmu010_register_attr(attrInfo_t * attr)
++{
++    unsigned long flags;
++    attrInfo_node_t *node;
++    int ret = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        //printk("PMU: %s \n", node->attr_info.name);
++
++        if (node->attr_info.attr_type == attr->attr_type) {
++            ret = -1;
++            break;
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    if (ret < 0)
++        return ret;
++
++    ret = -1;
++    node = kzalloc(sizeof(attrInfo_node_t), GFP_ATOMIC);
++    if (node) {
++        memcpy(&node->attr_info, attr, sizeof(attrInfo_t));
++        INIT_LIST_HEAD(&node->list);
++        list_add_tail(&node->list, &ATTR_LIST);
++        try_module_get(THIS_MODULE);
++        ret = 0;
++    }
++
++    return ret;
++}
++
++/* DeRegister a clok node.
++ * return value: 0 for success, < 0 for fail.
++ */
++int ftpmu010_deregister_attr(attrInfo_t * attr)
++{
++    unsigned long flags;
++    attrInfo_node_t *node, *ne;
++    int ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry_safe(node, ne, &ATTR_LIST, list) {
++        if (node->attr_info.attr_type == attr->attr_type) {
++            list_del_init(&node->list);
++            kfree(node);
++            module_put(THIS_MODULE);
++            ret = 0;
++            break;
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return ret;
++}
++
++/* get the content of the attribute
++ * return value: 0 for fail, > 0 for success
++ */
++unsigned int ftpmu010_get_attr(ATTR_TYPE_T attr_type)
++{
++    attrInfo_node_t *node;
++    unsigned int value = -1;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        if (node->attr_info.attr_type == attr_type) {
++            value = node->attr_info.value;
++            break;
++        }
++    }
++
++    return value;
++}
++
++/* register/de-register the register table
++ * return value:
++ *  give an unique fd if return value >= 0, otherwise < 0 if fail.
++ */
++int ftpmu010_register_reg(pmuRegInfo_t * info)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node, *new_node;
++    int i, j, ret = -1;
++    u32 reg_off;
++
++    /* sanity check */
++    if (unlikely(!strlen(info->name)))
++        return -1;
++
++    /* check if the register offset is duplicated */
++    for (i = 0; i < info->num; i++) {
++        reg_off = info->pRegArray[i].reg_off;
++
++        for (j = 0; j < info->num; j++) {
++            if (i == j)
++                continue;
++
++#if 1                           /* allow gather the mask, lock_bit .... */
++            if (reg_off == info->pRegArray[j].reg_off) {
++                info->pRegArray[i].bits_mask |= info->pRegArray[j].bits_mask;
++                info->pRegArray[i].lock_bits |= info->pRegArray[j].lock_bits;
++                info->pRegArray[i].init_val |= info->pRegArray[j].init_val;
++                info->pRegArray[i].init_mask |= info->pRegArray[j].init_mask;
++            }
++#else
++            if (reg_off == info->pRegArray[j].reg_off) {
++                printk("PMU: reg_offset 0x%x is duplicated! \n", reg_off);
++                return -1;
++            }
++#endif
++        }
++    }
++
++    /* self-test, bits_mask must cover lock_bits and init_val */
++    for (i = 0; i < info->num; i++) {
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].lock_bits) {
++            printk("PMU: %s wrong lock_bits 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].lock_bits, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].init_val) {
++            printk("PMU: %s wrong init_val 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_val, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].bits_mask) & info->pRegArray[i].init_mask) {
++            printk("PMU: %s wrong init_mask 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_mask, info->pRegArray[i].reg_off);
++            return -1;
++        }
++        if ((~info->pRegArray[i].init_mask) & info->pRegArray[i].init_val) {
++            printk("PMU: %s wrong init_val 0x%x or init_mask 0x%x in ofs 0x%x! \n", info->name,
++                   info->pRegArray[i].init_val, info->pRegArray[i].init_mask,
++                   info->pRegArray[i].reg_off);
++            return -1;
++        }
++    }
++
++    if (info->clock_src != ATTR_TYPE_NONE) {
++        if (ftpmu010_get_attr(info->clock_src) < 0) {
++            printk("PMU: %s registers non-existence clock source! \n", info->name);
++            return -1;
++        }
++    }
++
++    /* lock */
++    LIST_LOCK;
++
++    /* 1. check if duplicate registeration
++     */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (!strcmp(REGINFO_NAME(node), info->name)) {
++            /* allow the same node is multiple registered */
++            if ((info->num == REGINFO_REGCNT(node))
++                && !memcmp(info->pRegArray, node->pmuReg_info.pRegArray,
++                           info->num * sizeof(pmuReg_t))) {
++                node->ref_cnt++;
++                /* unlock */
++                LIST_UNLOCK;
++                return node->fd;
++            }
++            printk("PMU: %s was registed already! \n", info->name);
++            goto exit;
++        }
++    }
++
++    /* 2. check if the lockbits is overlap.
++     */
++    for (i = 0; i < info->num; i++) {
++        /* check the registers in each node */
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            for (j = 0; j < REGINFO_REGCNT(node); j++) {
++                if (info->pRegArray[i].reg_off != REGINFO_OFFSET(node, j))
++                    continue;
++
++                if (info->pRegArray[i].lock_bits & REGINFO_LOCKBITS(node, j)) {
++                    printk("PMU: lock_bits of %s is overlapped with %s in offset 0x%x! \n",
++                           info->name, REGINFO_NAME(node), info->pRegArray[i].reg_off);
++                    goto exit;
++                }
++            }                   /* loop j */
++        }
++    }                           /* loop i */
++
++    /* 3. sanity check is ok, create new node and chan it to the list
++     */
++    new_node = kzalloc(sizeof(pmuRegInfo_node_t), GFP_ATOMIC);
++    if (unlikely(!new_node)) {
++        ret = -ENOMEM;
++        goto exit;
++    }
++    new_node->fd = fd++;
++    new_node->ref_cnt = 1;
++    INIT_LIST_HEAD(&new_node->list);
++    memcpy(&new_node->pmuReg_info, info, sizeof(pmuRegInfo_t));
++    if (info->num >= REG_ARRAY_SZ)
++        panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++    new_node->pmuReg_info.pRegArray = kzalloc(REG_ARRAY_SZ * sizeof(pmuReg_t), GFP_ATOMIC);
++    if (unlikely(!new_node->pmuReg_info.pRegArray)) {
++        kfree(new_node);
++        ret = -ENOMEM;
++        goto exit;
++    }
++
++    /* init waitQ */
++    init_waitqueue_head(&new_node->wait_queue);
++
++    /* copy register array body */
++    if (info->num)
++        memcpy(new_node->pmuReg_info.pRegArray, info->pRegArray, info->num * sizeof(pmuReg_t));
++
++    list_add_tail(&new_node->list, &REGINFO_LIST);
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    ret = new_node->fd;
++    try_module_get(THIS_MODULE);
++
++    /* update to hardware */
++    for (i = 0; i < info->num; i++)
++        ftpmu010_write_reg(new_node->fd, info->pRegArray[i].reg_off, info->pRegArray[i].init_val,
++                           info->pRegArray[i].init_mask);
++
++    return ret;
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_deregister_reg(int fd)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node, *ne;
++    int ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry_safe(node, ne, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            if (--node->ref_cnt) {
++                ret = 0;
++                goto exit;
++            }
++            //printk("PMU: %s is deregistered. \n", node->pmuReg_info.name);
++            list_del_init(&node->list);
++            if (node->pmuReg_info.pRegArray)
++                kfree(node->pmuReg_info.pRegArray);
++            kfree(node);
++            module_put(THIS_MODULE);
++            ret = 0;
++            break;
++        }
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* lock/unlock/replace the bits in lock_bits field
++ * return value:
++ *  0 for success, < 0 for fail
++ */
++int ftpmu010_add_lockbits(int fd, unsigned int reg_off, unsigned int lock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    u32 *pLock_bits = NULL;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* do overlap check */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {   /* self check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                pLock_bits = &REGINFO_LOCKBITS(node, i);
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & lock_bits) {
++                    printk("PMU: %s new %#x is out of bits_mask %#x!\n", REGINFO_NAME(node),
++                           lock_bits, REGINFO_BITSMASK(node, i));
++                    goto exit;
++                }
++                ret = 0;
++                break;
++            }                   /* for i */
++        } else {
++            /* conflict check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                if (REGINFO_LOCKBITS(node, i) & lock_bits) {
++                    printk("PMU: %#x conflicts with lock_bits %#x of %s in off: %#x\n", lock_bits,
++                           REGINFO_LOCKBITS(node, i), REGINFO_NAME(node), reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }                       /* fd */
++    }
++
++    if (!ret)
++        *pLock_bits |= lock_bits;
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_del_lockbits(int fd, unsigned int reg_off, unsigned int unlock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            REGINFO_LOCKBITS(node, i) &= ~unlock_bits;
++            ret = 0;
++            break;
++        }
++        break;
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++int ftpmu010_update_lockbits(int fd, unsigned int reg_off, unsigned int new_lock_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    u32 *pLock_bits = NULL;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                pLock_bits = &REGINFO_LOCKBITS(node, i);
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & new_lock_bits) {
++                    printk("PMU: %s new 0x%x is out of bits_mask 0x%x!\n", REGINFO_NAME(node),
++                           new_lock_bits, REGINFO_BITSMASK(node, i));
++                    goto exit;
++                }
++                ret = 0;
++                break;
++            }                   /* for i */
++        } else {
++            /* conflict check */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                if (REGINFO_LOCKBITS(node, i) & new_lock_bits) {
++                    printk("PMU: new 0x%x conflicts with lock_bits 0x%x of %s\n", new_lock_bits,
++                           REGINFO_LOCKBITS(node, i), REGINFO_NAME(node));
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }
++    }
++
++    if (!ret)
++        *pLock_bits = new_lock_bits;
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* @int ftpmu010_bits_is_locked(int fd, int reg_off, unsigned int bits)
++ * @Purpose: This function is used to check if the bits are locked by any module or not.
++ * @Parameter:
++ *   reg_off: register offset
++ *   bits: the checked bits
++ * @Return:
++ *      If the any bit in bits is locked, then the returned value will be 0
++ *      otherwise, -1 is returned to indicates all bits are available.
++ *
++ */
++int ftpmu010_bits_is_locked(int fd, unsigned int reg_off, unsigned int bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        /* conflict check */
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            if (REGINFO_LOCKBITS(node, i) & bits) {
++                ret = 0;
++                goto exit;
++            }
++            break;
++        }
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* PMU register read/write
++ */
++unsigned int ftpmu010_read_reg(unsigned int reg_off)
++{
++    return ioread32(ftpmu10.base + reg_off);
++}
++
++/* return value < 0 for fail */
++int ftpmu010_write_reg(int fd, unsigned int reg_off, unsigned int val, unsigned int mask)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    /* sanity check */
++    if (unlikely(val & (~mask))) {
++        printk("%s: wrong mask:%#x or value:%#x in offset:%#x! \n", __func__, mask, val, reg_off);
++        goto exit;
++    }
++
++    if (unlikely(!mask)) {
++        ret = 0;
++        goto exit;              /* do nothing */
++    }
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd) {
++            ret = -1;
++            /* check if reg_off had been registered already */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                /* is mask within bits_mask ? */
++                if (~REGINFO_BITSMASK(node, i) & mask) {
++                    printk("PMU: %s writes with wrong mask 0x%x in off:%#x! \n",
++                           REGINFO_NAME(node), mask, reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                ret = 0;
++            }
++        }
++#if 0                           /* Bug fix, 2011/12/20 11:10�W��
++                                 * We don't need to check if my operation mask conflicts with the lockbits of others
++                                 */
++        else {
++            /* check if the bits is on lock_bits of others */
++            for (i = 0; i < REGINFO_REGCNT(node); i++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                /* is lock_bits conflicts with the input mask ? */
++                if (REGINFO_LOCKBITS(node, i) & mask) {
++                    printk("PMU: Wrong mask 0x%x conflicts with %s in off:%#x! \n", mask,
++                           REGINFO_NAME(node), reg_off);
++                    ret = -1;
++                    goto exit;
++                }
++                break;
++            }
++        }
++#endif
++    }
++
++    if (!ret) {
++        u32 tmp;
++
++        tmp = (ftpmu010_read_reg(reg_off) & (~mask));
++        tmp |= (val & mask);
++        iowrite32(tmp, ftpmu10.base + reg_off);
++    }
++
++  exit:
++    /* unlock */
++    LIST_UNLOCK;
++
++    if (ret < 0) {
++        dump_stack();
++        panic("Configure PMU fail! \n");
++    }
++
++    return ret;
++}
++
++/* PMU init function
++ * Input parameters: virtual address of PMU
++ *  tbl: clock gating table for IPs
++ *  pmu_handler: the callback from pmu to reload/reconfigure pmu. NULL if unecessary
++ * Return: 0 for success, < 0 for fail
++ */
++int __init ftpmu010_init(void __iomem * base, ftpmu010_gate_clk_t * tbl, void *pmu_handler)
++{
++    int i = 0;
++    ftpmu010_gate_clk_t *table = tbl;
++
++    ftpmu10.base = base;
++    spin_lock_init(&ftpmu10.spinlock);
++    INIT_LIST_HEAD(&ftpmu10.attr_list);
++    INIT_LIST_HEAD(&ftpmu10.reginfo_list);
++    /* proc function */
++    ftpmu010_proc_init();
++
++    /* self test */
++    while (table->midx != FTPMU_NONE) {
++        for (i = 0; i < table->num; i++) {
++            if (table->reg[i].bit_val & ~table->reg[i].bit_mask)
++                panic("%s, error gating clock table in ofs 0x%x of midx:%d! \n", __func__,
++                      table->reg[i].ofs, table->midx);
++        }
++        table++;
++    }
++
++    pmu_clkgate_tbl = tbl;
++    /* register the callback from pmu */
++    pmu_ctrl_handler = pmu_handler;
++
++    return 0;
++}
++
++/* Purpose: calculate the divisor by input clock
++ * Input: fd, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor(int fd, unsigned int in_clock, int near)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    unsigned int clock = 0;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        clock = ftpmu010_get_attr(node->pmuReg_info.clock_src);
++        if (clock == (u32) - 1)
++            return 0;
++
++        if (near)
++            clock += (in_clock >> 1);
++        /* n = n / base; return rem; */
++        do_div(clock, in_clock);
++        break;
++    }
++
++    LIST_UNLOCK;
++
++    return clock;
++}
++
++/* Purpose: calculate the divisor by input clock attribute
++ * Input: clock_src, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor2(ATTR_TYPE_T clock_src, unsigned int in_clock, int near)
++{
++    unsigned int clock = 0;
++
++    clock = ftpmu010_get_attr(clock_src);
++    if (clock == (u32) - 1)
++        return 0;
++    if (near)
++        clock += (in_clock >> 1);
++    /* n = n / base; return rem; */
++    do_div(clock, in_clock);
++
++    return clock;
++}
++
++/* @Purpose: request the pmu PIN
++ * @Parameter:
++ *      fd: unique identifier
++ *      reg_off: register offset
++ *      req_bits: request registers
++ *      b_wait: 1 for blocking until the resource is available
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_request_pins(int fd, unsigned int reg_off, unsigned int req_bits, int b_wait)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ofs, is_new, ret = 0;
++
++    if (b_wait) {
++        if (in_interrupt() || in_atomic())
++            panic("%s, wrong context in interrupt or atomic \n", __func__);
++    }
++
++    /* lock */
++    LIST_LOCK;
++    if (ftpmu010_bits_is_locked(fd, reg_off, req_bits) == -1) {
++        /* the bits are available */
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            if (node->fd != fd)
++                continue;
++
++            /* check if the offset exists ? */
++            is_new = 1;
++            for (i = 0; i < REGINFO_REGCNT(node); i ++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                REGINFO_BITSMASK(node, i) |= req_bits;
++                REGINFO_LOCKBITS(node, i) |= req_bits;
++                is_new = 0; /* this is not a new offset */
++                break;
++            }
++
++            if (is_new) { /* new node */
++                ofs = REGINFO_REGCNT(node);
++                if (ofs >= REG_ARRAY_SZ)
++                    panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++
++                REGINFO_OFFSET(node, ofs) = reg_off;
++                REGINFO_BITSMASK(node, ofs) = req_bits;
++                REGINFO_LOCKBITS(node, ofs) = req_bits;
++
++                REGINFO_REGCNT(node) ++;
++            }
++            break;
++        }
++    } else {
++        /* the bits are locked by others */
++        if (!b_wait) {
++            ret = -1;
++            goto exit;
++        }
++
++        ret = -1;
++        list_for_each_entry(node, &REGINFO_LIST, list) {
++            if (node->fd != fd)
++                continue;
++            ret = 0;
++            break;
++        }
++
++        if (ret == -1)
++            panic("%s, can't find fd in pmu module! \n", __func__);
++
++        node->waiting = 0;
++
++keep_wait:
++        LIST_UNLOCK;
++        wait_event_interruptible(node->wait_queue, node->waiting);
++        if (signal_pending(current))
++			return -ERESTARTSYS;
++        node->waiting = 0;
++
++        LIST_LOCK;
++
++        /* bits are freed */
++        if (ftpmu010_bits_is_locked(fd, reg_off, req_bits) == -1) {
++            ret = -1;
++            /* find the existed offset */
++            for (i = 0; i < REGINFO_REGCNT(node); i ++) {
++                if (REGINFO_OFFSET(node, i) != reg_off)
++                    continue;
++
++                REGINFO_BITSMASK(node, i) |= req_bits;
++                REGINFO_LOCKBITS(node, i) |= req_bits;
++                ret = 0;
++                break;
++            }
++
++            if (ret == -1) {
++                /* new offset */
++                ofs = REGINFO_REGCNT(node);
++                if (ofs >= REG_ARRAY_SZ)
++                    panic("%s, the array size %d is too small! \n", __func__, REG_ARRAY_SZ);
++                REGINFO_OFFSET(node, ofs) = reg_off;
++                REGINFO_BITSMASK(node, ofs) = req_bits;
++                REGINFO_LOCKBITS(node, ofs) = req_bits;
++                REGINFO_REGCNT(node) ++;
++                ret = 0;
++            }
++        } else {
++            goto keep_wait;
++        }
++    }
++
++exit:
++    LIST_UNLOCK;
++    return ret;
++}
++
++/* Purpose: release the pmu PIN
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_release_pins(int fd, unsigned int reg_off, unsigned int req_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, ret = -1;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd != fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            if (REGINFO_LOCKBITS(node, i) & req_bits) {
++                REGINFO_BITSMASK(node, i) &= ~req_bits;
++                REGINFO_LOCKBITS(node, i) &= ~req_bits;
++                ret = 0;
++            }
++            break;
++        }
++
++        break;
++    }
++
++    /* wake up the ones who are waiting for the pins */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        node->waiting = 1;
++        wake_up(&node->wait_queue);
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    return ret;
++}
++
++/* Purpose: check if the PINs was requested by others except myself.
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: those pins occupied by others. zero indicates the pin are available.
++ */
++unsigned int ftpmu010_pins_is_requested(int fd, unsigned int reg_off, unsigned int req_bits)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i;
++
++    /* lock */
++    LIST_LOCK;
++
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        if (node->fd == fd)
++            continue;
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            if (REGINFO_OFFSET(node, i) != reg_off)
++                continue;
++
++            req_bits &= REGINFO_LOCKBITS(node, i);
++            break;
++        }
++    }
++
++    /* unlock */
++    LIST_UNLOCK;
++
++    return req_bits;
++}
++
++/*
++ * This function is used to call pmu handler to reconfigure/reload the pmu setting
++ */
++int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2)
++{
++    int ret = -1;
++
++    if (pmu_ctrl_handler)
++        ret = (*pmu_ctrl_handler) (cmd, data1, data2);
++    else
++        printk("%s, pmu_ctrl_handler is not registered yet! \n", __func__);
++
++    return ret;
++}
++
++/* ------------------------------------------------------------------------------------
++ *  Proc function
++ * ------------------------------------------------------------------------------------
++ */
++
++ /* Attribute info
++  */
++static int proc_read_attribute_info(char *page, char **start, off_t off, int count, int *eof,
++                                    void *data)
++{
++    unsigned long flags;
++    attrInfo_node_t *node;
++    int len = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &ATTR_LIST, list) {
++        len += sprintf(page + len, "Attribute name : %s \n", node->attr_info.name);
++        len += sprintf(page + len, "Attribute type : %d \n", node->attr_info.attr_type);
++        if (node->attr_info.attr_type == ATTR_TYPE_CHIPVER) {
++            len += sprintf(page + len, "Attribute value: 0x%x \n\n", node->attr_info.value);
++        } else {
++            len += sprintf(page + len, "Attribute value: %d \n\n", node->attr_info.value);
++        }
++    }
++    /* unlock */
++    LIST_UNLOCK;
++
++    return len;
++}
++
++/* Register info
++ */
++static int proc_read_reginfo(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned long flags;
++    pmuRegInfo_node_t *node;
++    int i, len = 0, pos, begin = 0;
++
++    /* lock the database */
++    LIST_LOCK;
++    /* walk through whole attribute list */
++    list_for_each_entry(node, &REGINFO_LIST, list) {
++        pos = begin + len;
++        if (pos < off) {
++            len = 0;
++            begin = pos;
++        }
++
++        if (pos > off + count)
++            goto exit;
++
++        len +=
++            sprintf(page + len, "name: %s, fd = %d, attribute type = %d \n", REGINFO_NAME(node),
++                    node->fd, node->pmuReg_info.clock_src);
++
++        for (i = 0; i < REGINFO_REGCNT(node); i++) {
++            len += sprintf(page + len, "    reg_off: 0x%x, bits_mask: 0x%x, lock_bits: 0x%x\n",
++                           REGINFO_OFFSET(node, i), REGINFO_BITSMASK(node, i),
++                           REGINFO_LOCKBITS(node, i));
++        }
++
++        len += sprintf(page + len, "\n");
++    }
++    *eof = 1;
++    /* unlock */
++    LIST_UNLOCK;
++
++    return len;
++
++exit:
++    /* unlock */
++    LIST_UNLOCK;
++
++    *start = page + (off - begin);
++    len -= (off - begin);
++
++    if (len > count)
++        len = count;
++    else if (len < 0)
++        len = 0;
++
++    return len;
++}
++
++/* chip version info
++ */
++static int proc_read_chip_version(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned int value;
++    int len = 0;
++
++    value = ftpmu010_get_attr(ATTR_TYPE_CHIPVER);
++
++    len += sprintf(page + len, "%x\n", value);
++
++    return len;
++}
++
++static int ftpmu010_proc_init(void)
++{
++    int ret = 0;
++    struct proc_dir_entry *p;
++
++    p = create_proc_entry("pmu", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (p == NULL) {
++        return -ENOMEM;
++    }
++    pmu_proc_root = p;
++    /* pmu_proc_root->data = ;  */
++    /*
++     * attribute
++     */
++    attribute_proc = create_proc_entry("attribute", S_IRUGO, pmu_proc_root);
++    if (attribute_proc == NULL) {
++        printk("PMU: Fail to create proc attribute!\n");
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    attribute_proc->read_proc = (read_proc_t *) proc_read_attribute_info;
++    attribute_proc->write_proc = NULL;
++
++    /*
++     * regInfo
++     */
++    regInfo_proc = create_proc_entry("reginfo", S_IRUGO, pmu_proc_root);
++    if (regInfo_proc == NULL) {
++        printk("PMU: Fail to create proc regInfo!\n");
++        remove_proc_entry(attribute_proc->name, pmu_proc_root);
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    regInfo_proc->read_proc = (read_proc_t *) proc_read_reginfo;
++    regInfo_proc->write_proc = NULL;
++
++    /* IC version, for some AP easy to read */
++    chipver_proc = create_proc_entry("chipver", S_IRUGO, pmu_proc_root);
++    if (chipver_proc == NULL) {
++        printk("PMU: Fail to create proc regInfo!\n");
++        remove_proc_entry(attribute_proc->name, pmu_proc_root);
++        remove_proc_entry(regInfo_proc->name, pmu_proc_root);
++        remove_proc_entry(pmu_proc_root->name, NULL);
++        ret = -EINVAL;
++        goto end;
++    }
++    chipver_proc->read_proc = (read_proc_t *) proc_read_chip_version;
++    chipver_proc->write_proc = NULL;
++
++  end:
++    return ret;
++}
++
++EXPORT_SYMBOL(ftpmu010_register_attr);
++EXPORT_SYMBOL(ftpmu010_deregister_attr);
++EXPORT_SYMBOL(ftpmu010_get_attr);
++EXPORT_SYMBOL(ftpmu010_register_reg);
++EXPORT_SYMBOL(ftpmu010_deregister_reg);
++EXPORT_SYMBOL(ftpmu010_add_lockbits);
++EXPORT_SYMBOL(ftpmu010_del_lockbits);
++EXPORT_SYMBOL(ftpmu010_bits_is_locked);
++EXPORT_SYMBOL(ftpmu010_update_lockbits);
++EXPORT_SYMBOL(ftpmu010_read_reg);
++EXPORT_SYMBOL(ftpmu010_write_reg);
++EXPORT_SYMBOL(ftpmu010_clock_divisor);
++EXPORT_SYMBOL(ftpmu010_request_pins);
++EXPORT_SYMBOL(ftpmu010_release_pins);
++EXPORT_SYMBOL(ftpmu010_pins_is_requested);
++EXPORT_SYMBOL(ftpmu010_pmu_doaction);
++EXPORT_SYMBOL(ftpmu010_clock_divisor2);
++
++MODULE_AUTHOR("Grain-Media");
++MODULE_DESCRIPTION("FTPMU010 core");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM/fttmr010.c b/arch/arm/mach-GM/fttmr010.c
+new file mode 100644
+index 00000000..0276a870
+--- /dev/null
++++ b/arch/arm/mach-GM/fttmr010.c
+@@ -0,0 +1,275 @@
++/*
++ *  Faraday FTTMR010 Timer
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <asm/io.h>
++#include <asm/mach/irq.h>
++#include <mach/fttmr010.h>
++
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static const unsigned int fttmr010_cr_mask[3] = {
++	FTTMR010_TM1_ENABLE | FTTMR010_TM1_CLOCK |
++	FTTMR010_TM1_OFENABLE | FTTMR010_TM1_UPDOWN,
++
++	FTTMR010_TM2_ENABLE | FTTMR010_TM2_CLOCK |
++	FTTMR010_TM2_OFENABLE | FTTMR010_TM2_UPDOWN,
++
++	FTTMR010_TM3_ENABLE | FTTMR010_TM3_CLOCK |
++	FTTMR010_TM3_OFENABLE | FTTMR010_TM3_UPDOWN,
++};
++
++/* we always use down counter */
++static const unsigned int fttmr010_cr_enable_flag[3] = {
++	FTTMR010_TM1_ENABLE | FTTMR010_TM1_OFENABLE,
++	FTTMR010_TM2_ENABLE | FTTMR010_TM2_OFENABLE,
++	FTTMR010_TM3_ENABLE | FTTMR010_TM3_OFENABLE,
++};
++
++static const unsigned int fttmr010_cr_enable_noirq_flag[3] = {
++	FTTMR010_TM1_ENABLE,
++	FTTMR010_TM2_ENABLE,
++	FTTMR010_TM3_ENABLE,
++};
++
++/* TmxEnable + overflow interrupt enable
++ */
++static void fttmr010_enable(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];    /* maskout the mask, all setting goes to zero. */
++	cr |= fttmr010_cr_enable_flag[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++/* Just no overflow interrupt enable bit
++ */
++static void fttmr010_enable_noirq(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	cr |= fttmr010_cr_enable_noirq_flag[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static void fttmr010_disable(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static inline void fttmr010_write_timer(void __iomem *base, unsigned int id,
++		unsigned int reg, unsigned int value)
++{
++	void __iomem *addr = base + FTTMR010_OFFSET_TIMER(id) + reg;
++	writel (value, addr);
++}
++
++static inline unsigned int fttmr010_read_timer(void __iomem *base,
++		unsigned int id, unsigned int reg)
++{
++	void __iomem *addr = base + FTTMR010_OFFSET_TIMER(id) + reg;
++	return readl(addr);
++}
++
++static void fttmr010_set_counter(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_COUNTER, value);
++}
++
++static inline unsigned int fttmr010_get_counter(void __iomem *base, unsigned int id)
++{
++	return fttmr010_read_timer(base, id, FTTMR010_OFFSET_COUNTER);
++}
++
++static void fttmr010_set_reload(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_LOAD, value);
++}
++
++static void fttmr010_set_match1(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_MATCH1, value);
++}
++
++static void fttmr010_set_match2(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_MATCH2, value);
++}
++
++/******************************************************************************
++ * clockevent functions. Set the next trigger event
++ *****************************************************************************/
++static int fttmr010_set_next_event(unsigned long clc, struct clock_event_device *ce)
++{
++	struct fttmr010_clockevent *fttmr010;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++	fttmr010_set_counter(fttmr010->base, fttmr010->id, clc);
++
++	return 0;
++}
++
++static void fttmr010_set_mode(enum clock_event_mode mode, struct clock_event_device *ce)
++{
++	struct fttmr010_clockevent *fttmr010;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++
++	switch (mode) {
++	case CLOCK_EVT_MODE_PERIODIC:
++		fttmr010_set_reload(fttmr010->base, fttmr010->id, fttmr010->reload);
++		fttmr010_set_counter(fttmr010->base, fttmr010->id, fttmr010->reload);
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_RESUME:
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_ONESHOT:
++		fttmr010_set_reload(fttmr010->base, fttmr010->id, 0);
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_UNUSED:
++	case CLOCK_EVT_MODE_SHUTDOWN:
++	default:
++		fttmr010_disable(fttmr010->base, fttmr010->id);
++		break;
++	}
++}
++
++static irqreturn_t fttmr010_clockevent_interrupt(int irq, void *dev_id)
++{
++	struct clock_event_device *ce = dev_id;
++	struct fttmr010_clockevent *fttmr010;
++    unsigned int tmp;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++
++    /* Level Trigger needs this fix */
++	tmp = readl(fttmr010->base + FTTMR010_OFFSET_INTR_STATE);
++	writel(tmp, fttmr010->base + FTTMR010_OFFSET_INTR_STATE);
++
++	ce->event_handler(ce);
++	return IRQ_HANDLED;
++}
++
++void __init fttmr010_clockevent_init(struct fttmr010_clockevent *fttmr010)
++{
++	struct clock_event_device *ce = &fttmr010->clockevent;
++	struct irqaction *action = &fttmr010->irqaction;
++
++	if (!fttmr010->base || fttmr010->id >= 3)
++		BUG();
++
++	/* initialize to a known state */
++	fttmr010_disable(fttmr010->base, fttmr010->id);
++	fttmr010_set_match1(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_match2(fttmr010->base, fttmr010->id, 0);
++
++	/* setup reload value for periodic clockevents */
++	fttmr010->reload	= (fttmr010->freq / HZ) - 1;    /* FIX */
++
++	/* Make irqs happen for the system timer */
++	action->name		= ce->name;
++	action->handler		= fttmr010_clockevent_interrupt;
++	action->flags		= IRQF_DISABLED | IRQF_TIMER;
++	action->dev_id		= ce;
++
++	setup_irq(ce->irq, action);
++
++	/* setup struct clock_event_device */
++	ce->features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
++	ce->shift		= 32;
++	ce->rating		= 200;
++	ce->cpumask		= cpumask_of(0);    //CPU_MASK_ALL,
++
++	ce->mult		= div_sc(fttmr010->freq, NSEC_PER_SEC, ce->shift);
++	ce->max_delta_ns	= clockevent_delta2ns(0xffffffff, ce);
++	ce->min_delta_ns	= clockevent_delta2ns(0xff, ce);
++
++	ce->set_next_event	= fttmr010_set_next_event;
++	ce->set_mode		= fttmr010_set_mode;
++
++	clockevents_register_device(ce);
++}
++
++/******************************************************************************
++ * clocksource functions
++ *****************************************************************************/
++
++/*
++ * We support only one instance now.
++ *
++ * After 2.6.30, clocksource->read() has a parameter, and we can use it with
++ * container_of() to get the private data for each instance.
++ */
++static cycle_t fttmr010_clocksource_read(struct clocksource *cs)
++{
++    struct fttmr010_clocksource *fttmr010;
++	cycle_t counter;
++
++    fttmr010 = container_of(cs, struct fttmr010_clocksource, clocksource);
++	counter = fttmr010_get_counter(fttmr010->base, fttmr010->id);
++	return ~counter;
++}
++
++void __init fttmr010_clocksource_init(struct fttmr010_clocksource *fttmr010)
++{
++	struct clocksource *cs = &fttmr010->clocksource;
++
++	if (!fttmr010->base || fttmr010->id >= 3)
++		BUG();
++
++	cs->rating	= 300;
++	cs->read	= fttmr010_clocksource_read;
++	cs->mask	= CLOCKSOURCE_MASK(32);
++	cs->shift	= 20;
++	cs->flags	= CLOCK_SOURCE_IS_CONTINUOUS;
++	cs->mult	= clocksource_hz2mult(fttmr010->freq, cs->shift);
++
++	/* setup as free-running clocksource */
++	fttmr010_disable(fttmr010->base, fttmr010->id);
++	fttmr010_set_match1(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_match2(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_reload(fttmr010->base, fttmr010->id, 0xffffffff);
++	fttmr010_set_counter(fttmr010->base, fttmr010->id, 0xffffffff);
++	fttmr010_enable_noirq(fttmr010->base, fttmr010->id);
++
++	clocksource_register(cs);
++
++    if (1) {
++        extern int gm_jiffies_init(void *);
++	    gm_jiffies_init((void *)fttmr010);
++	}
++}
++
++
+diff --git a/arch/arm/mach-GM/gm_jiffies.c b/arch/arm/mach-GM/gm_jiffies.c
+new file mode 100644
+index 00000000..de6e9d96
+--- /dev/null
++++ b/arch/arm/mach-GM/gm_jiffies.c
+@@ -0,0 +1,141 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <linux/proc_fs.h>
++#include <linux/timer.h>
++#include <mach/fttmr010.h>
++#include <mach/gm_jiffies.h>
++
++/*
++ * Macro definitions
++ */
++#define HEART_BEAT_INTVAL   (10 * HZ)
++#define time_disance(a, b)  ((long)(b) - (long)(a))
++
++/*
++ * Local variables
++ */
++static unsigned long __gm_jiffies = 0;  /* 1ms granularity */
++static u64  __gm_jiffies_u64 = 0;       /* 1ms granularity */
++static unsigned long clk_khz = 0;
++static struct timer_list  gm_jiffies_tmr;
++static spinlock_t spinlock;
++static unsigned int refer_cnt = 0;
++static struct fttmr010_clocksource *pGmClkSrc = NULL;
++static struct proc_dir_entry *gm_jiffies_proc = NULL;
++
++/*
++ * Local functions
++ */
++static int proc_read_gm_jiffies(char *page, char **start, off_t off, int count, int *eof, void *data);
++
++static unsigned int distance = 0;
++
++/* get 1m jiffies */
++unsigned long get_gm_jiffies(void)
++{
++    static unsigned long keep_clk_val = 0;
++    unsigned long flags, new_clk_val;
++
++    if (pGmClkSrc == NULL)
++        return 0;
++
++    /* lock */
++    spin_lock_irqsave(&spinlock, flags);
++    new_clk_val = pGmClkSrc->clocksource.read(&pGmClkSrc->clocksource);
++    if (!keep_clk_val && !new_clk_val) {  /* not start yet */
++        spin_unlock_irqrestore(&spinlock, flags);
++        return 0;
++    }
++
++    distance += time_disance(keep_clk_val, new_clk_val);
++    keep_clk_val = new_clk_val;
++
++    if (distance >= clk_khz) {
++        unsigned long value = distance / clk_khz;
++
++        __gm_jiffies += value;
++        __gm_jiffies_u64 += value;
++        distance = distance % clk_khz;
++    }
++
++    /* unlock */
++    spin_unlock_irqrestore(&spinlock, flags);
++
++    refer_cnt ++;
++
++    return __gm_jiffies;
++}
++EXPORT_SYMBOL(get_gm_jiffies);
++
++/* get 1m jiffies */
++u64 get_gm_jiffies_u64(void)
++{
++    get_gm_jiffies();
++
++    return __gm_jiffies_u64;
++}
++EXPORT_SYMBOL(get_gm_jiffies_u64);
++
++/*
++ * A function to update __gm_jiffies periodically if there is no caller to call get_gm_jiffies()
++ *   in a long interval.
++ */
++void gm_heatbeat_handler(unsigned long data)
++{
++    struct fttmr010_clocksource *pGmClkSrc = (struct fttmr010_clocksource *)data;
++
++
++    /* in order to prevent __gm_jiffies not update in a long time */
++    get_gm_jiffies();
++
++    gm_jiffies_tmr.function = gm_heatbeat_handler;
++    gm_jiffies_tmr.data = (unsigned long)pGmClkSrc;
++    mod_timer(&gm_jiffies_tmr, jiffies + HEART_BEAT_INTVAL);
++
++    if (gm_jiffies_proc == NULL) {
++        gm_jiffies_proc = create_proc_entry("gm_jiffies", S_IRUGO, NULL);
++        if (gm_jiffies_proc == NULL)
++            panic("%s, error in create proc! \n", __func__);
++
++        gm_jiffies_proc->read_proc = (read_proc_t *) proc_read_gm_jiffies;
++        gm_jiffies_proc->write_proc = NULL;
++    }
++}
++
++int __init gm_jiffies_init(void *data)
++{
++    pGmClkSrc = (struct fttmr010_clocksource *)data;
++    if (pGmClkSrc == NULL)
++        panic("%s, data is NULL! \n", __func__);
++
++    clk_khz = pGmClkSrc->freq / 1000;
++
++    /* sanity check */
++    if ((HEART_BEAT_INTVAL / HZ) >= (0xffffffff / pGmClkSrc->freq))
++        panic("%s, HEART_BEAT_INTVAL = %d out of range! \n", __func__, HEART_BEAT_INTVAL / HZ);
++
++    spin_lock_init(&spinlock);
++    init_timer(&gm_jiffies_tmr);
++    gm_jiffies_tmr.function = gm_heatbeat_handler;
++    gm_jiffies_tmr.data = (unsigned long)pGmClkSrc;
++    mod_timer(&gm_jiffies_tmr, jiffies + HZ);
++    printk(KERN_INFO "%s, system HZ: %d, pClk: %d \n", __func__, HZ, pGmClkSrc->freq);
++
++    return 0;
++}
++
++static int proc_read_gm_jiffies(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    int len = 0;
++
++    len += sprintf(page + len, "gm jiffies: 0x%x, HZ = %d \n", (u32)gm_jiffies, HZ);
++    len += sprintf(page + len, "reference count: 0x%d \n", refer_cnt);
++
++    return len;
++}
++
++MODULE_AUTHOR("Grain Media Corp.");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-GM/include/mach/debug-macro.S b/arch/arm/mach-GM/include/mach/debug-macro.S
+new file mode 100644
+index 00000000..aadb8d57
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/debug-macro.S
+@@ -0,0 +1,44 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/debug-macro.S
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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 <linux/linkage.h>
++#include <mach/hardware.h>
++#include <mach/serial.h>
++
++		.macro	addruart, rp, rv, tmp
++		ldr	\rp, =DEBUG_LL_FTUART010_PA_BASE	@ physical base address of UART
++		ldr	\rv, =DEBUG_LL_FTUART010_VA_BASE	@ virtual base address of UART
++		.endm
++
++		.macro	senduart, rd, rx
++		strb	\rd, [\rx, #SERIAL_THR]
++		.endm
++
++		.macro	waituart, rd, rx
++1001:		ldrb	\rd, [\rx, #SERIAL_LSR]	@ LSR
++		tst	\rd, #SERIAL_LSR_THRE	@ test empty
++		beq	1001b
++		.endm
++
++		.macro	busyuart, rd, rx
++		mov	\rd, #0x100
++1010:		subs	\rd, \rd, #1
++		bne	1010b
++		.endm
+diff --git a/arch/arm/mach-GM/include/mach/dma_gm.h b/arch/arm/mach-GM/include/mach/dma_gm.h
+new file mode 100644
+index 00000000..0f1f707b
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/dma_gm.h
+@@ -0,0 +1,33 @@
++#ifndef __DMA_GM_H
++#define __DMA_GM_H
++
++enum dma_kind {
++	APB_DMA,
++	AHB_DMA,
++	AXI_DMA,
++};
++
++/** 
++* @brief memory copy used by DMA
++* 
++* @style: choose DMA style (APB, AHB, AXI)
++* @dest: DMA memory copy's destination address
++* @src: DMA memory copy's source address 
++* @len: DMA memory copy's memory length 
++* 
++* @return 0: success, other: failed 
++*/
++int dma_memcpy(enum dma_kind style, dma_addr_t dest, dma_addr_t src, size_t len);
++
++/** 
++* @brief memory set used by DMA
++* 
++* @style: choose DMA style (APB, AHB, AXI)
++* @dest: DMA memory set's destination address
++* @value: DMA memory set's value
++* @len: DMA memory set's memory length 
++* 
++* @return 0: success, other: failed 
++*/
++int dma_memset(enum dma_kind style, dma_addr_t dest, int value, size_t len);
++#endif /* __DMA_GM_H */
+diff --git a/arch/arm/mach-GM/include/mach/entry-macro.S b/arch/arm/mach-GM/include/mach/entry-macro.S
+new file mode 100644
+index 00000000..f3e8d129
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/entry-macro.S
+@@ -0,0 +1,306 @@
++/*
++ * arch/arm/mach-GM/include/mach/entry-macro.S
++ *
++ * Faraday Low-level Interrupt Vector Interface Macros
++ *
++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef CONFIG_CPU_FMP626
++
++#include <mach/irqs.h>
++#include <mach/ftintc030.h>
++#include <mach/ftintc010.h>
++
++	.macro	check_status, irqstat, tmp
++	//???
++	stmfd	sp!, {r7}
++	ldr	r7, =ftintc030_base_cpu_0_irq_base
++	ldr	r7, [r7]
++	mov 	r4, \tmp
++	mov	r4, r4, lsr #3				/* >>= 5, then << 2 calc INT offset */
++	ldr	r4, [r7, r4]
++	and	\irqstat, \irqstat, r4
++	ldmfd	sp!, {r7}
++	.endm
++
++	.macro	disable_fiq
++	.endm
++
++	.macro	get_irqnr_preamble, base, tmp
++#ifdef CONFIG_FTINTC030
++	ldr	\base, =ftintc030_base_addr
++#else
++	ldr	\base, =ftintc010_base_addr
++#endif
++	ldr	\base, [\base]
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++#if __LINUX_ARM_ARCH__ >= 5
++	.macro	__get_int_nr_and_base, irqnr, irqstat, tmp
++	clz	\irqnr, \irqstat				/* 32 if no bits are set, and zero if bit 31 is set */
++	rsb	\irqnr, \irqnr, #31			/* irqnr = 31 - irqnr, get irq number */
++	.endm
++#else
++	/*
++	 * An O(1) optimized version for getting IRQ/FIQ number
++	 * 08/29/2005 Luke Lee
++	 * Input/output: irqnr (initial value), irqstat (the word to scan)
++	 * Local R/W:	tmp
++	 */
++	.macro	__get_int_nr_and_base, irqnr, irqstat, tmp
++	mov	\tmp, \irqstat, lsl #16	/* check if lower 16 bits = zero */
++	cmp	\tmp, #0
++	movne	\irqstat, \irqstat, lsl #16	/* irqstat <<= 16 */
++	subne	\irqnr, \irqnr, #16	/* irqnr -= 16 */
++	tst	\irqstat, #0x00FF0000
++	movne	\irqstat, \irqstat, lsl #8	/* irqstat <<= 8 */
++	subne	\irqnr, \irqnr, #8	/* irqnr -= 8 */
++	tst	\irqstat, #0x0F000000
++	movne	\irqstat, \irqstat, lsl #4	/* irqstat <<= 4 */
++	subne	\irqnr, \irqnr, #4	/* irqnr -= 4 */
++	tst	\irqstat, #0x30000000
++	movne	\irqstat, \irqstat, lsl #2	/* irqstat <<= 2 */
++	subne	\irqnr, \irqnr, #2	/* irqnr -= 2 */
++	tst	\irqstat, #0x40000000
++	subne	\irqnr, \irqnr, #1	/* irqnr -= 1 */
++	.endm
++#endif
++
++#ifdef CONFIG_FTINTC010EX
++	/*
++	 * Get EXTEND IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp, base, offset
++   * 					base: irq IP base address
++   * 					offset: register offset
++	 */
++	.macro	__get_ex_nr, irqnr, irqstat, tmp, base, offset
++	ldr	\irqstat, [\base, \offset]
++	cmp	\irqstat, #0
++	beq	15f
++	mov	\irqnr, #31
++
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++
++	add	\irqnr, \irqnr, #32
++	cmp	\irqnr, #NR_IRQS
++15:
++	.endm	/* get_ex_nr */
++#endif
++
++#ifdef CONFIG_FTINTC030
++	/*
++	 * Get SPI INTC030 IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp, base, r5
++   * 					irqstat: spi status
++   * 					tmp: register offset
++   * 					base: irq IP base address
++   * 					offset: register offset
++   * 					r3: irq number base
++	 */
++	.macro	__get_spi_nr, irqnr, irqstat, tmp, base, offset, mode
++	ldr	\irqstat, [\base, \offset]	/* read IRQ status, irq group 1 */
++
++	add \base, \base, #0x20
++	mov \tmp, #32
++	mov r3, #32										/* move spi base to 32 */
++//	???
++	check_status \irqstat, r3
++	cmp	\irqstat, #0
++	beq	7f
++
++	mov	\irqnr, #31								/* irq between this range */
++6:
++	sub \base, \base, \tmp
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++
++	add	\irqnr, \irqnr, r3					/* add irq base and return value */
++	cmp	r3, #(NR_IRQS - 32)
++	b 9f
++7:
++	cmp	r3, #(NR_IRQS - 32)				/* check irq overflow */
++	bge	9f
++	add \tmp, \tmp, #0x20					/* shift to next register offset */
++	add \base, \base, #0x20
++	ldr	\irqstat, [\base, \offset]	/* read IRQ status, irq group 2~14 */
++	add	r3, r3, #32								/* add IRQ number base */
++//	???
++	check_status \irqstat, r3
++	cmp	\irqstat, #0
++	beq	7b
++	b 6b
++9:
++
++	.endm	/* get_spi_nr */
++#endif
++
++	/*
++	 * Get IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp
++	 */
++	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++
++	mov	\irqnr, #0
++#ifdef CONFIG_FTINTC030
++	ldr	\irqstat, [\base, #FTINTC030_OFFSET_IRQPEND]	/* irq group 0 */
++
++	check_status \irqstat, \irqnr
++//???
++#else
++	ldr	\irqstat, [\base, #FTINTC010_OFFSET_IRQSTATUS]/* irq group 0 */
++#endif
++
++	cmp	\irqstat, #0
++	beq	3f
++
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++	cmp	\irqnr, #NR_IRQS
++#if (defined(CONFIG_FTINTC010EX) || defined(CONFIG_FTINTC030))
++	b	5f
++#endif
++3:
++#ifdef CONFIG_FTINTC010EX
++	__get_ex_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC010_OFFSET_IRQSTATUSEX	/* irq group 1 */
++5:
++#endif
++#ifdef CONFIG_FTINTC030
++	__get_spi_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC030_OFFSET_IRQPEND1	, #0	/* irq group 1~14 */
++	cmp \irqnr, #0
++5:
++#endif
++	.endm	/* get_irqnr_and_base */
++
++#ifdef CONFIG_FIQ
++    /*
++    * Get FIQ number and base
++	* Input: none
++	* Output: irqnr, Z flag
++	* Local R/W: irqstat, base, tmp
++	*/
++	.macro get_fiqnr_and_base, irqnr, irqstat, base, tmp
++#ifdef CONFIG_FTINTC030
++	ldr \irqstat, [\base, #FTINTC030_OFFSET_IRQPEND]		/* fiq group 0 */
++#else
++	ldr \irqstat, [\base, #FTINTC010_OFFSET_FIQSTATUS]	/* fiq group 0 */
++#endif
++	cmp	\irqstat, #0
++	beq	2003f
++	mov	\irqnr, #0
++	__get_int_nr_and_base	\irqnr, \irqstat, \tmp
++	cmp	\irqnr, #NR_IRQS
++#if (defined(CONFIG_FTINTC010EX) || defined(CONFIG_FTINTC030))
++    b   2005f
++#endif
++2003:
++#ifdef CONFIG_FTINTC010EX
++	__get_ex_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC010_OFFSET_FIQSTATUSEX	/* fiq group 1 */
++2005:
++#endif
++#ifdef CONFIG_FTINTC030
++	__get_spi_nr	\irqnr, \irqstat, \tmp, \base, #FTINTC030_OFFSET_IRQPEND1, #1		/* fiq group 1~14 */
++2005:
++#endif
++    .endm	/* get_fiqnr_and_base */
++
++#endif /* CONFIG_FIQ */
++
++
++#else	/* CONFIG_CPU_FMP626 */
++
++#include <mach/hardware.h>
++#include <asm/hardware/gic.h>
++
++	.macro	disable_fiq
++	.endm
++
++	.macro	get_irqnr_preamble, base, tmp
++	ldr	\base, =gic_cpu_base_addr
++	ldr	\base, [\base]
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++	/*
++	 * The interrupt numbering scheme is defined in the
++	 * interrupt controller spec.  To wit:
++	 *
++	 * Interrupts 0-15 are IPI
++	 * 16-28 are reserved
++	 * 29-31 are local.  We allow 30 to be used for the watchdog.
++	 * 32-1020 are global
++	 * 1021-1022 are reserved
++	 * 1023 is "spurious" (no interrupt)
++	 *
++	 * For now, we ignore all local interrupts so only return an interrupt if it's
++	 * between 30 and 1020.  The test_for_ipi routine below will pick up on IPIs.
++	 *
++	 * A simple read from the controller will tell us the number of the highest
++	 * priority enabled interrupt.  We then just need to check whether it is in the
++	 * valid range for an IRQ (30-1020 inclusive).
++	 */
++
++	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++
++	ldr	\irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 = src CPU, 9-0 = int # */
++
++	ldr	\tmp, =1021
++
++	bic	\irqnr, \irqstat, #0x1c00
++
++	cmp	\irqnr, #29
++	cmpcc	\irqnr, \irqnr
++	cmpne	\irqnr, \tmp
++	cmpcs	\irqnr, \irqnr
++
++	.endm
++
++	/* We assume that irqstat (the raw value of the IRQ acknowledge
++	 * register) is preserved from the macro above.
++	 * If there is an IPI, we immediately signal end of interrupt on the
++	 * controller, since this requires the original irqstat value which
++	 * we won't easily be able to recreate later.
++	 */
++
++	.macro	test_for_ipi, irqnr, irqstat, base, tmp
++	bic	\irqnr, \irqstat, #0x1c00
++	cmp	\irqnr, #16
++	strcc	\irqstat, [\base, #GIC_CPU_EOI]
++	cmpcs	\irqnr, \irqnr
++	.endm
++
++	/* As above, this assumes that irqstat and base are preserved.. */
++
++	.macro	test_for_ltirq, irqnr, irqstat, base, tmp
++	bic	\irqnr, \irqstat, #0x1c00
++	mov 	\tmp, #0
++	cmp	\irqnr, #29
++	moveq	\tmp, #1
++	streq	\irqstat, [\base, #GIC_CPU_EOI]
++	cmp	\tmp, #0
++	.endm
++
++#endif	/* CONFIG_CPU_FMP626 */
+diff --git a/arch/arm/mach-GM/include/mach/fmem.h b/arch/arm/mach-GM/include/mach/fmem.h
+new file mode 100644
+index 00000000..b4e4debc
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/fmem.h
+@@ -0,0 +1,82 @@
++#ifndef __FMEM_H
++#define __FMEM_H
++#include <linux/mm.h>
++#include <asm/io.h>
++#include <asm/setup.h>
++#include <linux/list.h>
++#include <linux/dma-direction.h>
++
++#define MAX_DDR_CHUNKS 2   /* include system memory */
++
++typedef struct g_page_info_s
++{
++    int         nr_node;        /* number of active DDRs */
++    int         block_sz;       /* page allocation size once */
++    int         node_sz[MAX_DDR_CHUNKS];    /* the size for the DDR node */
++    dma_addr_t  phy_start[MAX_DDR_CHUNKS];  /* the min physical start */
++    struct list_head list[MAX_DDR_CHUNKS];  /* page node list */
++} g_page_info_t;
++
++/* page node for each pages allocation */
++typedef struct {
++    struct page     *page;
++    dma_addr_t      phy_start;
++    unsigned int    size;   /* the real size */
++    int             ddr_id; /* belong to which DDR */
++    struct list_head list;
++} page_node_t;
++
++void fmem_get_pageinfo(g_page_info_t **data_ptr);
++int  fmem_give_pages(int node_id, unsigned int give_sz);
++void fmem_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi);
++
++void fmem_free_ex(size_t size, void *cpu_addr, dma_addr_t handle);
++void *fmem_alloc_ex(size_t size, dma_addr_t * dma_handle, unsigned long flags, int ddr_id);
++
++/**
++ * @brief to resolve the virtual address (including direct mapping, ioremap or user space address to
++ *      its real physical address.
++ *
++ * @parm vaddr indicates any virtual address
++ *
++ * @return  >= 0 for success, 0xFFFFFFFF for fail
++ */
++phys_addr_t fmem_lookup_pa(unsigned int vaddr);
++
++/*
++ *  * @This function is used to read CPU id and pci id
++ *   * @Return value: 0 for success, -1 for fail
++ *    */
++typedef enum {
++    FMEM_CPU_FA726 = 0,
++    FMEM_CPU_FA626,
++    FMEM_CPU_UNKNOWN,
++} fmem_cpu_id_t;
++
++typedef enum {
++    FMEM_PCI_HOST = 0,
++    FMEM_PCI_DEV0,
++} fmem_pci_id_t;
++
++int fmem_get_identifier(fmem_pci_id_t *pci_id, fmem_cpu_id_t *cpu_id);
++
++/* @this function is a data cache operation function,
++ * @parm: vaddr: any virtual address
++ * @parm: dir will be:
++ * DMA_BIDIRECTIONAL = 0, it means flush operation.
++ * DMA_TO_DEVICE = 1, it means clean operation.
++ * DMA_FROM_DEVICE = 2, it means invalidate operation.
++ * DMA_NONE = 3,
++ */
++void fmem_dcache_sync(void *vaddr, u32 len, enum dma_data_direction dir);
++
++/* The following functions are only valid in GM8210 and adopted by videgraph.
++ */
++int fmem_set_ep_outbound_win(u32 phy_addr, u32 size);
++u32 fmem_get_pcie_addr(u32 axi_phy_addr);
++u32 fmem_get_axi_addr(u32 pcie_phy_addr);
++
++#endif /* __FMEM_H */
++
++
++
+diff --git a/arch/arm/mach-GM/include/mach/ftapbb020.h b/arch/arm/mach-GM/include/mach/ftapbb020.h
+new file mode 100644
+index 00000000..79570039
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/ftapbb020.h
+@@ -0,0 +1,138 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftapbb020.h
++ *
++ *  Faraday FTAPBB020 APB Bridge with DMA function
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTAPBB020_H
++#define __FTAPBB020_H
++
++#define FTAPBB020_OFFSET_BSR(x)		((x) * 0x4)		/* BSR of slave x */
++#define FTAPBB020_OFFSET_SAR(x)		(0x80 + (x) * 0x10)	/* src addr of channel x */
++#define FTAPBB020_OFFSET_DAR(x)		(0x84 + (x) * 0x10)	/* dst addr of channel x */
++#define FTAPBB020_OFFSET_CYC(x)		(0x88 + (x) * 0x10)	/* cycles of channel x */
++#define FTAPBB020_OFFSET_CMD(x)		(0x8c + (x) * 0x10)	/* command of channel x */
++#define FTAPBB020_OFFSET_CR		0xc0
++#define FTAPBB020_OFFSET_SR		0xc4
++#define FTAPBB020_OFFSET_REV		0xc8
++
++/*
++ * Base/size of each slave
++ */
++#define FTAPBB020_BSR_SIZE_1M		(0 << 16)
++#define FTAPBB020_BSR_SIZE_2M		(1 << 16)
++#define FTAPBB020_BSR_SIZE_4M		(2 << 16)
++#define FTAPBB020_BSR_SIZE_8M		(3 << 16)
++#define FTAPBB020_BSR_SIZE_16M		(4 << 16)
++#define FTAPBB020_BSR_SIZE_32M		(5 << 16)
++#define FTAPBB020_BSR_SIZE_64M		(6 << 16)
++#define FTAPBB020_BSR_SIZE_128M		(7 << 16)
++#define FTAPBB020_BSR_SIZE_256M		(8 << 16)
++#define FTAPBB020_BSR_BASE(x)		((x) & (0x3ff << 20))
++
++/*
++ * Cycle count of each DMA channel
++ */
++#define FTAPBB020_CYC_MASK		0x00ffffff
++
++/*
++ * Command of each DMA channel
++ */
++#define FTAPBB020_CMD_ENABLE		(1 << 0)
++#define FTAPBB020_CMD_FININT_S		(1 << 1)
++#define FTAPBB020_CMD_FININT_E		(1 << 2)
++#define FTAPBB020_CMD_BURST		(1 << 3)
++#define FTAPBB020_CMD_ERRINT_S		(1 << 4)
++#define FTAPBB020_CMD_ERRINT_E		(1 << 5)
++#define FTAPBB020_CMD_SRC_TYPE_AHB	(1 << 6)
++#define FTAPBB020_CMD_DST_TYPE_AHB	(1 << 7)
++#define FTAPBB020_CMD_SRC_MODE_FIXED	(0 << 8)
++#define FTAPBB020_CMD_SRC_MODE_BYTE_INC	(1 << 8)
++#define FTAPBB020_CMD_SRC_MODE_HALF_INC	(2 << 8)
++#define FTAPBB020_CMD_SRC_MODE_WORD_INC	(3 << 8)
++#define FTAPBB020_CMD_SRC_MODE_BYTE_DEC	(5 << 8)
++#define FTAPBB020_CMD_SRC_MODE_HALF_DEC	(6 << 8)
++#define FTAPBB020_CMD_SRC_MODE_WORD_DEC	(7 << 8)
++#define FTAPBB020_CMD_DST_MODE_FIXED	(0 << 12)
++#define FTAPBB020_CMD_DST_MODE_BYTE_INC	(1 << 12)
++#define FTAPBB020_CMD_DST_MODE_HALF_INC	(2 << 12)
++#define FTAPBB020_CMD_DST_MODE_WORD_INC	(3 << 12)
++#define FTAPBB020_CMD_DST_MODE_BYTE_DEC	(5 << 12)
++#define FTAPBB020_CMD_DST_MODE_HALF_DEC	(6 << 12)
++#define FTAPBB020_CMD_DST_MODE_WORD_DEC	(7 << 12)
++#define FTAPBB020_CMD_DST_HANDSHAKE(x)	(((x) & 0xf) << 16)	/* destination handshake channel */
++#define FTAPBB020_CMD_WIDTH_WORD	(0 << 20)
++#define FTAPBB020_CMD_WIDTH_HALF	(1 << 20)
++#define FTAPBB020_CMD_WIDTH_BYTE	(2 << 20)
++#define FTAPBB020_CMD_SRC_HANDSHAKE(x)	(((x) & 0xf) << 24)	/* source handshake channel */
++
++/*
++ * Control register
++ */
++#define FTAPBB020_CR_BUF_NORMAL		(0 << 0)
++#define FTAPBB020_CR_BUF_ALWAYS		(1 << 0)
++#define FTAPBB020_CR_BUF_NEVER		(2 << 0)
++#define FTAPBB020_CR_BWERRINT_E		(1 << 2)
++
++/*
++ * Status register
++ */
++#define FTAPBB020_SR_BWERRINT		(1 << 0)
++
++/*
++ * Revision register
++ */
++#define FTAPBB020_REV_REVISION(rev)	((rev) & ~(0xff << 24))
++
++enum ftapbb020_bus_type {
++	FTAPBB020_BUS_TYPE_AHB,
++	FTAPBB020_BUS_TYPE_APB,
++};
++
++enum ftapbb020_channels {
++	FTAPBB020_CHANNEL_0 = (1 << 0),
++	FTAPBB020_CHANNEL_1 = (1 << 1),
++	FTAPBB020_CHANNEL_2 = (1 << 2),
++	FTAPBB020_CHANNEL_3 = (1 << 3),
++	FTAPBB020_CHANNEL_ALL = 0xf,
++};
++
++/**
++ * struct ftapbb020_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @type: bus type of the device
++ * @channels: bitmap of usable DMA channels
++ * @handshake: hardware handshake number
++ */
++struct ftapbb020_dma_slave {
++	struct dma_slave_config common;
++	enum ftapbb020_bus_type type;
++//	enum ftapbb020_channels channels;
++	unsigned int handshake;
++};
++
++/**
++ * ftapbb020_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftapbb020_dma_slave
++ */
++bool ftapbb020_chan_filter(struct dma_chan *chan, void *data);
++
++#endif	/* __FTAPBB020_H */
+diff --git a/arch/arm/mach-GM/include/mach/ftdmac020.h b/arch/arm/mach-GM/include/mach/ftdmac020.h
+new file mode 100644
+index 00000000..6a4a9bd2
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/ftdmac020.h
+@@ -0,0 +1,236 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftdmac020.h
++ *
++ *  Faraday FTDMAC020 DMA controller
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTDMAC020_H
++#define __FTDMAC020_H
++
++#include <linux/dmaengine.h>
++
++#define FTDMAC020_OFFSET_ISR		0x0
++#define FTDMAC020_OFFSET_TCISR		0x4
++#define FTDMAC020_OFFSET_TCICR		0x8
++#define FTDMAC020_OFFSET_EAISR		0xc
++#define FTDMAC020_OFFSET_EAICR		0x10
++#define FTDMAC020_OFFSET_TCRAW		0x14
++#define FTDMAC020_OFFSET_EARAW		0x18
++#define FTDMAC020_OFFSET_CH_ENABLED	0x1c
++#define FTDMAC020_OFFSET_CH_BUSY	0x20
++#define FTDMAC020_OFFSET_CR		    0x24
++#define FTDMAC020_OFFSET_SYNC		0x28
++#define FTDMAC020_OFFSET_REVISION	0x2c
++#define FTDMAC020_OFFSET_FEATURE	0x30
++
++#define FTDMAC020_OFFSET_CCR_CH(x)	(0x100 + (x) * 0x20)
++#define FTDMAC020_OFFSET_CFG_CH(x)	(0x104 + (x) * 0x20)
++#define FTDMAC020_OFFSET_SRC_CH(x)	(0x108 + (x) * 0x20)
++#define FTDMAC020_OFFSET_DST_CH(x)	(0x10c + (x) * 0x20)
++#define FTDMAC020_OFFSET_LLP_CH(x)	(0x110 + (x) * 0x20)
++#define FTDMAC020_OFFSET_CYC_CH(x)	(0x114 + (x) * 0x20)
++
++/*
++ * Error/abort interrupt status/clear register
++ * Error/abort status register
++ */
++#define FTDMAC020_EA_ERR_CH(x)		(1 << (x))
++#define FTDMAC020_EA_ABT_CH(x)		(1 << ((x) + 16))
++
++/*
++ * Main configuration status register
++ */
++#define FTDMAC020_CR_ENABLE		(1 << 0)
++#define FTDMAC020_CR_M0_BE		(1 << 1)	/* master 0 big endian */
++#define FTDMAC020_CR_M1_BE		(1 << 2)	/* master 1 big endian */
++
++/*
++ * Channel control register
++ */
++#define FTDMAC020_CCR_ENABLE		(1 << 0)
++#define FTDMAC020_CCR_DST_M1		(1 << 1)
++#define FTDMAC020_CCR_SRC_M1		(1 << 2)
++#define FTDMAC020_CCR_DST_INC		(0x0 << 3)
++#define FTDMAC020_CCR_DST_DEC		(0x1 << 3)
++#define FTDMAC020_CCR_DST_FIXED		(0x2 << 3)
++#define FTDMAC020_CCR_SRC_INC		(0x0 << 5)
++#define FTDMAC020_CCR_SRC_DEC		(0x1 << 5)
++#define FTDMAC020_CCR_SRC_FIXED		(0x2 << 5)
++#define FTDMAC020_CCR_HANDSHAKE		(1 << 7)
++#define FTDMAC020_CCR_DST_WIDTH_8	(0x0 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_16	(0x1 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_32	(0x2 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_64	(0x3 << 8)
++#define FTDMAC020_CCR_SRC_WIDTH_8	(0x0 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_16	(0x1 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_32	(0x2 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_64	(0x3 << 11)
++#define FTDMAC020_CCR_ABORT		    (1 << 15)
++#define FTDMAC020_CCR_BURST_1		(0x0 << 16)
++#define FTDMAC020_CCR_BURST_4		(0x1 << 16)
++#define FTDMAC020_CCR_BURST_8		(0x2 << 16)
++#define FTDMAC020_CCR_BURST_16		(0x3 << 16)
++#define FTDMAC020_CCR_BURST_32		(0x4 << 16)
++#define FTDMAC020_CCR_BURST_64		(0x5 << 16)
++#define FTDMAC020_CCR_BURST_128		(0x6 << 16)
++#define FTDMAC020_CCR_BURST_256		(0x7 << 16)
++#define FTDMAC020_CCR_PRIVILEGED	(1 << 19)
++#define FTDMAC020_CCR_BUFFERABLE	(1 << 20)
++#define FTDMAC020_CCR_CACHEABLE		(1 << 21)
++#define FTDMAC020_CCR_PRIO_0		(0x0 << 22)
++#define FTDMAC020_CCR_PRIO_1		(0x1 << 22)
++#define FTDMAC020_CCR_PRIO_2		(0x2 << 22)
++#define FTDMAC020_CCR_PRIO_3		(0x3 << 22)
++#define FTDMAC020_CCR_FIFOTH_1		(0x0 << 24)
++#define FTDMAC020_CCR_FIFOTH_2		(0x1 << 24)
++#define FTDMAC020_CCR_FIFOTH_4		(0x2 << 24)
++#define FTDMAC020_CCR_FIFOTH_8		(0x3 << 24)
++#define FTDMAC020_CCR_FIFOTH_16		(0x4 << 24)
++#define FTDMAC020_CCR_MASK_TC		(1 << 31)
++
++/*
++ * Channel configuration register
++ */
++#define FTDMAC020_CFG_MASK_TCI		(1 << 0)	/* mask tc interrupt */
++#define FTDMAC020_CFG_MASK_EI		(1 << 1)	/* mask error interrupt */
++#define FTDMAC020_CFG_MASK_AI		(1 << 2)	/* mask abort interrupt */
++#define FTDMAC020_CFG_SRC_HANDSHAKE(x)	(((x) & 0xf) << 3)
++#define FTDMAC020_CFG_SRC_HANDSHAKE_EN	(1 << 7)
++#define FTDMAC020_CFG_BUSY		(1 << 8)
++#define FTDMAC020_CFG_DST_HANDSHAKE(x)	(((x) & 0xf) << 9)
++#define FTDMAC020_CFG_DST_HANDSHAKE_EN	(1 << 13)
++#define FTDMAC020_CFG_LLP_CNT(cfg)	(((cfg) >> 16) & 0xf)
++
++/*
++ * Link list descriptor pointer
++ */
++#define FTDMAC020_LLP_M1		(1 << 0)
++#define FTDMAC020_LLP_ADDR(a)		((a) & ~0x3)
++
++/*
++ * Transfer size register
++ */
++#define FTDMAC020_CYC_MASK		0x3fffff
++
++/**
++ * Table 3-1. Address Map for Linked List Descriptor(Base Address: Cn_LLP[31:2])
++ *
++ * struct ftdmac020_lld - hardware link list descriptor.
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the next link list descriptor
++ * @ctrl: control field
++ * @cycle: transfer size
++ *
++ * should be word aligned.
++ */
++struct ftdmac020_lld {
++	dma_addr_t src;     /* SrcAddr */
++	dma_addr_t dst;     /* DstAddr */
++	dma_addr_t next;    /* LLP */
++	unsigned int ctrl;  /* Control */
++	unsigned int cycle; /* Total Size */
++};
++
++#define FTDMAC020_LLD_CTRL_DST_M1	(1 << 16)
++#define FTDMAC020_LLD_CTRL_SRC_M1	(1 << 17)
++#define FTDMAC020_LLD_CTRL_DST_INC	(0x0 << 18)
++#define FTDMAC020_LLD_CTRL_DST_DEC	(0x1 << 18)
++#define FTDMAC020_LLD_CTRL_DST_FIXED	(0x2 << 18)
++#define FTDMAC020_LLD_CTRL_SRC_INC	(0x0 << 20)
++#define FTDMAC020_LLD_CTRL_SRC_DEC	(0x1 << 20)
++#define FTDMAC020_LLD_CTRL_SRC_FIXED	(0x2 << 20)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_8	(0x0 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_16	(0x1 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_32	(0x2 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_64	(0x3 << 22)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_8	(0x0 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_16	(0x1 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_32	(0x2 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_64	(0x3 << 25)
++#define FTDMAC020_LLD_CTRL_MASK_TC	(1 << 28)
++#define FTDMAC020_LLD_CTRL_FIFOTH_1	(0x0 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_2	(0x1 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_4	(0x2 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_8	(0x3 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_16	(0x4 << 29)
++
++#define FTDMAC020_LLD_CYCLE_MASK	0x3fffff
++
++enum ftdmac020_channels {
++	FTDMAC020_CHANNEL_0 = (1 << 0),
++	FTDMAC020_CHANNEL_1 = (1 << 1),
++	FTDMAC020_CHANNEL_2 = (1 << 2),
++	FTDMAC020_CHANNEL_3 = (1 << 3),
++	FTDMAC020_CHANNEL_4 = (1 << 4),
++	FTDMAC020_CHANNEL_5 = (1 << 5),
++	FTDMAC020_CHANNEL_6 = (1 << 6),
++	FTDMAC020_CHANNEL_7 = (1 << 7),
++	FTDMAC020_CHANNEL_ALL = 0xff,
++};
++
++enum ftdmac020_burst {
++    FTDMAC020_BURST_SZ_1 = 0,
++    FTDMAC020_BURST_SZ_4,
++    FTDMAC020_BURST_SZ_8,
++    FTDMAC020_BURST_SZ_16,
++    FTDMAC020_BURST_SZ_32,
++    FTDMAC020_BURST_SZ_64,
++    FTDMAC020_BURST_SZ_128,
++    FTDMAC020_BURST_SZ_256
++};
++
++enum ftdmac020_ahbmaster {
++    FTDMA020_AHBMASTER_0 = 0,
++    FTDMA020_AHBMASTER_1
++};
++
++/**
++ * struct ftdmac020_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @id: specify which ftdmac020 device to use, -1 for wildcard
++ * @handshake: hardware handshake number, -1 to disable handshake mode
++ */
++struct ftdmac020_dma_slave {
++	struct dma_slave_config common;
++	int id;
++	int handshake;      /* handshake number, -1 means disable */
++	enum ftdmac020_burst     src_size;   /* source burst size selection */
++	enum ftdmac020_ahbmaster src_sel;  /* AHB Master selection */
++	enum ftdmac020_ahbmaster dst_sel;  /* AHB Master selection */
++};
++
++/**
++ * ftdmac020_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftdmac020_dma_slave
++ */
++bool ftdmac020_chan_filter(struct dma_chan *chan, void *data);
++
++/**
++ * ftdmac020_set_platform_chanfilter() - filter function for platform dependent.
++ * @chan_id: DMA channel
++ * @chan_filter_fn: filter function used in platform. When ftdmac020_chan_filter is called, it will
++ *                  call chan_filter_fn as well.
++ * @return value: 0 for success, -1 for fail
++ */
++int ftdmac020_set_platform_chanfilter(int (*chan_filter_fn)(int chan_id));
++
++#endif	/* __FTDMAC020_H */
+diff --git a/arch/arm/mach-GM/include/mach/ftintc010.h b/arch/arm/mach-GM/include/mach/ftintc010.h
+new file mode 100644
+index 00000000..78fa0edf
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/ftintc010.h
+@@ -0,0 +1,83 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftintc010.h
++ *
++ *  Faraday FTINTC010 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef __FTINTC010_H
++#define __FTINTC010_H
++
++#define FTINTC010_OFFSET_IRQSRC		0x00
++#define FTINTC010_OFFSET_IRQMASK	0x04
++#define FTINTC010_OFFSET_IRQCLEAR	0x08
++#define FTINTC010_OFFSET_IRQMODE	0x0c
++#define FTINTC010_OFFSET_IRQLEVEL	0x10
++#define FTINTC010_OFFSET_IRQSTATUS	0x14
++
++#define FTINTC010_OFFSET_FIQSRC		0x20
++#define FTINTC010_OFFSET_FIQMASK	0x24
++#define FTINTC010_OFFSET_FIQCLEAR	0x28
++#define FTINTC010_OFFSET_FIQMODE	0x2c
++#define FTINTC010_OFFSET_FIQLEVEL	0x30
++#define FTINTC010_OFFSET_FIQSTATUS	0x34
++
++#define FTINTC010_OFFSET_IRQSRCEX	0x60
++#define FTINTC010_OFFSET_IRQMASKEX	0x64
++#define FTINTC010_OFFSET_IRQCLEAREX	0x68
++#define FTINTC010_OFFSET_IRQMODEEX	0x6c
++#define FTINTC010_OFFSET_IRQLEVELEX	0x70
++#define FTINTC010_OFFSET_IRQSTATUSEX	0x74
++
++#define FTINTC010_OFFSET_FIQSRCEX		0x80
++#define FTINTC010_OFFSET_FIQMASKEX	    0x84
++#define FTINTC010_OFFSET_FIQCLEAREX	    0x88
++#define FTINTC010_OFFSET_FIQMODEEX	    0x8c
++#define FTINTC010_OFFSET_FIQLEVELEX	    0x90
++#define FTINTC010_OFFSET_FIQSTATUSEX	0x94
++
++#ifndef __ASSEMBLY__
++struct ftintc010_trigger_type {
++	unsigned int irqmode;
++	unsigned int irqlevel;
++	unsigned int fiqmode;
++	unsigned int fiqlevel;
++#ifdef CONFIG_FTINTC010EX
++	unsigned int irqmodeex;
++	unsigned int irqlevelex;
++	unsigned int fiqmodeex;
++	unsigned int fiqlevelex;
++#endif
++};
++
++#include <linux/irq.h>
++
++void __init ftintc010_cascade_irq(unsigned int ftintc010_nr, unsigned int irq);
++
++void __init ftintc010_init(unsigned int ftintc010_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc010_trigger_type *trigger_type);
++/* reconfigure the irq type. Maybe the original is edge trigger, now change to level trigger 
++ * @type:	IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
++ */
++int ftintc010_set_irq_type(unsigned int irq, unsigned int type);
++			   
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FTINTC010_H */
+diff --git a/arch/arm/mach-GM/include/mach/ftintc030.h b/arch/arm/mach-GM/include/mach/ftintc030.h
+new file mode 100644
+index 00000000..ae5a3386
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/ftintc030.h
+@@ -0,0 +1,92 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftintc030.h
++ *
++ *  Faraday FTINTC030 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Po-Yu Chuang
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ */
++
++#ifndef __FTINTC030_H
++#define __FTINTC030_H
++
++#ifdef CONFIG_PLATFORM_GM8210_S
++#define FTINTC030_OFFSET_IRQTARGET	FTINTC030_OFFSET_CPU_1_IRQ
++#else
++#define FTINTC030_OFFSET_IRQTARGET	FTINTC030_OFFSET_CPU_0_IRQ
++#endif
++
++#define FTINTC030_OFFSET_IRQSRC		0x00
++#define FTINTC030_OFFSET_IRQENABLE  0x04
++#define FTINTC030_OFFSET_IRQCLEAR	0x08
++#define FTINTC030_OFFSET_IRQMODE	0x0c
++#define FTINTC030_OFFSET_IRQLEVEL	0x10
++#define FTINTC030_OFFSET_IRQPEND	0x14//IRQSTATUS
++#define FTINTC030_OFFSET_IRQPEND1	0x34
++
++
++#define FTINTC030_OFFSET_IRQCONFIG	0x200
++//#define FTINTC030_OFFSET_IRQTARGET	0x420
++
++#define FTINTC030_OFFSET_CPU_0_FIQ	0x420
++#define FTINTC030_OFFSET_CPU_0_IRQ	0x45C
++#define FTINTC030_OFFSET_CPU_1_FIQ	0x498
++#define FTINTC030_OFFSET_CPU_1_IRQ	0x4D4
++#define FTINTC030_OFFSET_CPU_2_FIQ	0x510
++#define FTINTC030_OFFSET_CPU_2_IRQ	0x54C
++#define FTINTC030_OFFSET_CPU_3_FIQ	0x588
++#define FTINTC030_OFFSET_CPU_3_IRQ	0x5C4
++
++#define FTINTC010_OFFSET_FIQCLEAREX	0x88
++
++#ifndef __ASSEMBLY__
++struct ftintc030_trigger_type {
++	unsigned int irqmode[15];
++	unsigned int irqlevel[15];
++	unsigned int fiqmode[15];
++	unsigned int fiqlevel[15];
++};
++
++/* IRQ */
++#define FTINTC030_TARGETIRQ_CPU0   0x1
++#define FTINTC030_TARGETIRQ_CPU1   0x2
++#define FTINTC030_TARGETIRQ_CPU2   0x4
++#define FTINTC030_TARGETIRQ_CPU3   0x8
++/* FIQ */
++#define FTINTC030_TARGETFIQ_CPU0   0x1
++#define FTINTC030_TARGETFIQ_CPU1   0x2
++#define FTINTC030_TARGETFIQ_CPU2   0x4
++#define FTINTC030_TARGETFIQ_CPU3   0x8
++
++void __init ftintc030_cascade_irq(unsigned int ftintc030_nr, unsigned int irq);
++
++void __init ftintc030_init(unsigned int ftintc030_nr, void __iomem *base,
++			   unsigned int irq_start,
++			   struct ftintc030_trigger_type *trigger_type);
++
++/*
++ * Set a highlevel chained flow handler for a given IRQ.
++ * ftintc030_nr: INTC030 index
++ * irq: which irq number is the cascade irq
++ * handler: the handler function of this cascade irq
++ * handler_data: private data of the handler
++ */
++void ftintc030_setup_chain_irq(unsigned int ftintc030_nr, unsigned int irq, void *handler, void *handler_data);
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FTINTC030_H */
+diff --git a/arch/arm/mach-GM/include/mach/ftpmu010.h b/arch/arm/mach-GM/include/mach/ftpmu010.h
+new file mode 100644
+index 00000000..98b21150
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/ftpmu010.h
+@@ -0,0 +1,277 @@
++/*
++ *  arch/arm/mach-GM/include/mach/ftpmu010.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __FTPMU010_H
++#define __FTPMU010_H
++
++#include <mach/platform/pmu.h>
++
++#define PMU010_NAME "ftpmu010"
++#define NAME_SZ     20
++
++
++/*  MACROs for reading clock source
++ */
++#define PLL1_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL1)
++#define PLL2_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL2)
++#define PLL3_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL3)
++#define PLL4_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL4)
++#define PLL5_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_PLL5)
++#define AXI_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_AXI)
++#define AXI0_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_AXI0)
++#define AXI1_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_AXI1)
++#define AXI2_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_AXI2)
++#define AHB_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_AHB)
++#define APB_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_APB)
++#define APB0_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_APB0)
++#define APB1_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_APB1)
++#define APB2_CLK_IN     ftpmu010_get_attr(ATTR_TYPE_APB2)
++#define CPU_CLK_IN      ftpmu010_get_attr(ATTR_TYPE_CPU)
++
++typedef enum {
++    FTPMU_H264E_0 = 0x1,
++    FTPMU_H264D_0,
++    FTPMU_H264E_1,
++    FTPMU_H264D_1,
++    FTPMU_SCALER_0,
++    FTPMU_SCALER_1,
++    FTPMU_3DI_0,
++    FTPMU_3DI_1,
++    FTPMU_LCD_0,
++    FTPMU_LCD_1,
++    FTPMU_LCD_2,
++    FTPMU_CAP_0,
++    FTPMU_CAP_1,
++    FTPMU_CAP_2,
++    FTPMU_CAP_3,
++    FTPMU_ISP_0,
++    FTPMU_ISP_1,
++    FTPMU_AES,
++    FTPMU_MCP100_0,
++    FTPMU_NONE = 0xFFFFF,
++} ftpmu010_midx_t;
++
++typedef struct {
++    ftpmu010_midx_t midx;   /* module idx */
++    int             num;    /* number of clock gate */
++    struct {
++        unsigned int ofs;
++        unsigned int bit_val;    //specify the enable value
++        unsigned int bit_mask;   //specify gating clock bits
++    } reg[3];
++} ftpmu010_gate_clk_t;
++
++/* PMU init function
++ * Input parameters: virtual address of PMU
++ *  tbl: clock gating table for IPs
++ *  pmu_handler: the callback from pmu to reload/reconfigure pmu. NULL if unecessary
++ * Return: 0 for success, < 0 for fail
++ */
++int ftpmu010_init(void __iomem  *base, ftpmu010_gate_clk_t *tbl, void *pmu_handler);
++
++typedef enum
++{
++    ATTR_TYPE_NONE = 0,
++    ATTR_TYPE_PLL1,
++    ATTR_TYPE_PLL2,
++    ATTR_TYPE_PLL3,
++    ATTR_TYPE_PLL4,
++    ATTR_TYPE_PLL5,
++    ATTR_TYPE_AXI,
++    ATTR_TYPE_AHB,
++    ATTR_TYPE_APB,
++    ATTR_TYPE_APB0,
++    ATTR_TYPE_APB1,
++    ATTR_TYPE_APB2,
++    ATTR_TYPE_CPU,
++    ATTR_TYPE_PMUVER,
++    ATTR_TYPE_CHIPVER,
++    ATTR_TYPE_EPCNT,
++    ATTR_TYPE_CPUENUM,  //for: 0 for RC_FA726, 1: RC_FA626, 2: RC_fC7500......
++    ATTR_TYPE_AXI0,
++    ATTR_TYPE_AXI1,
++    ATTR_TYPE_AXI2,
++    ATTR_TYPE_IDPIN,
++} ATTR_TYPE_T;
++
++/* cpu enumerator in whole system */
++typedef enum {
++    CPU_RC_FA726    = 0,
++    CPU_RC_FA626    = 1,
++    CPU_RC_FC7500   = 2,
++    CPU_EP0_FA726   = 3,
++    CPU_EP0_FA626   = 4,
++    CPU_EP0_FC7500  = 5,
++} attr_cpu_enum_t;
++
++typedef enum {
++    PMUVER_A = 0,
++    PMUVER_B,
++    PMUVER_C,
++    PMUVER_D,
++    PMUVER_UNKNOWN,
++} pmuver_t;
++
++typedef struct
++{
++    char          name[NAME_SZ+1];    /* hclk, .... */
++    ATTR_TYPE_T   attr_type;
++    unsigned int  value;
++} attrInfo_t;
++
++/* register attribute
++ */
++int ftpmu010_register_attr(attrInfo_t *attr);
++int ftpmu010_deregister_attr(attrInfo_t *attr);
++/* get attribute value
++ * return value: 0 for fail, > 0 for success
++ */
++unsigned int ftpmu010_get_attr(ATTR_TYPE_T attr);
++
++
++/*
++ * Structure for pinMux
++ */
++typedef struct
++{
++    unsigned int  reg_off;    /* register offset from PMU base */
++    unsigned int  bits_mask;  /* bits this module covers */
++    unsigned int  lock_bits;  /* bits this module locked */
++    unsigned int  init_val;   /* initial value */
++    unsigned int  init_mask;  /* initial mask */
++} pmuReg_t;
++
++typedef struct
++{
++    char        name[NAME_SZ+1];    /* module name length */
++    int         num;                /* number of register entries */
++    ATTR_TYPE_T clock_src;          /* which clock this module uses */
++    pmuReg_t    *pRegArray;         /* register array */
++} pmuRegInfo_t;
++
++/* register/de-register the register table
++ * return value:
++ *  give an unique fd if return value >= 0, otherwise < 0 if fail.
++ */
++int ftpmu010_register_reg(pmuRegInfo_t *info);
++int ftpmu010_deregister_reg(int fd);
++
++/* lock/unlock/replace the bits in lock_bits field
++ * return value:
++ *  0 for success, < 0 for fail
++ */
++int ftpmu010_add_lockbits(int fd, unsigned int reg_off, unsigned int lock_bits);
++int ftpmu010_del_lockbits(int fd, unsigned int reg_off, unsigned int unlock_bits);
++int ftpmu010_update_lockbits(int fd, unsigned int reg_off, unsigned int new_lock_bits);
++/* @int ftpmu010_bits_is_locked(int reg_off, unsigned int bits)
++ * @Purpose: This function is used to check if the bits are locked by any module or not.
++ * @Parameter:
++ *   reg_off: register offset
++ *   bits: the checked bits
++ * @Return:
++ *      If the any bit in bits is locked, then the returned value will be 0
++ *      otherwise, -1 is returned to indicates all bits are available.
++ *
++ */
++int ftpmu010_bits_is_locked(int fd, unsigned int reg_off, unsigned int bits);
++
++/* PMU register read/write
++ */
++unsigned int ftpmu010_read_reg(unsigned int reg_off);
++/* return value < 0 for fail */
++int ftpmu010_write_reg(int fd, unsigned int reg_off, unsigned int val, unsigned int mask);
++
++/* Purpose: calculate the divisor by input clock
++ * Input: fd, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor(int fd, unsigned int in_clock, int near);
++
++/* Purpose: calculate the divisor by input clock attribute
++ * Input: clock_src, in_clock, near
++ * Output: None
++ * Return: quotient if > 0, 0 for fail
++ * Note: The return value will take the nearest value if near is 1. For example: 17.6 will be treated as 18,
++ *          but 17.4 will be treated as 17.
++ */
++unsigned int ftpmu010_clock_divisor2(ATTR_TYPE_T clock_src, unsigned int in_clock, int near);
++
++/* @Purpose: request the pmu PINs
++ * @Parameter:
++ *      fd: unique identifier
++ *      reg_off: register offset
++ *      req_bits: request registers
++ *      b_wait: 1 for blocking until the resource is available
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_request_pins(int fd, unsigned int reg_off, unsigned int req_bits, int b_wait);
++
++
++/* Purpose: release the pmu PINs
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: 0 for success, !0 for fail
++ */
++int ftpmu010_release_pins(int fd, unsigned int reg_off, unsigned int req_bits);
++
++/* Purpose: check if the PINs was requested by others except myself.
++ * Input: fd, reg_off, req_bits
++ * Output: None
++ * Return: those pins occupied by others. zero indicates the pin are available.
++ */
++unsigned int ftpmu010_pins_is_requested(int fd, unsigned int reg_off, unsigned int req_bits);
++/*
++ * The following is used for specific functionality to PMU
++ */
++#define FUNC_TYPE_RELOAD_ATTR   0
++#define FUNC_TYPE_INTR_CLR      1
++#define FUNC_TYPE_INTR_FIRE     2
++
++/*
++ * The following function are used for module to send/clear interrupt.
++ * return: 0 for success, -1 for fail
++ */
++/* send interrupt from pmu */
++static inline int ftpmu010_trigger_intr(int irq)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_INTR_FIRE , irq, 0);
++}
++/* clear interupt in pmu */
++static inline int ftpmu010_clear_intr(int irq)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_INTR_CLR , irq, 0);
++}
++/* force the attribute refresh again */
++static inline int ftpmu010_reload_attr(ATTR_TYPE_T attr_type)
++{
++    extern int ftpmu010_pmu_doaction(u32 cmd, u32 data1, u32 data2);
++
++    return ftpmu010_pmu_doaction(FUNC_TYPE_RELOAD_ATTR , attr_type, 0);
++}
++
++#endif	/* __FTPMU010_H */
+diff --git a/arch/arm/mach-GM/include/mach/fttmr010.h b/arch/arm/mach-GM/include/mach/fttmr010.h
+new file mode 100644
+index 00000000..4f10f121
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/fttmr010.h
+@@ -0,0 +1,87 @@
++/*
++ * Copyright (C) 2009 Po-Yu Chuang
++ * Copyright (C) 2009 Faraday Technology
++ *
++ * 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.
++ */
++
++/*
++ * Timer
++ */
++#ifndef __FTTMR010_H
++#define __FTTMR010_H
++
++#define FTTMR010_OFFSET_COUNTER		0x00
++#define FTTMR010_OFFSET_LOAD		0x04
++#define FTTMR010_OFFSET_MATCH1		0x08
++#define FTTMR010_OFFSET_MATCH2		0x0c
++#define FTTMR010_OFFSET_TIMER(x)	((x) * 0x10)
++#define FTTMR010_OFFSET_CR		0x30
++#define FTTMR010_OFFSET_INTR_STATE	0x34
++#define FTTMR010_OFFSET_INTR_MASK	0x38
++
++/*
++ * Timer Control Register
++ */
++#define FTTMR010_TM3_UPDOWN	(1 << 11)
++#define FTTMR010_TM2_UPDOWN	(1 << 10)
++#define FTTMR010_TM1_UPDOWN	(1 << 9)
++#define FTTMR010_TM3_OFENABLE	(1 << 8)
++#define FTTMR010_TM3_CLOCK	(1 << 7)
++#define FTTMR010_TM3_ENABLE	(1 << 6)
++#define FTTMR010_TM2_OFENABLE	(1 << 5)
++#define FTTMR010_TM2_CLOCK	(1 << 4)
++#define FTTMR010_TM2_ENABLE	(1 << 3)
++#define FTTMR010_TM1_OFENABLE	(1 << 2)
++#define FTTMR010_TM1_CLOCK	(1 << 1)
++#define FTTMR010_TM1_ENABLE	(1 << 0)
++
++/*
++ * Timer Interrupt State & Mask Registers
++ */
++#define FTTMR010_TM3_OVERFLOW	(1 << 8)
++#define FTTMR010_TM3_MATCH2	(1 << 7)
++#define FTTMR010_TM3_MATCH1	(1 << 6)
++#define FTTMR010_TM2_OVERFLOW	(1 << 5)
++#define FTTMR010_TM2_MATCH2	(1 << 4)
++#define FTTMR010_TM2_MATCH1	(1 << 3)
++#define FTTMR010_TM1_OVERFLOW	(1 << 2)
++#define FTTMR010_TM1_MATCH2	(1 << 1)
++#define FTTMR010_TM1_MATCH1	(1 << 0)
++
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++
++struct fttmr010_clockevent {
++	struct clock_event_device	clockevent;
++	struct irqaction		irqaction;
++	void __iomem			*base;
++	unsigned int			id;	/* one of 3 counters */
++	unsigned int			reload;
++	unsigned int			freq;
++};
++
++struct fttmr010_clocksource {
++	struct clocksource	clocksource;
++	void __iomem		*base;
++	unsigned int		id;	/* one of 3 counters */
++	unsigned int		freq;
++};
++
++void __init fttmr010_clockevent_init(struct fttmr010_clockevent *fttmr010);
++void __init fttmr010_clocksource_init(struct fttmr010_clocksource *fttmr010);
++
++#endif	/* __FTTMR010_H */
+diff --git a/arch/arm/mach-GM/include/mach/gm_jiffies.h b/arch/arm/mach-GM/include/mach/gm_jiffies.h
+new file mode 100644
+index 00000000..66d4196b
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/gm_jiffies.h
+@@ -0,0 +1,27 @@
++#ifndef __GM_JIFFIES_H__
++#define __GM_JIFFIES_H__
++
++#define gm_jiffies      get_gm_jiffies()
++#define gm_jiffies_u64  get_gm_jiffies_u64()
++
++/* @unsigned long get_gm_jiffies(void)
++ * @Purpose: This function provides jiffies with 1ms granularity. This value will count up to 0xFFFFFFFF
++ *           and warp around again.
++ * @Parameter:
++ *   None
++ * @Return:
++ *      0 means the timer is not active. Othwise return non-zero value.
++ */
++unsigned long get_gm_jiffies(void);
++
++/* @u64 get_gm_jiffies_u64(void)
++ * @Purpose: This function provides jiffies with 1ms granularity. This value will count up to 0xFFFFFFFFFFFFFFFF
++ *           and warp around again.
++ * @Parameter:
++ *   None
++ * @Return:
++ *      0 means the timer is not active. Othwise return non-zero value.
++ */
++u64 get_gm_jiffies_u64(void);
++
++#endif /* __GM_JIFFIES_H__ */
+\ No newline at end of file
+diff --git a/arch/arm/mach-GM/include/mach/hardware.h b/arch/arm/mach-GM/include/mach/hardware.h
+new file mode 100644
+index 00000000..cd3c7737
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/hardware.h
+@@ -0,0 +1,38 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/hardware.h
++ *
++ *  This file contains the hardware definitions of the Faraday boards.
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_H
++#define __ASM_ARCH_HARDWARE_H
++
++#ifndef PCIBIOS_MIN_IO
++/* the mini io address is 0x6000,that is IO will allocate from 0-0x6000 offset*/
++#define PCIBIOS_MIN_IO	0x0
++#endif
++
++#ifndef PCIBIOS_MIN_MEM
++/* the mini MEM address is 0x100000,that is MEM will allocate from 0-0x100000 offset*/
++#define PCIBIOS_MIN_MEM	0x0
++#endif
++
++#define pcibios_assign_all_busses()	1
++
++#endif /* __ASM_ARCH_HARDWARE_H */
+diff --git a/arch/arm/mach-GM/include/mach/io.h b/arch/arm/mach-GM/include/mach/io.h
+new file mode 100644
+index 00000000..238defe3
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/io.h
+@@ -0,0 +1,18 @@
++/* arch/arm/mach-s3c64xxinclude/mach/io.h
++ *
++ * Copyright 2008 Simtec Electronics
++ *	Ben Dooks <ben-linux@fluff.org>
++ *
++ * Default IO routines for S3C64XX based
++ */
++
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++/* No current ISA/PCI bus support. */
++#define __io(a)		((void __iomem *)(a))//__typesafe_io(a)
++#define __mem_pci(a)	(a)
++
++#define IO_SPACE_LIMIT (0xFFFFFFFF)
++
++#endif
+diff --git a/arch/arm/mach-GM/include/mach/irqs.h b/arch/arm/mach-GM/include/mach/irqs.h
+new file mode 100644
+index 00000000..a30bfb22
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/irqs.h
+@@ -0,0 +1,34 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/irqs.h
++ *
++ *  Faraday Platform Independent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 09/16/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__
++
++/* Include platform *dependent* IRQ definitions */
++#include <mach/platform/irqs.h>
++
++#endif /* __GM_PLATFORM_INDEPENDENT_IRQS_HEADER__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/memory.h b/arch/arm/mach-GM/include/mach/memory.h
+new file mode 100644
+index 00000000..d91f1a70
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/memory.h
+@@ -0,0 +1,48 @@
++/*
++ *  arch/arm/mach-GM/include/mach/memory.h
++ *  
++ *  Faraday Platform Independent Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ *  Harry Hsu 04/06/2010 add "isolate high memory" function
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__
++
++#include <asm/sizes.h>
++#include <mach/platform/memory.h>
++#include <mach/platform/platform_io.h>
++
++#define MEM_SIZE        SZ_256M
++#define END_MEM		    (CPU_MEM_PA_LIMIT + 1)
++
++#define CONSISTENT_DMA_SIZE  (12 << 20)	/* 12M NISH_20121015 */
++
++#ifndef __ASSEMBLY__
++extern unsigned long fmem_virt_to_phys(unsigned int vaddr);
++extern unsigned int fmem_phys_to_virt(unsigned long phys);
++
++#define __virt_to_phys(x)	fmem_virt_to_phys((unsigned int)(x))  //((x) - PAGE_OFFSET + PHYS_OFFSET)
++#define __phys_to_virt(x)	fmem_phys_to_virt((unsigned long)(x))  //((x) - PHYS_OFFSET + PAGE_OFFSET)
++#endif /* __ASSEMBLY__ */
++
++#endif /* __GM_PLATFORM_INDEPENDENT_MEMORY_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform b/arch/arm/mach-GM/include/mach/platform
+new file mode 120000
+index 00000000..e8ee9a89
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform
+@@ -0,0 +1 @@
++platform-GM8136
+\ No newline at end of file
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/board.h b/arch/arm/mach-GM/include/mach/platform-GM8126/board.h
+new file mode 100644
+index 00000000..bf00de68
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/board.h
+@@ -0,0 +1,84 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/board.h
++ *  
++ *  GM board Independent Specification
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 
++ *
++ *  ChangeLog
++ *  
++ *   Harry  2012/3/6 03:15 created. 
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM8126"
++#define BOOT_PARAMETER_PA_BASE  (CPU_MEM_PA_BASE + 0x100)
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)   
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0x99000000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE	0x98300000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        9
++
++/* TIMER */
++#define TIMER_FTTMR010_PA_BASE	    0x99100000
++#define TIMER_FTTMR010_VA_BASE	    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         14
++#define TIMER_FTTMR010_IRQ1         14
++#define TIMER_FTTMR010_IRQ2         14
++
++/* INTC */
++#define INTC_FTINTC010_PA_BASE      0x99500000
++#define INTC_FTINTC010_VA_BASE      (TIMER_FTTMR010_VA_BASE + TIMER_FTTMR010_VA_SIZE)
++#define INTC_FTINTC010_VA_SIZE	    SZ_4K
++
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE    
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__ 
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/dma_route.h b/arch/arm/mach-GM/include/mach/platform-GM8126/dma_route.h
+new file mode 100644
+index 00000000..4fbf887a
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/dma_route.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
++ *
++ * 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.
++ * 
++ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++#ifndef __DMA_ROUTE_H__
++#define __DMA_ROUTE_H__
++
++/* define AHB DMA routing table 
++ */
++#define AHBDMA_REQ_SSP0_RX  0
++#define AHBDMA_REQ_SSP0_TX  1
++#define AHBDMA_REQ_SSP1_RX  2
++#define AHBDMA_REQ_SSP1_TX  3
++#define AHBDMA_REQ_SSP2_RX  4
++#define AHBDMA_REQ_SSP2_TX  5
++#define AHBDMA_REQ_SDC      6
++#define AHBDMA_REQ_NANDC    9
++#define AHBDMA_REQ_PWMTMR5  12
++#define AHBDMA_REQ_PWMTMR6  13
++#define AHBDMA_REQ_PWMTMR7  14
++#define AHBDMA_REQ_PWMTMR8  15
++
++/* define APB DMA routing table 
++ */
++#define APBDMA_REQ_UART0_RX 1
++#define APBDMA_REQ_UART0_TX 2
++#define APBDMA_REQ_UART1_RX 3
++#define APBDMA_REQ_UART1_TX 4
++#define APBDMA_REQ_UART2_RX 5
++#define APBDMA_REQ_UART2_TX 6
++#define APBDMA_REQ_UART3_RX 7  
++#define APBDMA_REQ_UART3_TX 8
++#define APBDMA_REQ_UART4_RX 9  
++#define APBDMA_REQ_UART4_TX 10
++#define APBDMA_REQ_PWMTMR1  12
++#define APBDMA_REQ_PWMTMR2  13
++#define APBDMA_REQ_PWMTMR3  14
++#define APBDMA_REQ_PWMTMR4  15
++
++
++#endif /* __DMA_ROUTE_H__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/gpio.h b/arch/arm/mach-GM/include/mach/platform-GM8126/gpio.h
+new file mode 100644
+index 00000000..c26a9e86
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8126_GPIO_H__
++#define __GM8126_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		3
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8126_GPIO_H__
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/irqs.h b/arch/arm/mach-GM/include/mach/platform-GM8126/irqs.h
+new file mode 100644
+index 00000000..f836656e
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/irqs.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8126/irqs.h
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 10/06/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/memory.h b/arch/arm/mach-GM/include/mach/platform-GM8126/memory.h
+new file mode 100644
+index 00000000..cb3a5f91
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/memory.h
+@@ -0,0 +1,63 @@
++/*
++ *  linux/include/asm-armnommu/arch-GM/platform-GM8126/memory.h
++ *  
++ *  GM Platform Dependent Memory Configuration
++ *  
++ * 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
++ *  
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define PHYS_OFFSET     CPU_MEM_PA_BASE
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management. 
++ *
++ * Users can adjust the memory size based on the real memory size requirement.  
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     0x1000000
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement. 
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE. 
++ * The memory boundary is 16M alginment 
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/platform_io.h b/arch/arm/mach-GM/include/mach/platform-GM8126/platform_io.h
+new file mode 100644
+index 00000000..7a1cb8be
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/platform_io.h
+@@ -0,0 +1,575 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8126/platform_io.h
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *  
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++
++#define PLATFORM_FIQ_BASE       0
++#define PLATFORM_INTERRUPTS     64      /* interrupt controller supports 64 interrupts */
++#define CPU_MEM_PA_BASE         0x0     /* the memory physical start address(DDR) */
++
++/*
++ * Component counts
++ */ 
++
++/* PWMTMR */
++#define PWMTMR_COUNT	1
++#define PWMTMR_FTPWM010_COUNT	1
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	3
++#define GPIO_FTGPIO010_COUNT	3
++/* I2C */
++#define I2C_COUNT	1
++#define I2C_FTI2C010_COUNT	1 
++/* SSP */
++#define SSP_COUNT	3
++#define SSP_FTSSP010_COUNT	3
++/* SDC */
++#define SDC_COUNT	1
++#define SDC_FTSDC010_COUNT	1
++/* NAND */
++#define NAND_COUNT	1
++#define NAND_FTNAND023_COUNT	1
++/* NANDDP */
++#define NANDDP_COUNT	1
++#define NANDDP_FTNAND023_COUNT	1
++/* USB */
++#define USB_COUNT       1
++#define USB_FOTG2XX_COUNT       1
++/* LCD */
++#define LCD_COUNT	1
++#define LCD_FTLCDC200_COUNT	1
++/* MAC */
++#define MAC_COUNT	1
++#define MAC_FTMAC110_COUNT	1
++/* TVE */
++#define TVE_COUNT	1
++#define TVE_FTTVE100_COUNT	1
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* SCAL */
++#define SCAL_COUNT	1
++#define SCAL_FTSCAL010_COUNT	1
++/* CAP */
++#define CAP_COUNT	2
++#define CAP_FTCAP020_COUNT	2
++/* DI3D */
++#define DI3D_COUNT	1
++#define DI3D_FTDI3D_COUNT	1
++/* H264E */
++#define H264E_COUNT	1
++#define H264E_FTMCP200_COUNT	1
++/* WRAP */
++#define WRAP_COUNT	1
++#define WRAP_FTWRAP00_COUNT	1
++/* MCP100W */
++#define MCP100W_COUNT	1
++#define MCP100W_FTMCP100_COUNT	1
++/* MCP */
++#define MCP_COUNT	1
++#define MCP_FTMCP100_COUNT	1
++/* CT656 */
++#define CT656_COUNT	1
++#define CT656_FTCT656_COUNT	1
++/* ISP_BME */
++#define ISP_BME_COUNT	1
++#define ISP_BME_FTISPBME_COUNT	1
++/* ISP210 */
++#define ISP210_COUNT	1
++#define ISP210_FTISP210_COUNT	1
++/* IR_DET */
++#define IR_DET_COUNT	1
++#define IR_DET_FTIRDET_COUNT	1
++/* RTC */
++#define RTC_COUNT	1
++#define RTC_FTRTC_COUNT	1
++
++/* ADC */
++#define ADC_COUNT	1
++#define ADC_WRAP_COUNT	1
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_COUNT 1
++
++/* APBBRG */
++#define APBBRG_COUNT	1
++#define APBBRG_FTAPBBRG020S_COUNT	1
++
++/* DDRC */
++#define DDRC_COUNT	1
++#define DDRC_FTDDRC010_COUNT	1
++/*
++ * Interrrupt numbers
++ */
++/* PWMTMR */
++#define PWMTMR_FTPWM010_IRQ_COUNT	8
++#define PWMTMR_FTPWM010_IRQ0	34
++#define PWMTMR_FTPWM010_0_IRQ0	34
++#define PWMTMR_FTPWM010_IRQ1	35
++#define PWMTMR_FTPWM010_0_IRQ1	35
++#define PWMTMR_FTPWM010_IRQ2	36
++#define PWMTMR_FTPWM010_0_IRQ2	36
++#define PWMTMR_FTPWM010_IRQ3	37
++#define PWMTMR_FTPWM010_0_IRQ3	37
++#define PWMTMR_FTPWM010_IRQ4	38
++#define PWMTMR_FTPWM010_0_IRQ4	38
++#define PWMTMR_FTPWM010_IRQ5	42
++#define PWMTMR_FTPWM010_0_IRQ5	42
++#define PWMTMR_FTPWM010_IRQ6	43
++#define PWMTMR_FTPWM010_0_IRQ6	43
++#define PWMTMR_FTPWM010_IRQ7	44
++#define PWMTMR_FTPWM010_0_IRQ7	44
++
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	16
++#define WDT_FTWDT010_0_IRQ	16
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	1
++#define GPIO_FTGPIO010_IRQ	13
++#define GPIO_FTGPIO010_0_IRQ	13
++#define GPIO_FTGPIO010_1_IRQ	17
++#define GPIO_FTGPIO010_2_IRQ	25
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	18
++#define I2C_FTI2C010_0_IRQ	18
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	6
++#define SSP_FTSSP010_0_IRQ	6
++#define SSP_FTSSP010_1_IRQ	7
++#define SSP_FTSSP010_2_IRQ	11
++
++/* SDC */
++#define SDC_FTSDC010_IRQ_COUNT	1
++#define SDC_FTSDC010_IRQ	15
++#define SDC_FTSDC010_0_IRQ	15
++
++/* NAND */
++#define NAND_FTNAND023_IRQ_COUNT	1
++#define NAND_FTNAND023_IRQ	23
++#define NAND_FTNAND023_0_IRQ	23
++
++/* USB */
++#define USB_FOTG2XX_IRQ_COUNT	1
++#define USB_FOTG2XX_IRQ		4
++#define USB_FOTG2XX_0_IRQ	4
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	24
++#define LCD_FTLCDC200_0_IRQ	24
++
++/* MAC */
++#define MAC_FTMAC110_IRQ_COUNT	1
++#define MAC_FTMAC110_IRQ	3
++#define MAC_FTMAC110_0_IRQ	3
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	19
++#define AES_FTAES020_0_IRQ	19
++
++/* SCAL */
++#define SCAL_FTSCAL010_IRQ_COUNT	1
++#define SCAL_FTSCAL010_IRQ	12
++#define SCAL_FTSCAL010_0_IRQ	12
++
++/* CAP */
++#define CAP_FTCAP020_IRQ_COUNT	1
++#define CAP_FTCAP020_IRQ	32
++#define CAP_FTCAP020_0_IRQ	32
++#define CAP_FTCAP020_1_IRQ	33
++
++/* DI3D */
++#define DI3D_FTDI3D_IRQ_COUNT	1
++#define DI3D_FTDI3D_IRQ	41
++#define DI3D_FTDI3D_0_IRQ	41
++
++/* H264E */
++#define H264E_FTMCP200_IRQ_COUNT	1
++#define H264E_FTMCP200_IRQ	29
++#define H264E_FTMCP200_0_IRQ	29
++
++/* WRAP */
++#define WRAP_FTWRAP00_IRQ_COUNT	1
++#define WRAP_FTWRAP00_IRQ	29
++#define WRAP_FTWRAP00_0_IRQ	29
++
++/* MCP100W */
++#define MCP100W_FTMCP100_IRQ_COUNT	1
++#define MCP100W_FTMCP100_IRQ	31
++#define MCP100W_FTMCP100_0_IRQ	31
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	1
++#define MCP_FTMCP100_IRQ	31
++#define MCP_FTMCP100_0_IRQ	31
++
++/* ISP_BME */
++#define ISP_BME_FTISPBME_IRQ_COUNT  1
++#define ISP_BME_FTISPBME_IRQ    45
++#define ISP_BME_FTISPBME_0_IRQ  45
++
++/* ISP210 */
++#define ISP210_FTISP210_IRQ_COUNT	3
++#define ISP210_FTISP210_IRQ0	27
++#define ISP210_FTISP210_0_IRQ0	27
++#define ISP210_FTISP210_IRQ1	28
++#define ISP210_FTISP210_0_IRQ1	28
++#define ISP210_FTISP210_IRQ2	30
++#define ISP210_FTISP210_0_IRQ2	30
++
++/* IR_DET */
++#define IR_DET_FTIRDET_IRQ_COUNT	1
++#define IR_DET_FTIRDET_IRQ	39
++#define IR_DET_FTIRDET_0_IRQ	39
++
++/* RTC */
++#define RTC_FTRTC_IRQ_COUNT	1
++#define RTC_FTRTC_IRQ	5
++#define RTC_FTRTC_0_IRQ	5
++
++/* ADC */
++#define ADC_WRAP_IRQ_COUNT	1
++#define ADC_WRAP_IRQ	40
++#define ADC_WRAP_0_IRQ	40
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_IRQ_COUNT    1
++#define DMAC_FTDMAC020_IRQ  1
++
++/* APBBRG */
++#define APBBRG_FTAPBBRG020S_IRQ_COUNT	1
++#define APBBRG_FTAPBBRG020S_IRQ		2
++
++/*
++ * Base addresses
++ */
++ 
++/* PWMTMR */
++#define PWMTMR_FTPWM010_PA_COUNT	1
++#define PWMTMR_FTPWM010_PA_BASE	    0x98B00000
++#define PWMTMR_FTPWM010_PA_LIMIT	0x98B0FFFF
++#define PWMTMR_FTPWM010_PA_SIZE	    0x00010000
++#define PWMTMR_FTPWM010_0_PA_BASE	0x98B00000
++#define PWMTMR_FTPWM010_0_PA_LIMIT	0x98B0FFFF
++#define PWMTMR_FTPWM010_0_PA_SIZE	0x00010000
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x99200000
++#define WDT_FTWDT010_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x99200000
++#define WDT_FTWDT010_0_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	1
++#define GPIO_FTGPIO010_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0x99700000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0x99700FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_2_PA_BASE	0x99800000
++#define GPIO_FTGPIO010_2_PA_LIMIT	0x99800FFF
++#define GPIO_FTGPIO010_2_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0x99600000
++#define I2C_FTI2C010_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0x99600000
++#define I2C_FTI2C010_0_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0x98200000
++#define SSP_FTSSP010_PA_LIMIT	0x98200FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0x98200000
++#define SSP_FTSSP010_0_PA_LIMIT	0x98200FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0x98600000
++#define SSP_FTSSP010_1_PA_LIMIT	0x98600FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++#define SSP_FTSSP010_2_PA_BASE	0x98A00000
++#define SSP_FTSSP010_2_PA_LIMIT	0x98A00FFF
++#define SSP_FTSSP010_2_PA_SIZE	0x00001000
++
++/* SDC */
++#define SDC_FTSDC010_PA_COUNT	1
++#define SDC_FTSDC010_PA_BASE	0x92800000
++#define SDC_FTSDC010_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC010_PA_SIZE	0x00001000
++#define SDC_FTSDC010_0_PA_BASE	0x92800000
++#define SDC_FTSDC010_0_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC010_0_PA_SIZE	0x00001000
++
++/* NAND */
++#define NAND_FTNAND023_PA_COUNT	1
++#define NAND_FTNAND023_PA_BASE	0x92C00000
++#define NAND_FTNAND023_PA_LIMIT	0x92CFFFFF
++#define NAND_FTNAND023_PA_SIZE	0x00100000
++#define NAND_FTNAND023_0_PA_BASE	0x92C00000
++#define NAND_FTNAND023_0_PA_LIMIT	0x92CFFFFF
++#define NAND_FTNAND023_0_PA_SIZE	0x00100000
++
++/* NANDDP */
++#define NANDDP_FTNAND023_PA_COUNT	1
++#define NANDDP_FTNAND023_PA_BASE	0x96000000
++#define NANDDP_FTNAND023_PA_LIMIT	0x960FFFFF
++#define NANDDP_FTNAND023_PA_SIZE	0x00100000
++#define NANDDP_FTNAND023_0_PA_BASE	0x96000000
++#define NANDDP_FTNAND023_0_PA_LIMIT	0x960FFFFF
++#define NANDDP_FTNAND023_0_PA_SIZE	0x00100000
++#define NANDDP_FTNAND023_VA_COUNT	1
++#define NANDDP_FTNAND023_VA_BASE	0xF9600000
++#define NANDDP_FTNAND023_VA_LIMIT	0xF960FFFF
++#define NANDDP_FTNAND023_VA_SIZE	0x00010000
++#define NANDDP_FTNAND023_0_VA_BASE	0xF9600000
++#define NANDDP_FTNAND023_0_VA_LIMIT	0xF960FFFF
++#define NANDDP_FTNAND023_0_VA_SIZE	0x00010000
++
++/* USB */
++#define USB_FOTG2XX_PA_COUNT	1
++#define USB_FOTG2XX_PA_BASE	0x92200000
++#define USB_FOTG2XX_PA_LIMIT	0x92200FFF
++#define USB_FOTG2XX_PA_SIZE	0x00001000
++#define USB_FOTG2XX_0_PA_BASE	0x92200000
++#define USB_FOTG2XX_0_PA_LIMIT	0x92200FFF
++#define USB_FOTG2XX_0_PA_SIZE	0x00001000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	1
++#define LCD_FTLCDC200_PA_BASE	0x98700000
++#define LCD_FTLCDC200_PA_LIMIT	0x9870CFFF
++#define LCD_FTLCDC200_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	0x98700000
++#define LCD_FTLCDC200_0_PA_LIMIT	0x9870CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	0x0000D000
++
++/* MAC */
++#define MAC_FTMAC110_PA_COUNT	1
++#define MAC_FTMAC110_PA_BASE	0x92500000
++#define MAC_FTMAC110_PA_LIMIT	0x92500FFF
++#define MAC_FTMAC110_PA_SIZE	0x00001000
++#define MAC_FTMAC110_0_PA_BASE	0x92500000
++#define MAC_FTMAC110_0_PA_LIMIT	0x92500FFF
++#define MAC_FTMAC110_0_PA_SIZE	0x00001000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT	1
++#define TVE_FTTVE100_PA_BASE	0x92B00000
++#define TVE_FTTVE100_PA_LIMIT	0x92B00FFF
++#define TVE_FTTVE100_PA_SIZE	0x00001000
++#define TVE_FTTVE100_0_PA_BASE	0x92B00000
++#define TVE_FTTVE100_0_PA_LIMIT	0x92B00FFF
++#define TVE_FTTVE100_0_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0x92700000
++#define AES_FTAES020_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0x92700000
++#define AES_FTAES020_0_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* SCAL */
++#define SCAL_FTSCAL010_PA_COUNT	1
++#define SCAL_FTSCAL010_PA_BASE	0x92400000
++#define SCAL_FTSCAL010_PA_LIMIT	0x92400FFF
++#define SCAL_FTSCAL010_PA_SIZE	0x00001000
++#define SCAL_FTSCAL010_0_PA_BASE	0x92400000
++#define SCAL_FTSCAL010_0_PA_LIMIT	0x92400FFF
++#define SCAL_FTSCAL010_0_PA_SIZE	0x00001000
++
++/* CAP */
++#define CAP_FTCAP020_PA_COUNT	1
++#define CAP_FTCAP020_PA_BASE	0x90B00000
++#define CAP_FTCAP020_PA_LIMIT	0x90B00FFF
++#define CAP_FTCAP020_PA_SIZE	0x00001000
++#define CAP_FTCAP020_0_PA_BASE	0x90B00000
++#define CAP_FTCAP020_0_PA_LIMIT	0x90B00FFF
++#define CAP_FTCAP020_0_PA_SIZE	0x00001000
++#define CAP_FTCAP020_1_PA_BASE	0x90C00000
++#define CAP_FTCAP020_1_PA_LIMIT	0x90C00FFF
++#define CAP_FTCAP020_1_PA_SIZE	0x00001000
++
++/* DI3D */
++#define DI3D_FTDI3D_PA_COUNT	1
++#define DI3D_FTDI3D_PA_BASE	    0x91400000
++#define DI3D_FTDI3D_PA_LIMIT	0x91400FFF
++#define DI3D_FTDI3D_PA_SIZE	    0x00001000
++#define DI3D_FTDI3D_0_PA_BASE	0x91400000
++#define DI3D_FTDI3D_0_PA_LIMIT	0x91400FFF
++#define DI3D_FTDI3D_0_PA_SIZE	0x00001000
++
++/* H264E */
++#define H264E_FTMCP200_PA_COUNT	1
++#define H264E_FTMCP200_PA_BASE	0x94000000
++#define H264E_FTMCP200_PA_LIMIT	0x940FFFFF
++#define H264E_FTMCP200_PA_SIZE	0x00100000
++#define H264E_FTMCP200_0_PA_BASE	0x94000000
++#define H264E_FTMCP200_0_PA_LIMIT	0x940FFFFF
++#define H264E_FTMCP200_0_PA_SIZE	0x00100000
++
++/* WRAP */
++#define WRAP_FTWRAP00_PA_COUNT	1
++#define WRAP_FTWRAP00_PA_BASE	0x94100000
++#define WRAP_FTWRAP00_PA_LIMIT	0x94100FFF
++#define WRAP_FTWRAP00_PA_SIZE	0x00001000
++#define WRAP_FTWRAP00_0_PA_BASE	0x94100000
++#define WRAP_FTWRAP00_0_PA_LIMIT	0x94100FFF
++#define WRAP_FTWRAP00_0_PA_SIZE	0x00001000
++
++/* MCP100W */
++#define MCP100W_FTMCP100_PA_COUNT	1
++#define MCP100W_FTMCP100_PA_BASE	0x94200000
++#define MCP100W_FTMCP100_PA_LIMIT	0x94200FFF
++#define MCP100W_FTMCP100_PA_SIZE	0x00001000
++#define MCP100W_FTMCP100_0_PA_BASE	0x94200000
++#define MCP100W_FTMCP100_0_PA_LIMIT	0x94200FFF
++#define MCP100W_FTMCP100_0_PA_SIZE	0x00001000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0x94300000
++#define MCP_FTMCP100_PA_LIMIT	0x943FFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_0_PA_BASE	0x94300000
++#define MCP_FTMCP100_0_PA_LIMIT	0x943FFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++
++/* CT656 */
++#define CT656_FTCT656_PA_COUNT	1
++#define CT656_FTCT656_PA_BASE	0x92A00000
++#define CT656_FTCT656_PA_LIMIT	0x92A00FFF
++#define CT656_FTCT656_PA_SIZE	0x00001000
++#define CT656_FTCT656_0_PA_BASE	0x92A00000
++#define CT656_FTCT656_0_PA_LIMIT	0x92A00FFF
++#define CT656_FTCT656_0_PA_SIZE	0x00001000
++
++/* ISP_BME */
++#define ISP_BME_FTISPBME_PA_COUNT	1
++#define ISP_BME_FTISPBME_PA_BASE	0x92D00000
++#define ISP_BME_FTISPBME_PA_LIMIT	0x92DFFFFF
++#define ISP_BME_FTISPBME_PA_SIZE	0x00100000
++#define ISP_BME_FTISPBME_0_PA_BASE	0x92D00000
++#define ISP_BME_FTISPBME_0_PA_LIMIT	0x92DFFFFF
++#define ISP_BME_FTISPBME_0_PA_SIZE	0x00100000
++
++/* ISP210 */
++#define ISP210_FTISP210_PA_COUNT	1
++#define ISP210_FTISP210_PA_BASE	    0x92300000
++#define ISP210_FTISP210_PA_LIMIT	0x923FFFFF
++#define ISP210_FTISP210_PA_SIZE	    0x00100000
++#define ISP210_FTISP210_0_PA_BASE	0x92300000
++#define ISP210_FTISP210_0_PA_LIMIT	0x923FFFFF
++#define ISP210_FTISP210_0_PA_SIZE	0x00100000
++
++/* IR_DET */
++#define IR_DET_FTIRDET_PA_COUNT	1
++#define IR_DET_FTIRDET_PA_BASE	0x98C00000
++#define IR_DET_FTIRDET_PA_LIMIT	0x98C00FFF
++#define IR_DET_FTIRDET_PA_SIZE	0x00001000
++#define IR_DET_FTIRDET_0_PA_BASE	0x98C00000
++#define IR_DET_FTIRDET_0_PA_LIMIT	0x98C00FFF
++#define IR_DET_FTIRDET_0_PA_SIZE	0x00001000
++
++/* RTC */
++#define RTC_FTRTC_PA_COUNT	1
++#define RTC_FTRTC_PA_BASE	0x99900000
++#define RTC_FTRTC_PA_LIMIT	0x99900FFF
++#define RTC_FTRTC_PA_SIZE	0x00001000
++#define RTC_FTRTC_0_PA_BASE	0x99900000
++#define RTC_FTRTC_0_PA_LIMIT	0x99900FFF
++#define RTC_FTRTC_0_PA_SIZE	0x00001000
++
++/* ADC */
++#define ADC_WRAP_PA_COUNT	1
++#define ADC_WRAP_PA_BASE	0x98D00000
++#define ADC_WRAP_PA_LIMIT	0x98D00FFF
++#define ADC_WRAP_PA_SIZE	0x00001000
++#define ADC_WRAP_0_PA_BASE	0x98D00000
++#define ADC_WRAP_0_PA_LIMIT	0x98D00FFF
++#define ADC_WRAP_0_PA_SIZE	0x00001000
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_PA_COUNT 1
++#define DMAC_FTDMAC020_PA_BASE  0x92600000
++#define DMAC_FTDMAC020_PA_LIMIT 0x92600FFF
++#define DMAC_FTDMAC020_PA_SIZE  0x0001000
++
++/* APBBRG */
++#define APBBRG_FTAPBBRG020S_PA_COUNT	1
++#define APBBRG_FTAPBBRG020S_PA_BASE	0x92000000
++#define APBBRG_FTAPBBRG020S_PA_LIMIT	0x920FFFFF
++#define APBBRG_FTAPBBRG020S_PA_SIZE	0x00100000
++#define APBBRG_FTAPBBRG020S_0_PA_BASE	0x92000000
++#define APBBRG_FTAPBBRG020S_0_PA_LIMIT	0x920FFFFF
++#define APBBRG_FTAPBBRG020S_0_PA_SIZE	0x00100000
++
++/* DDRC */
++#define DDRC_FTDDRC010_PA_COUNT	1
++#define DDRC_FTDDRC010_PA_BASE	0x99300000
++#define DDRC_FTDDRC010_PA_LIMIT	0x99300FFF
++#define DDRC_FTDDRC010_PA_SIZE	0x00001000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	    0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	    0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	    0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	    0xFFFFFFFF
++
++#ifdef CONFIG_FTINTC010EX /* 2010/03/26: autospec doesn't support extended IRQ/FIQ, had reported it to CTD */
++#define PLATFORM_IRQ_TRIGGER_MODEEX2	0x00002000  // set IRQ45 as edge-triggered mode
++#define PLATFORM_IRQ_TRIGGER_LEVELEX2	0xFFFFDFFF  // set IRQ45 as rising-edge trigger
++#define PLATFORM_FIQ_TRIGGER_MODEEX2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVELEX2	0xFFFFFFFF
++#endif /* CONFIG_FTINTC010EX */
++ 
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/pmu.h b/arch/arm/mach-GM/include/mach/platform-GM8126/pmu.h
+new file mode 100644
+index 00000000..2c9e9e50
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/pmu.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++#define GM8126_TEST_CHIP_ID 0x812610
++#define GM8126_MP2_CHIP_ID  0x812620
++#define GM8128_MP_CHIP_ID   0x812621
++
++unsigned int pmu_get_apb_clk(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/serial.h b/arch/arm/mach-GM/include/mach/platform-GM8126/serial.h
+new file mode 100644
+index 00000000..3edaebb2
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/serial.h
+@@ -0,0 +1,75 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 4 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ *  Luke Lee  11/16/2005  Add conditional compilation.
++ */
++
++//#define UART_CLKSRC_OSCH
++
++#ifdef UART_CLKSRC_OSCH
++#define CONFIG_UART_CLK			12000000
++#else
++#define CONFIG_UART_CLK			(30000000/16)
++#endif
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#ifdef UART_FTUART010_1_VA_BASE
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++#else
++#define EXTENDED_UART_1
++#endif
++
++#ifdef UART_FTUART010_2_VA_BASE
++#define EXTENDED_UART_2 \
++     { 0, BASE_BAUD, UART_FTUART010_2_VA_BASE, UART_FTUART010_2_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS2 */
++#else
++#define EXTENDED_UART_2
++#endif
++
++#ifdef UART_FTUART010_3_VA_BASE
++#define EXTENDED_UART_3 \
++     { 0, BASE_BAUD, UART_FTUART010_3_VA_BASE, UART_FTUART010_3_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS3 */
++#else
++#define EXTENDED_UART_3
++#endif
++
++#ifdef UART_FTUART010_4_VA_BASE
++#define EXTENDED_UART_4 \
++     { 0, BASE_BAUD, UART_FTUART010_4_VA_BASE, UART_FTUART010_4_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS4 */
++#else
++#define EXTENDED_UART_4
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1            \
++        EXTENDED_UART_2            \
++        EXTENDED_UART_3            \
++        EXTENDED_UART_4
++
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/system.h b/arch/arm/mach-GM/include/mach/platform-GM8126/system.h
+new file mode 100644
+index 00000000..5bd61dca
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/system.h
+@@ -0,0 +1,77 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-a320/system.h
++ *  
++ *  Faraday Platform Dependent System Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/22/2005  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++extern inline void arch_reset(char mode, const char *cmd)
++{
++#define BIT15 (0x1<<15)
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++    pmuReg_t regRSTArray[] = {
++    	/* reg_off,bit_masks,lock_bits,init_val,init_mask */
++	{0x3C, BIT15, BIT15, 0, BIT15},
++    };
++    pmuRegInfo_t rst_clk_info = {
++    	"rst_clk",
++	ARRAY_SIZE(regRSTArray),
++	ATTR_TYPE_NONE,
++	regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<15)), (PMU_FTPMU010_VA_BASE + 0x3C));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C)); //reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));//load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08)); /*Magic number*/
++    writeb(0x03, (wdt_va_base + 0x0C)); /*Enable WDT */
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8126/vmalloc.h b/arch/arm/mach-GM/include/mach/platform-GM8126/vmalloc.h
+new file mode 100644
+index 00000000..70e3023c
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8126/vmalloc.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8126/vmalloc.h
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  10/06/2005  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/board.h b/arch/arm/mach-GM/include/mach/platform-GM8136/board.h
+new file mode 100644
+index 00000000..3936fd38
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/board.h
+@@ -0,0 +1,100 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/board.h
++ *
++ *  GM board Independent Specification
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ *  ChangeLog
++ *
++ *   Harry  2012/3/6 03:15 created.
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM8136 series"
++#define BOOT_PARAMETER_PA_OFFSET  0x100
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0x90C00000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE	0x90700000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        21
++
++#define UART_FTUART010_1_PA_BASE    0x90800000
++#define UART_FTUART010_1_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_1_VA_SIZE    SZ_4K
++#define UART_FTUART010_1_IRQ        22
++
++#define UART_FTUART010_2_PA_BASE    0x90900000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_1_VA_BASE + UART_FTUART010_1_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        25
++
++/* TIMER */
++#define TIMER_FTTMR010_PA_BASE	    0x90D00000
++#define TIMER_FTTMR010_VA_BASE	    (UART_FTUART010_2_VA_BASE + UART_FTUART010_2_VA_SIZE)
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         14
++#define TIMER_FTTMR010_IRQ1         14
++#define TIMER_FTTMR010_IRQ2         14
++
++/* INTC030 */
++#define INTC_FTINTC030_PA_BASE      0x96000000
++#define INTC_FTINTC030_VA_BASE      (TIMER_FTTMR010_VA_BASE + TIMER_FTTMR010_VA_SIZE)
++#define INTC_FTINTC030_VA_SIZE	    SZ_4K
++
++/* L2 Cache */
++//#define L2CACHE_FTL2CC031_PA_BASE   0xE4B00000
++//#define L2CACHE_FTL2CC031_VA_BASE   (INTC_FTINTC030_VA_BASE + INTC_FTINTC030_VA_SIZE)
++//#define L2CACHE_FTL2CC031_VA_SIZE   SZ_4K
++//#define L2CACHE_FTL2CC031_IRQ	    2
++	
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/dma_route.h b/arch/arm/mach-GM/include/mach/platform-GM8136/dma_route.h
+new file mode 100644
+index 00000000..4fbf887a
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/dma_route.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
++ *
++ * 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.
++ * 
++ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++#ifndef __DMA_ROUTE_H__
++#define __DMA_ROUTE_H__
++
++/* define AHB DMA routing table 
++ */
++#define AHBDMA_REQ_SSP0_RX  0
++#define AHBDMA_REQ_SSP0_TX  1
++#define AHBDMA_REQ_SSP1_RX  2
++#define AHBDMA_REQ_SSP1_TX  3
++#define AHBDMA_REQ_SSP2_RX  4
++#define AHBDMA_REQ_SSP2_TX  5
++#define AHBDMA_REQ_SDC      6
++#define AHBDMA_REQ_NANDC    9
++#define AHBDMA_REQ_PWMTMR5  12
++#define AHBDMA_REQ_PWMTMR6  13
++#define AHBDMA_REQ_PWMTMR7  14
++#define AHBDMA_REQ_PWMTMR8  15
++
++/* define APB DMA routing table 
++ */
++#define APBDMA_REQ_UART0_RX 1
++#define APBDMA_REQ_UART0_TX 2
++#define APBDMA_REQ_UART1_RX 3
++#define APBDMA_REQ_UART1_TX 4
++#define APBDMA_REQ_UART2_RX 5
++#define APBDMA_REQ_UART2_TX 6
++#define APBDMA_REQ_UART3_RX 7  
++#define APBDMA_REQ_UART3_TX 8
++#define APBDMA_REQ_UART4_RX 9  
++#define APBDMA_REQ_UART4_TX 10
++#define APBDMA_REQ_PWMTMR1  12
++#define APBDMA_REQ_PWMTMR2  13
++#define APBDMA_REQ_PWMTMR3  14
++#define APBDMA_REQ_PWMTMR4  15
++
++
++#endif /* __DMA_ROUTE_H__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/gpio.h b/arch/arm/mach-GM/include/mach/platform-GM8136/gpio.h
+new file mode 100644
+index 00000000..dbf443dd
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8136_GPIO_H__
++#define __GM8136_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		2
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8136_GPIO_H__
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/irqs.h b/arch/arm/mach-GM/include/mach/platform-GM8136/irqs.h
+new file mode 100644
+index 00000000..cfe1f144
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/irqs.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8129/irqs.h
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 10/06/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/memory.h b/arch/arm/mach-GM/include/mach/platform-GM8136/memory.h
+new file mode 100644
+index 00000000..db0904f7
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/memory.h
+@@ -0,0 +1,63 @@
++/*
++ *  linux/include/asm-armnommu/arch-GM/platform-GM8129/memory.h
++ *  
++ *  GM Platform Dependent Memory Configuration
++ *  
++ * 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
++ *  
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define PHYS_OFFSET     CPU_MEM_PA_BASE
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management. 
++ *
++ * Users can adjust the memory size based on the real memory size requirement.  
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     0x1000000
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement. 
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE. 
++ * The memory boundary is 16M alginment 
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/platform_io.h b/arch/arm/mach-GM/include/mach/platform-GM8136/platform_io.h
+new file mode 100644
+index 00000000..499fd694
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/platform_io.h
+@@ -0,0 +1,593 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8136/platform_io.h
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++
++#define PLATFORM_FIQ_BASE       0
++#define PLATFORM_IRQ_TOTALCOUNT	64/* interrupt controller supports 96 interrupts */
++#define PLATFORM_INTERRUPTS     PLATFORM_IRQ_TOTALCOUNT
++#define CPU_MEM_PA_BASE         0x0     /* the memory physical start address(DDR) */
++
++/*
++ * Component counts
++ */
++
++/* PWMTMR */
++#define PWMTMR_COUNT	1
++#define PWMTMR_FTPWM010_COUNT	1
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	2
++#define GPIO_FTGPIO010_COUNT	2
++/* I2C */
++#define I2C_COUNT	1
++#define I2C_FTI2C010_COUNT	1
++/* SSP */
++#define SSP_COUNT	2
++#define SSP_FTSSP010_COUNT	2
++/* SPI020 */
++#define SPI_COUNT	1
++#define SPI_FTSPI020_COUNT	1
++/* SDC */
++#define SDC_COUNT	2
++#define SDC_FTSDC021_COUNT	2
++/* USB */
++#define USB_COUNT       2
++#define USB_FOTG2XX_COUNT       2
++/* LCD */
++#define LCD_COUNT	1
++#define LCD_FTLCDC200_COUNT	1
++/* MAC */
++#define MAC_COUNT	1
++#define MAC_FTGMAC100_COUNT	1
++/* TVE */
++#define TVE_COUNT	1
++#define TVE_FTTVE100_COUNT	1
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* SCAL */
++#define SCAL_COUNT	1
++#define SCAL_FTSCAL300_COUNT	1
++/* CAP */
++#define CAP_COUNT	1
++#define CAP_FTCAP300_COUNT	1
++/* DI3D */
++#define DI3D_COUNT	1
++#define DI3D_FTDI3D_COUNT	1
++/* H264E */
++#define H264E_COUNT	1
++#define H264E_FTMCP280_COUNT	1
++/* MCP */
++#define MCP_COUNT	1
++#define MCP_FTMCP100_COUNT	1
++/* ISP */
++#define ISP_COUNT	1
++#define ISP_FTISP328_COUNT	1
++
++/* THDNR */
++#define THDNR_COUNT	1
++#define THDNR_FT3DNR_COUNT	1
++
++/* IR_DET */
++#define IR_DET_COUNT	1
++#define IR_DET_FTIRDET_COUNT	1
++
++/* RTC */
++#define RTC_COUNT	1
++#define RTC_FTRTC_COUNT	1
++
++/* ADC */
++#define ADC_COUNT	1
++#define ADC_WRAP_COUNT	1
++
++/* ADDA */
++#define ADDA_COUNT	1
++#define ADDA_WRAP_COUNT	1
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_COUNT 1
++
++/* APBBRG */
++#define APBBRG_COUNT	1
++#define APBBRG_FTAPBBRG020S_COUNT	1
++
++/* DDRC */
++#define DDRC_COUNT	1
++#define DDRC_FTDDRC010_COUNT	1
++/*
++ * Interrrupt numbers
++ */
++/* PWMTMR */
++#define PWMTMR_FTPWM010_IRQ_COUNT	1
++#define PWMTMR_FTPWM010_IRQ0	49
++#define PWMTMR_FTPWM010_0_IRQ0	49
++
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	16
++#define WDT_FTWDT010_0_IRQ	16
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	1
++#define GPIO_FTGPIO010_IRQ	13
++#define GPIO_FTGPIO010_0_IRQ	13
++#define GPIO_FTGPIO010_1_IRQ	63
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	18
++#define I2C_FTI2C010_0_IRQ	18
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	6
++#define SSP_FTSSP010_0_IRQ	6
++#define SSP_FTSSP010_1_IRQ	11
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	54
++#define SPI_FTSPI020_0_IRQ	54
++
++/* SDC */
++#define SDC_FTSDC021_IRQ_COUNT	1
++#define SDC_FTSDC021_IRQ	15
++#define SDC_FTSDC021_0_IRQ	15
++#define SDC_FTSDC021_1_IRQ	17
++
++/* USB */
++#define USB_FOTG2XX_IRQ_COUNT	1
++#define USB_FOTG2XX_IRQ		9
++#define USB_FOTG2XX_0_IRQ	9
++#define USB_FOTG2XX_1_IRQ	10
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	24
++#define LCD_FTLCDC200_0_IRQ	24
++
++/* MAC */
++#define MAC_FTGMAC100_IRQ_COUNT	1
++#define MAC_FTGMAC100_IRQ	3
++#define MAC_FTGMAC100_0_IRQ	3
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	19
++#define AES_FTAES020_0_IRQ	19
++
++/* SCAL */
++#define SCAL_FTSCAL300_IRQ_COUNT    1
++#define SCAL_FTSCAL300_IRQ  12
++#define SCAL_FTSCAL300_0_IRQ    12
++
++/* CAP */
++#define CAP_FTCAP300_IRQ_COUNT	1
++#define CAP_FTCAP300_IRQ	32
++#define CAP_FTCAP300_0_IRQ	32
++
++/* DI3D */
++#define DI3D_FTDI3D_IRQ_COUNT	1
++#define DI3D_FTDI3D_IRQ	41
++#define DI3D_FTDI3D_0_IRQ	41
++
++/* H264E */
++#define H264E_FTMCP280_IRQ_COUNT	1
++#define H264E_FTMCP280_IRQ	29
++#define H264E_FTMCP280_0_IRQ	29
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	1
++#define MCP_FTMCP100_IRQ	31
++#define MCP_FTMCP100_0_IRQ	31
++
++/* ISP */
++#define ISP_FTISP328_IRQ_COUNT	1
++#define ISP_FTISP328_IRQ0	43
++#define ISP_FTISP328_0_IRQ0	43
++
++/* MIPI */
++#define MIPI_FTCSIRX100_IRQ_COUNT	1
++#define MIPI_FTCSIRX100_IRQ0	52
++#define MIPI_FTCSIRX100_0_IRQ0	52
++
++/* LVDS */
++#define LVDS_FTLVDS_IRQ_COUNT	1
++#define LVDS_FTLVDS_IRQ0	46
++#define LVDS_FTLVDS_0_IRQ0	46
++
++/* THDNR */
++#define THDNR_FT3DNR_IRQ_COUNT 1
++#define THDNR_FT3DNR_IRQ 42
++#define THDNR_FT3DNR_0_IRQ 42
++
++/* IR_DET */
++#define IR_DET_FTIRDET_IRQ_COUNT	1
++#define IR_DET_FTIRDET_IRQ	48
++#define IR_DET_FTIRDET_0_IRQ	48
++
++/* RTC */
++#define RTC_FTRTC_IRQ_COUNT     2
++#define RTC_FTRTC_IRQ           50
++#define RTC_FTRTC_0_IRQ         50      ///< RTC_INT
++#define RTC_FTRTC_0_ALM_IRQ     51      ///< RTC_ALARM
++
++/* ADC */
++#define ADC_WRAP_IRQ_COUNT	1
++#define ADC_WRAP_IRQ	35
++#define ADC_WRAP_0_IRQ	35
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_IRQ_COUNT    1
++#define DMAC_FTDMAC020_IRQ  1
++#define DMAC_FTDMAC020_0_IRQ		1
++
++/* APBBRG */
++#define APBBRG_FTAPBBRG020S_IRQ_COUNT	1
++#define APBBRG_FTAPBBRG020S_IRQ		2
++
++/*Think2d*/
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_IRQ_COUNT	1
++#define GRA_FT2DGRA_IRQ	4
++#define GRA_FT2DGRA_0_IRQ	4
++
++/* pMonitor */
++#define PMONITOR_IRQ_COUNT	1
++#define PMONITOR_IRQ		44
++#define PMONITOR_0_IRQ		44
++
++/*
++ * Base addresses
++ */
++
++/* PWMTMR */
++#define PWMTMR_FTPWM010_PA_COUNT	1
++#define PWMTMR_FTPWM010_PA_BASE	    0x91B00000
++#define PWMTMR_FTPWM010_PA_LIMIT	0x91B0FFFF
++#define PWMTMR_FTPWM010_PA_SIZE	    0x00010000
++#define PWMTMR_FTPWM010_0_PA_BASE	0x91B00000
++#define PWMTMR_FTPWM010_0_PA_LIMIT	0x91B0FFFF
++#define PWMTMR_FTPWM010_0_PA_SIZE	0x00010000
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x90E00000
++#define WDT_FTWDT010_PA_LIMIT	0x90E00FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x90E00000
++#define WDT_FTWDT010_0_PA_LIMIT	0x90E00FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	1
++#define GPIO_FTGPIO010_PA_BASE	0x91000000
++#define GPIO_FTGPIO010_PA_LIMIT	0x91000FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0x91000000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0x91000FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0x91900000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0x91900FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0x91200000
++#define I2C_FTI2C010_PA_LIMIT	0x91200FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0x91200000
++#define I2C_FTI2C010_0_PA_LIMIT	0x91200FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0x91300000
++#define SSP_FTSSP010_PA_LIMIT	0x91300FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0x91300000
++#define SSP_FTSSP010_0_PA_LIMIT	0x91300FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0x91400000
++#define SSP_FTSSP010_1_PA_LIMIT	0x91400FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++
++/* SPI */
++#define SPI_FTSPI020_PA_COUNT	1
++#define SPI_FTSPI020_PA_BASE	0x92300000
++#define SPI_FTSPI020_PA_LIMIT	0x92300FFF
++#define SPI_FTSPI020_PA_SIZE	0x00001000
++#define SPI_FTSPI020_0_PA_BASE	0x92300000
++#define SPI_FTSPI020_0_PA_LIMIT	0x92300FFF
++#define SPI_FTSPI020_0_PA_SIZE	0x00001000
++
++/* SDC */
++#define SDC_FTSDC021_PA_COUNT	1
++#define SDC_FTSDC021_PA_BASE	0x92800000
++#define SDC_FTSDC021_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_PA_SIZE	0x00001000
++#define SDC_FTSDC021_0_PA_BASE	0x92800000
++#define SDC_FTSDC021_0_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_0_PA_SIZE	0x00001000
++#define SDC_FTSDC021_1_PA_BASE	0x93800000
++#define SDC_FTSDC021_1_PA_LIMIT	0x93800FFF
++#define SDC_FTSDC021_1_PA_SIZE	0x00001000
++
++/* USB */
++#define USB_FOTG2XX_PA_COUNT	1
++#define USB_FOTG2XX_PA_BASE	0x93000000
++#define USB_FOTG2XX_PA_LIMIT	0x93000FFF
++#define USB_FOTG2XX_PA_SIZE	0x00001000
++#define USB_FOTG2XX_0_PA_BASE	0x93000000
++#define USB_FOTG2XX_0_PA_LIMIT	0x93000FFF
++#define USB_FOTG2XX_0_PA_SIZE	0x00001000
++#define USB_FOTG2XX_1_PA_BASE	0x93700000
++#define USB_FOTG2XX_1_PA_LIMIT	0x93700FFF
++#define USB_FOTG2XX_1_PA_SIZE	0x00001000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	1
++#define LCD_FTLCDC200_PA_BASE	0x9BF00000
++#define LCD_FTLCDC200_PA_LIMIT	0x9BF0CFFF
++#define LCD_FTLCDC200_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	0x9BF00000
++#define LCD_FTLCDC200_0_PA_LIMIT	0x9BF0CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	0x0000D000
++
++/* MAC */
++#define MAC_FTGMAC100_PA_COUNT	1
++#define MAC_FTGMAC100_PA_BASE	0x92500000
++#define MAC_FTGMAC100_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_0_PA_BASE	0x92500000
++#define MAC_FTGMAC100_0_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_0_PA_SIZE	0x00001000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT	1
++#define TVE_FTTVE100_PA_BASE	0x93500000
++#define TVE_FTTVE100_PA_LIMIT	0x93500FFF
++#define TVE_FTTVE100_PA_SIZE	0x00001000
++#define TVE_FTTVE100_0_PA_BASE	0x93500000
++#define TVE_FTTVE100_0_PA_LIMIT	0x93500FFF
++#define TVE_FTTVE100_0_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0x92700000
++#define AES_FTAES020_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0x92700000
++#define AES_FTAES020_0_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* SCAL */
++#define SCAL_FTSCAL300_PA_COUNT 1
++#define SCAL_FTSCAL300_PA_BASE  0x96200000
++#define SCAL_FTSCAL300_PA_LIMIT 0x96247FFF
++#define SCAL_FTSCAL300_PA_SIZE  0x00048000
++#define SCAL_FTSCAL300_0_PA_BASE    0x96200000
++#define SCAL_FTSCAL300_0_PA_LIMIT   0x96247FFF
++#define SCAL_FTSCAL300_0_PA_SIZE    0x00048000
++
++/* CAP */
++#define CAP_FTCAP300_PA_COUNT	1
++#define CAP_FTCAP300_PA_BASE	0x96100000
++#define CAP_FTCAP300_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_PA_SIZE	0x00001000
++#define CAP_FTCAP300_0_PA_BASE	0x96100000
++#define CAP_FTCAP300_0_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_0_PA_SIZE	0x00001000
++
++/* DI3D */
++#define DI3D_FTDI3D_PA_COUNT	1
++#define DI3D_FTDI3D_PA_BASE	    0x9B000000
++#define DI3D_FTDI3D_PA_LIMIT	0x9B000FFF
++#define DI3D_FTDI3D_PA_SIZE	    0x00001000
++#define DI3D_FTDI3D_0_PA_BASE	0x9B000000
++#define DI3D_FTDI3D_0_PA_LIMIT	0x9B000FFF
++#define DI3D_FTDI3D_0_PA_SIZE	0x00001000
++
++/* H264E */
++#define H264E_FTMCP280_PA_COUNT	1
++#define H264E_FTMCP280_PA_BASE	0x92C00000
++#define H264E_FTMCP280_PA_LIMIT	0x92C00FFF
++#define H264E_FTMCP280_PA_SIZE	0x00001000
++#define H264E_FTMCP280_0_PA_BASE	0x92C00000
++#define H264E_FTMCP280_0_PA_LIMIT	0x92C00FFF
++#define H264E_FTMCP280_0_PA_SIZE	0x00001000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0x92000000
++#define MCP_FTMCP100_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_0_PA_BASE	0x92000000
++#define MCP_FTMCP100_0_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++
++/* ISP */
++#define ISP_FTISP328_PA_COUNT	1
++#define ISP_FTISP328_PA_BASE	0x93930000
++#define ISP_FTISP328_PA_LIMIT	0x93932FFF
++#define ISP_FTISP328_PA_SIZE	0x00003000
++#define ISP_FTISP328_0_PA_BASE	0x93930000
++#define ISP_FTISP328_0_PA_LIMIT	0x93932FFF
++#define ISP_FTISP328_0_PA_SIZE	0x00003000
++
++/* MIPI */
++#define MIPI_FTCSIRX100_PA_COUNT	1
++#define MIPI_FTCSIRX100_PA_BASE		0x9ba00000
++#define MIPI_FTCSIRX100_PA_LIMIT	0x9ba00FFF
++#define MIPI_FTCSIRX100_PA_SIZE		0x00001000
++#define MIPI_FTCSIRX100_0_PA_BASE	0x9ba00000
++#define MIPI_FTCSIRX100_0_PA_LIMIT	0x9ba00FFF
++#define MIPI_FTCSIRX100_0_PA_SIZE	0x00001000
++
++/* LVDS */
++#define LVDS_FTLVDS_PA_COUNT	1
++#define LVDS_FTLVDS_PA_BASE		0x9bc00000
++#define LVDS_FTLVDS_PA_LIMIT	0x9bc00FFF
++#define LVDS_FTLVDS_PA_SIZE		0x00001000
++#define LVDS_FTLVDS_0_PA_BASE	0x9bc00000
++#define LVDS_FTLVDS_0_PA_LIMIT	0x9bc00FFF
++#define LVDS_FTLVDS_0_PA_SIZE	0x00001000
++
++/* THDNR */
++#define THDNR_FT3DNR_PA_COUNT   1
++#define THDNR_FT3DNR_PA_BASE    0x9b700000
++#define THDNR_FT3DNR_PA_LIMIT   0x9b7007FF
++#define THDNR_FT3DNR_PA_SIZE    0x00000800
++#define THDNR_FT3DNR_0_PA_BASE  0x9b700000
++#define THDNR_FT3DNR_0_PA_LIMIT 0x9b7007FF
++#define THDNR_FT3DNR_0_PA_SIZE  0x00000800
++
++/* IR_DET */
++#define IR_DET_FTIRDET_PA_COUNT	1
++#define IR_DET_FTIRDET_PA_BASE	0x91600000
++#define IR_DET_FTIRDET_PA_LIMIT	0x91600FFF
++#define IR_DET_FTIRDET_PA_SIZE	0x00001000
++#define IR_DET_FTIRDET_0_PA_BASE	0x91600000
++#define IR_DET_FTIRDET_0_PA_LIMIT	0x91600FFF
++#define IR_DET_FTIRDET_0_PA_SIZE	0x00001000
++
++/* RTC */
++#define RTC_FTRTC_PA_COUNT      1
++#define RTC_FTRTC_PA_BASE       0x91C00000
++#define RTC_FTRTC_PA_LIMIT      0x91C00FFF
++#define RTC_FTRTC_PA_SIZE       0x00001000
++#define RTC_FTRTC_0_PA_BASE     0x91C00000
++#define RTC_FTRTC_0_PA_LIMIT    0x91C00FFF
++#define RTC_FTRTC_0_PA_SIZE     0x00001000
++
++/* ADC */
++#define ADC_WRAP_PA_COUNT	1
++#define ADC_WRAP_PA_BASE	0x90A00000
++#define ADC_WRAP_PA_LIMIT	0x90A00FFF
++#define ADC_WRAP_PA_SIZE	0x00001000
++#define ADC_WRAP_0_PA_BASE	0x90A00000
++#define ADC_WRAP_0_PA_LIMIT	0x90A00FFF
++#define ADC_WRAP_0_PA_SIZE	0x00001000
++
++/* ADDA */
++#define ADDA_WRAP_PA_COUNT	1
++#define ADDA_WRAP_PA_BASE	0x90B00000
++#define ADDA_WRAP_PA_LIMIT	0x90B00FFF
++#define ADDA_WRAP_PA_SIZE	0x00001000
++#define ADDA_WRAP_0_PA_BASE	0x90B00000
++#define ADDA_WRAP_0_PA_LIMIT	0x90B00FFF
++#define ADDA_WRAP_0_PA_SIZE	0x00001000
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_PA_COUNT 1
++#define DMAC_FTDMAC020_PA_BASE  0x92600000
++#define DMAC_FTDMAC020_PA_LIMIT 0x92600FFF
++#define DMAC_FTDMAC020_PA_SIZE  0x0001000
++#define DMAC_FTDMAC020_0_PA_BASE	0x92600000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0x92600FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++
++/* DDRC */
++#define DDRC_FTDDRC010_PA_COUNT	1
++#define DDRC_FTDDRC010_PA_BASE	0x9A100000
++#define DDRC_FTDDRC010_PA_LIMIT	0x9A100FFF
++#define DDRC_FTDDRC010_PA_SIZE	0x00001000
++
++/*THINK 2D*/
++#define GRA_FT2DGRA_PA_BASE     0x92200000
++#define GRA_FT2DGRA_PA_LIMIT    0x92200FFF
++#define GRA_FT2DGRA_PA_SIZE     0x00001000
++
++/* GPENC */
++#define GRAPHIC_ENC_PA_BASE     0x9B200000
++#define GRAPHIC_ENC_PA_LIMIT    0x9B200FFF
++#define GRAPHIC_ENC_PA_SIZE     0x00001000
++
++/* GPDEC */
++#define GRAPHIC_DEC_PA_BASE     0x9B300000
++#define GRAPHIC_DEC_PA_LIMIT    0x9B300FFF
++#define GRAPHIC_DEC_PA_SIZE     0x00001000
++#define GRAPHIC_DEC_0_PA_BASE   0x9B300000
++#define GRAPHIC_DEC_0_PA_LIMIT  0x9B300FFF
++#define GRAPHIC_DEC_0_PA_SIZE   0x00001000
++
++/* pMonitor */
++#define PMONITOR_PA_BASE	0x91D00000
++#define PMONITOR_PA_LIMIT	0x91D00FFF
++#define PMONITOR_PA_SIZE	0x00001000
++#define PMONITOR_0_PA_BASE	0x91D00000
++#define PMONITOR_0_PA_LIMIT	0x91D00FFF
++#define PMONITOR_0_PA_SIZE	0x00001000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++#define PLATFORM_IRQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL1	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL1	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL3	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL3	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL4	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL4	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL5	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL5	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL6	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL6	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL7	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL7	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL8	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL8	0xFFFFFFFF
++
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/pmu.h b/arch/arm/mach-GM/include/mach/platform-GM8136/pmu.h
+new file mode 100644
+index 00000000..00e0588a
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/pmu.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++
++
++unsigned int pmu_get_apb_clk(void);
++int platform_check_flash_type(void);
++int platform_spi_four_byte_mode(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/serial.h b/arch/arm/mach-GM/include/mach/platform-GM8136/serial.h
+new file mode 100644
+index 00000000..14ca651f
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/serial.h
+@@ -0,0 +1,96 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 4 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ *  Luke Lee  11/16/2005  Add conditional compilation.
++ */
++
++#ifdef CONFIG_FPGA
++#define CONFIG_UART_CLK			12000000
++#else
++#define CONFIG_UART_CLK			25000000
++#endif
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#ifdef CONFIG_SERIAL_UART1_IP
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++#else
++#define EXTENDED_UART_1 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART2_IP
++#define EXTENDED_UART_2 \
++     { 0, BASE_BAUD, UART_FTUART010_2_VA_BASE, UART_FTUART010_2_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS2 */
++#else
++#define EXTENDED_UART_2 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1            \
++        EXTENDED_UART_2
++
++/* set uart clock source select to PLL2 divider output / 2 and clock divided value */
++static inline void ft_set_uartclk(void)
++{
++    unsigned int val, pval;
++
++#if 0
++    /* default is already set to pll2out_div2 */
++    val = inl(PMU_FTPMU010_VA_BASE + 0x28);
++    val &= ~(1 << 3);
++    outl(val, PMU_FTPMU010_VA_BASE + 0x28);
++#endif
++    pval = 0;
++    val = inl(PMU_FTPMU010_VA_BASE + 0x70);
++    val = (val & ~(0x3F << 16)) | (pval << 16);
++    outl(val, PMU_FTPMU010_VA_BASE + 0x70);
++}
++
++#define OSCH_FREQ   30000000
++
++/* get UCLK at run time, CONFIG_UART_CLK is omitted */
++static inline unsigned int ft_get_uartclk(void)
++{
++    unsigned int pval, mul, div;
++    static int set_done = 0;
++
++    if (set_done == 0) {
++        ft_set_uartclk();
++        set_done = 1;
++    }
++
++    pval = (inl(PMU_FTPMU010_VA_BASE + 0x70) >> 16) & 0x3F;
++
++    /* uart clock source = PLL2 divider output / 2 */
++    mul = (inl(PMU_FTPMU010_VA_BASE + 0x34) >> 4) & 0x7F;
++    div = (inl(PMU_FTPMU010_VA_BASE + 0x34) >> 11) & 0x1F;
++
++    return (OSCH_FREQ / div * mul) / 2 / (pval + 1);
++}
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/system.h b/arch/arm/mach-GM/include/mach/platform-GM8136/system.h
+new file mode 100644
+index 00000000..e15380d5
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/system.h
+@@ -0,0 +1,78 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8129/system.h
++ *
++ *  Faraday Platform Dependent System Definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/22/2005  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++static inline void arch_reset(char mode, const char *cmd)
++{
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++
++    pmuReg_t regRSTArray[] = {
++        /* reg_off, bit_masks, lock_bits,init_val, init_mask */
++        {0xB8, (1<< 10), (1<< 10), 0, (1<< 10)},
++    };
++
++    pmuRegInfo_t rst_clk_info = {
++        "rst_clk",
++        ARRAY_SIZE(regRSTArray),
++        ATTR_TYPE_NONE,
++        regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<15)), (PMU_FTPMU010_VA_BASE + 0x3C));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C));        // reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));        // load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08));   // Magic number
++    writeb(0x03, (wdt_va_base + 0x0C));     // Enable WDT
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8136/vmalloc.h b/arch/arm/mach-GM/include/mach/platform-GM8136/vmalloc.h
+new file mode 100644
+index 00000000..320deb0c
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8136/vmalloc.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8129/vmalloc.h
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  10/06/2005  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/board.h b/arch/arm/mach-GM/include/mach/platform-GM8139/board.h
+new file mode 100644
+index 00000000..0706bef5
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/board.h
+@@ -0,0 +1,100 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/board.h
++ *
++ *  GM board Independent Specification
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ *  ChangeLog
++ *
++ *   Harry  2012/3/6 03:15 created.
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM813x series"
++#define BOOT_PARAMETER_PA_OFFSET  0x100
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0x90C00000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE	0x90700000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        21
++
++#define UART_FTUART010_1_PA_BASE    0x90800000
++#define UART_FTUART010_1_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_1_VA_SIZE    SZ_4K
++#define UART_FTUART010_1_IRQ        22
++
++#define UART_FTUART010_2_PA_BASE    0x90900000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_1_VA_BASE + UART_FTUART010_1_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        25
++
++/* TIMER */
++#define TIMER_FTTMR010_PA_BASE	    0x90D00000
++#define TIMER_FTTMR010_VA_BASE	    (UART_FTUART010_2_VA_BASE + UART_FTUART010_2_VA_SIZE)
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         14
++#define TIMER_FTTMR010_IRQ1         14
++#define TIMER_FTTMR010_IRQ2         14
++
++/* INTC030 */
++#define INTC_FTINTC030_PA_BASE      0x96000000
++#define INTC_FTINTC030_VA_BASE      (TIMER_FTTMR010_VA_BASE + TIMER_FTTMR010_VA_SIZE)
++#define INTC_FTINTC030_VA_SIZE	    SZ_4K
++
++/* L2 Cache */
++#define L2CACHE_FTL2CC031_PA_BASE   0xE4B00000
++#define L2CACHE_FTL2CC031_VA_BASE   (INTC_FTINTC030_VA_BASE + INTC_FTINTC030_VA_SIZE)
++#define L2CACHE_FTL2CC031_VA_SIZE   SZ_4K
++#define L2CACHE_FTL2CC031_IRQ	    2
++	
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/dma_route.h b/arch/arm/mach-GM/include/mach/platform-GM8139/dma_route.h
+new file mode 100644
+index 00000000..4fbf887a
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/dma_route.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
++ *
++ * 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.
++ * 
++ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++#ifndef __DMA_ROUTE_H__
++#define __DMA_ROUTE_H__
++
++/* define AHB DMA routing table 
++ */
++#define AHBDMA_REQ_SSP0_RX  0
++#define AHBDMA_REQ_SSP0_TX  1
++#define AHBDMA_REQ_SSP1_RX  2
++#define AHBDMA_REQ_SSP1_TX  3
++#define AHBDMA_REQ_SSP2_RX  4
++#define AHBDMA_REQ_SSP2_TX  5
++#define AHBDMA_REQ_SDC      6
++#define AHBDMA_REQ_NANDC    9
++#define AHBDMA_REQ_PWMTMR5  12
++#define AHBDMA_REQ_PWMTMR6  13
++#define AHBDMA_REQ_PWMTMR7  14
++#define AHBDMA_REQ_PWMTMR8  15
++
++/* define APB DMA routing table 
++ */
++#define APBDMA_REQ_UART0_RX 1
++#define APBDMA_REQ_UART0_TX 2
++#define APBDMA_REQ_UART1_RX 3
++#define APBDMA_REQ_UART1_TX 4
++#define APBDMA_REQ_UART2_RX 5
++#define APBDMA_REQ_UART2_TX 6
++#define APBDMA_REQ_UART3_RX 7  
++#define APBDMA_REQ_UART3_TX 8
++#define APBDMA_REQ_UART4_RX 9  
++#define APBDMA_REQ_UART4_TX 10
++#define APBDMA_REQ_PWMTMR1  12
++#define APBDMA_REQ_PWMTMR2  13
++#define APBDMA_REQ_PWMTMR3  14
++#define APBDMA_REQ_PWMTMR4  15
++
++
++#endif /* __DMA_ROUTE_H__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/gpio.h b/arch/arm/mach-GM/include/mach/platform-GM8139/gpio.h
+new file mode 100644
+index 00000000..051044e0
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8139_GPIO_H__
++#define __GM8139_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		2
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8139_GPIO_H__
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/irqs.h b/arch/arm/mach-GM/include/mach/platform-GM8139/irqs.h
+new file mode 100644
+index 00000000..cfe1f144
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/irqs.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8129/irqs.h
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 10/06/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/memory.h b/arch/arm/mach-GM/include/mach/platform-GM8139/memory.h
+new file mode 100644
+index 00000000..db0904f7
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/memory.h
+@@ -0,0 +1,63 @@
++/*
++ *  linux/include/asm-armnommu/arch-GM/platform-GM8129/memory.h
++ *  
++ *  GM Platform Dependent Memory Configuration
++ *  
++ * 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
++ *  
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define PHYS_OFFSET     CPU_MEM_PA_BASE
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management. 
++ *
++ * Users can adjust the memory size based on the real memory size requirement.  
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     0x1000000
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement. 
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE. 
++ * The memory boundary is 16M alginment 
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/platform_io.h b/arch/arm/mach-GM/include/mach/platform-GM8139/platform_io.h
+new file mode 100644
+index 00000000..929d727b
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/platform_io.h
+@@ -0,0 +1,644 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8129/platform_io.h
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++
++#define PLATFORM_FIQ_BASE       0
++#define PLATFORM_IRQ_TOTALCOUNT	64/* interrupt controller supports 96 interrupts */
++#define PLATFORM_INTERRUPTS     PLATFORM_IRQ_TOTALCOUNT
++#define CPU_MEM_PA_BASE         0x0     /* the memory physical start address(DDR) */
++
++/*
++ * Component counts
++ */
++
++/* PWMTMR */
++#define PWMTMR_COUNT	1
++#define PWMTMR_FTPWM010_COUNT	1
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	2
++#define GPIO_FTGPIO010_COUNT	2
++/* I2C */
++#define I2C_COUNT	1
++#define I2C_FTI2C010_COUNT	1
++/* SSP */
++#define SSP_COUNT	2
++#define SSP_FTSSP010_COUNT	2
++/* SPI020 */
++#define SPI_COUNT	1
++#define SPI_FTSPI020_COUNT	1
++/* SDC */
++#define SDC_COUNT	1
++#define SDC_FTSDC021_COUNT	1
++/* NAND */
++#define NAND_COUNT	1
++#define NAND_FTNAND024_COUNT	1
++/* NANDDP */
++#define NANDDP_COUNT	1
++#define NANDDP_FTNAND024_COUNT	1
++/* USB */
++#define USB_COUNT       1
++#define USB_FOTG2XX_COUNT       1
++/* LCD */
++#define LCD_COUNT	1
++#define LCD_FTLCDC200_COUNT	1
++/* MAC */
++#define MAC_COUNT	1
++#define MAC_FTGMAC100_COUNT	1
++/* TVE */
++#define TVE_COUNT	1
++#define TVE_FTTVE100_COUNT	1
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* SCAL */
++#define SCAL_COUNT	1
++#define SCAL_FTSCAL300_COUNT	1
++/* CAP */
++#define CAP_COUNT	1
++#define CAP_FTCAP300_COUNT	1
++/* DI3D */
++#define DI3D_COUNT	1
++#define DI3D_FTDI3D_COUNT	1
++/* H264E */
++#define H264E_COUNT	1
++#define H264E_FTMCP280_COUNT	1
++/* MCP */
++#define MCP_COUNT	1
++#define MCP_FTMCP100_COUNT	1
++/* CT656 */
++#define CT656_COUNT	1
++#define CT656_FTCT656_COUNT	1
++/* ISP320 */
++#define ISP320_COUNT	1
++#define ISP320_FTISP320_COUNT	1
++
++/* THDNR */
++#define THDNR_COUNT	1
++#define THDNR_FT3DNR_COUNT	1
++
++/* IR_DET */
++#define IR_DET_COUNT	1
++#define IR_DET_FTIRDET_COUNT	1
++
++/* RTC */
++#define RTC_COUNT	1
++#define RTC_FTRTC_COUNT	1
++
++/* ADC */
++#define ADC_COUNT	1
++#define ADC_WRAP_COUNT	1
++
++/* ADDA */
++#define ADDA_COUNT	1
++#define ADDA_WRAP_COUNT	1
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_COUNT 1
++
++/* APBBRG */
++#define APBBRG_COUNT	1
++#define APBBRG_FTAPBBRG020S_COUNT	1
++
++/* DDRC */
++#define DDRC_COUNT	1
++#define DDRC_FTDDRC010_COUNT	1
++/*
++ * Interrrupt numbers
++ */
++/* PWMTMR */
++#define PWMTMR_FTPWM010_IRQ_COUNT	1
++#define PWMTMR_FTPWM010_IRQ0	49
++#define PWMTMR_FTPWM010_0_IRQ0	49
++
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	16
++#define WDT_FTWDT010_0_IRQ	16
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	1
++#define GPIO_FTGPIO010_IRQ	13
++#define GPIO_FTGPIO010_0_IRQ	13
++#define GPIO_FTGPIO010_1_IRQ	63
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	18
++#define I2C_FTI2C010_0_IRQ	18
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	6
++#define SSP_FTSSP010_0_IRQ	6
++#define SSP_FTSSP010_1_IRQ	11
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	54
++#define SPI_FTSPI020_0_IRQ	54
++
++/* SDC */
++#define SDC_FTSDC021_IRQ_COUNT	1
++#define SDC_FTSDC021_IRQ	15
++#define SDC_FTSDC021_0_IRQ	15
++
++/* NAND */
++#define NAND_FTNAND024_IRQ_COUNT	1
++#define NAND_FTNAND024_IRQ	23
++#define NAND_FTNAND024_0_IRQ	23
++
++/* USB */
++#define USB_FOTG2XX_IRQ_COUNT	1
++#define USB_FOTG2XX_IRQ		9
++#define USB_FOTG2XX_0_IRQ	9
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	24
++#define LCD_FTLCDC200_0_IRQ	24
++
++/* MAC */
++#define MAC_FTGMAC100_IRQ_COUNT	1
++#define MAC_FTGMAC100_IRQ	3
++#define MAC_FTGMAC100_0_IRQ	3
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	19
++#define AES_FTAES020_0_IRQ	19
++
++/* SCAL */
++#define SCAL_FTSCAL300_IRQ_COUNT    1
++#define SCAL_FTSCAL300_IRQ  12
++#define SCAL_FTSCAL300_0_IRQ    12
++
++/* CAP */
++#define CAP_FTCAP300_IRQ_COUNT	1
++#define CAP_FTCAP300_IRQ	32
++#define CAP_FTCAP300_0_IRQ	32
++
++/* DI3D */
++#define DI3D_FTDI3D_IRQ_COUNT	1
++#define DI3D_FTDI3D_IRQ	41
++#define DI3D_FTDI3D_0_IRQ	41
++
++/* H264E */
++#define H264E_FTMCP280_IRQ_COUNT	1
++#define H264E_FTMCP280_IRQ	29
++#define H264E_FTMCP280_0_IRQ	29
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	1
++#define MCP_FTMCP100_IRQ	31
++#define MCP_FTMCP100_0_IRQ	31
++
++/* ISP320 */
++#define ISP320_FTISP320_IRQ_COUNT	1
++#define ISP320_FTISP320_IRQ0	43
++#define ISP320_FTISP320_0_IRQ0	43
++
++/* MIPI */
++#define MIPI_FTCSIRX100_IRQ_COUNT	1
++#define MIPI_FTCSIRX100_IRQ0	52
++#define MIPI_FTCSIRX100_0_IRQ0	52
++
++/* HiSPi */
++#define HISPI_FTHISPI_IRQ_COUNT	1
++#define HISPI_FTHISPI_IRQ0	45
++#define HISPI_FTHISPI_0_IRQ0	45
++
++/* LVDS */
++#define LVDS_FTLVDS_IRQ_COUNT	1
++#define LVDS_FTLVDS_IRQ0	46
++#define LVDS_FTLVDS_0_IRQ0	46
++
++/* THDNR */
++#define THDNR_FT3DNR_IRQ_COUNT 1
++#define THDNR_FT3DNR_IRQ 42
++#define THDNR_FT3DNR_0_IRQ 42
++
++/* IR_DET */
++#define IR_DET_FTIRDET_IRQ_COUNT	1
++#define IR_DET_FTIRDET_IRQ	48
++#define IR_DET_FTIRDET_0_IRQ	48
++
++/* RTC */
++#define RTC_FTRTC_IRQ_COUNT     2
++#define RTC_FTRTC_IRQ           50
++#define RTC_FTRTC_0_IRQ         50      ///< RTC_INT
++#define RTC_FTRTC_0_ALM_IRQ     51      ///< RTC_ALARM
++
++/* ADC */
++#define ADC_WRAP_IRQ_COUNT	1
++#define ADC_WRAP_IRQ	35
++#define ADC_WRAP_0_IRQ	35
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_IRQ_COUNT    1
++#define DMAC_FTDMAC020_IRQ  1
++#define DMAC_FTDMAC020_0_IRQ		1
++
++/* APBBRG */
++#define APBBRG_FTAPBBRG020S_IRQ_COUNT	1
++#define APBBRG_FTAPBBRG020S_IRQ		2
++
++/*Think2d*/
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_IRQ_COUNT	1
++#define GRA_FT2DGRA_IRQ	4
++#define GRA_FT2DGRA_0_IRQ	4
++
++/* pMonitor */
++#define PMONITOR_IRQ_COUNT	1
++#define PMONITOR_IRQ		44
++
++/*
++ * Base addresses
++ */
++
++/* PWMTMR */
++#define PWMTMR_FTPWM010_PA_COUNT	1
++#define PWMTMR_FTPWM010_PA_BASE	    0x91B00000
++#define PWMTMR_FTPWM010_PA_LIMIT	0x91B0FFFF
++#define PWMTMR_FTPWM010_PA_SIZE	    0x00010000
++#define PWMTMR_FTPWM010_0_PA_BASE	0x91B00000
++#define PWMTMR_FTPWM010_0_PA_LIMIT	0x91B0FFFF
++#define PWMTMR_FTPWM010_0_PA_SIZE	0x00010000
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x90E00000
++#define WDT_FTWDT010_PA_LIMIT	0x90E00FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x90E00000
++#define WDT_FTWDT010_0_PA_LIMIT	0x90E00FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	1
++#define GPIO_FTGPIO010_PA_BASE	0x91000000
++#define GPIO_FTGPIO010_PA_LIMIT	0x91000FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0x91000000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0x91000FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0x91900000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0x91900FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0x91200000
++#define I2C_FTI2C010_PA_LIMIT	0x91200FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0x91200000
++#define I2C_FTI2C010_0_PA_LIMIT	0x91200FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0x91300000
++#define SSP_FTSSP010_PA_LIMIT	0x91300FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0x91300000
++#define SSP_FTSSP010_0_PA_LIMIT	0x91300FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0x91400000
++#define SSP_FTSSP010_1_PA_LIMIT	0x91400FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++
++/* SPI */
++#define SPI_FTSPI020_PA_COUNT	1
++#define SPI_FTSPI020_PA_BASE	0x92300000
++#define SPI_FTSPI020_PA_LIMIT	0x92300FFF
++#define SPI_FTSPI020_PA_SIZE	0x00001000
++#define SPI_FTSPI020_0_PA_BASE	0x92300000
++#define SPI_FTSPI020_0_PA_LIMIT	0x92300FFF
++#define SPI_FTSPI020_0_PA_SIZE	0x00001000
++
++/* SDC */
++#define SDC_FTSDC021_PA_COUNT	1
++#define SDC_FTSDC021_PA_BASE	0x92800000
++#define SDC_FTSDC021_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_PA_SIZE	0x00001000
++#define SDC_FTSDC021_0_PA_BASE	0x92800000
++#define SDC_FTSDC021_0_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_0_PA_SIZE	0x00001000
++
++/* NAND */
++#define NAND_FTNAND024_PA_COUNT	1
++#define NAND_FTNAND024_PA_BASE	0x93700000
++#define NAND_FTNAND024_PA_LIMIT	0x937FFFFF
++#define NAND_FTNAND024_PA_SIZE	0x00100000
++#define NAND_FTNAND024_0_PA_BASE	0x93700000
++#define NAND_FTNAND024_0_PA_LIMIT	0x937FFFFF
++#define NAND_FTNAND024_0_PA_SIZE	0x00100000
++
++/* NAND Data Port */
++#define NANDDP_FTNAND024_PA_COUNT	1
++#define NANDDP_FTNAND024_PA_BASE	0x93800000
++#define NANDDP_FTNAND024_PA_LIMIT	0x938FFFFF
++#define NANDDP_FTNAND024_PA_SIZE	0x00100000
++#define NANDDP_FTNAND024_0_PA_BASE	0x93800000
++#define NANDDP_FTNAND024_0_PA_LIMIT	0x938FFFFF
++#define NANDDP_FTNAND024_0_PA_SIZE	0x00100000
++
++/* USB */
++#define USB_FOTG2XX_PA_COUNT	1
++#define USB_FOTG2XX_PA_BASE	0x93000000
++#define USB_FOTG2XX_PA_LIMIT	0x93000FFF
++#define USB_FOTG2XX_PA_SIZE	0x00001000
++#define USB_FOTG2XX_0_PA_BASE	0x93000000
++#define USB_FOTG2XX_0_PA_LIMIT	0x93000FFF
++#define USB_FOTG2XX_0_PA_SIZE	0x00001000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	1
++#define LCD_FTLCDC200_PA_BASE	0x9BF00000
++#define LCD_FTLCDC200_PA_LIMIT	0x9BF0CFFF
++#define LCD_FTLCDC200_PA_SIZE	0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	0x9BF00000
++#define LCD_FTLCDC200_0_PA_LIMIT	0x9BF0CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	0x0000D000
++
++/* MAC */
++#define MAC_FTGMAC100_PA_COUNT	1
++#define MAC_FTGMAC100_PA_BASE	0x92500000
++#define MAC_FTGMAC100_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_0_PA_BASE	0x92500000
++#define MAC_FTGMAC100_0_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_0_PA_SIZE	0x00001000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT	1
++#define TVE_FTTVE100_PA_BASE	0x93500000
++#define TVE_FTTVE100_PA_LIMIT	0x93500FFF
++#define TVE_FTTVE100_PA_SIZE	0x00001000
++#define TVE_FTTVE100_0_PA_BASE	0x93500000
++#define TVE_FTTVE100_0_PA_LIMIT	0x93500FFF
++#define TVE_FTTVE100_0_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0x92700000
++#define AES_FTAES020_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0x92700000
++#define AES_FTAES020_0_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* SCAL */
++#define SCAL_FTSCAL300_PA_COUNT 1
++#define SCAL_FTSCAL300_PA_BASE  0x96200000
++#define SCAL_FTSCAL300_PA_LIMIT 0x96247FFF
++#define SCAL_FTSCAL300_PA_SIZE  0x00048000
++#define SCAL_FTSCAL300_0_PA_BASE    0x96200000
++#define SCAL_FTSCAL300_0_PA_LIMIT   0x96247FFF
++#define SCAL_FTSCAL300_0_PA_SIZE    0x00048000
++
++/* CAP */
++#define CAP_FTCAP300_PA_COUNT	1
++#define CAP_FTCAP300_PA_BASE	0x96100000
++#define CAP_FTCAP300_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_PA_SIZE	0x00001000
++#define CAP_FTCAP300_0_PA_BASE	0x96100000
++#define CAP_FTCAP300_0_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_0_PA_SIZE	0x00001000
++
++/* DI3D */
++#define DI3D_FTDI3D_PA_COUNT	1
++#define DI3D_FTDI3D_PA_BASE	    0x9B000000
++#define DI3D_FTDI3D_PA_LIMIT	0x9B000FFF
++#define DI3D_FTDI3D_PA_SIZE	    0x00001000
++#define DI3D_FTDI3D_0_PA_BASE	0x9B000000
++#define DI3D_FTDI3D_0_PA_LIMIT	0x9B000FFF
++#define DI3D_FTDI3D_0_PA_SIZE	0x00001000
++
++/* H264E */
++#define H264E_FTMCP280_PA_COUNT	1
++#define H264E_FTMCP280_PA_BASE	0x92C00000
++#define H264E_FTMCP280_PA_LIMIT	0x92C00FFF
++#define H264E_FTMCP280_PA_SIZE	0x00001000
++#define H264E_FTMCP280_0_PA_BASE	0x92C00000
++#define H264E_FTMCP280_0_PA_LIMIT	0x92C00FFF
++#define H264E_FTMCP280_0_PA_SIZE	0x00001000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0x92000000
++#define MCP_FTMCP100_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_0_PA_BASE	0x92000000
++#define MCP_FTMCP100_0_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++
++/* CT656 */
++#define CT656_FTCT656_PA_COUNT	1
++#define CT656_FTCT656_PA_BASE	0x92A00000
++#define CT656_FTCT656_PA_LIMIT	0x92A00FFF
++#define CT656_FTCT656_PA_SIZE	0x00001000
++#define CT656_FTCT656_0_PA_BASE	0x92A00000
++#define CT656_FTCT656_0_PA_LIMIT	0x92A00FFF
++#define CT656_FTCT656_0_PA_SIZE	0x00001000
++
++/* ISP320 */
++#define ISP320_FTISP320_PA_COUNT	1
++#define ISP320_FTISP320_PA_BASE		0x93930000
++#define ISP320_FTISP320_PA_LIMIT	0x93932FFF
++#define ISP320_FTISP320_PA_SIZE		0x00003000
++#define ISP320_FTISP320_0_PA_BASE	0x93930000
++#define ISP320_FTISP320_0_PA_LIMIT	0x93932FFF
++#define ISP320_FTISP320_0_PA_SIZE	0x00003000
++
++/* MIPI */
++#define MIPI_FTCSIRX100_PA_COUNT	1
++#define MIPI_FTCSIRX100_PA_BASE		0x9ba00000
++#define MIPI_FTCSIRX100_PA_LIMIT	0x9ba00FFF
++#define MIPI_FTCSIRX100_PA_SIZE		0x00001000
++#define MIPI_FTCSIRX100_0_PA_BASE	0x9ba00000
++#define MIPI_FTCSIRX100_0_PA_LIMIT	0x9ba00FFF
++#define MIPI_FTCSIRX100_0_PA_SIZE	0x00001000
++
++/* HiSPi */
++#define HISPI_FTHISPI_PA_COUNT		1
++#define HISPI_FTHISPI_PA_BASE		0x9bb00000
++#define HISPI_FTHISPI_PA_LIMIT		0x9bb00FFF
++#define HISPI_FTHISPI_PA_SIZE		0x00001000
++#define HISPI_FTHISPI_0_PA_BASE		0x9bb00000
++#define HISPI_FTHISPI_0_PA_LIMIT	0x9bb00FFF
++#define HISPI_FTHISPI_0_PA_SIZE		0x00001000
++
++/* LVDS */
++#define LVDS_FTLVDS_PA_COUNT	1
++#define LVDS_FTLVDS_PA_BASE		0x9bc00000
++#define LVDS_FTLVDS_PA_LIMIT	0x9bc00FFF
++#define LVDS_FTLVDS_PA_SIZE		0x00001000
++#define LVDS_FTLVDS_0_PA_BASE	0x9bc00000
++#define LVDS_FTLVDS_0_PA_LIMIT	0x9bc00FFF
++#define LVDS_FTLVDS_0_PA_SIZE	0x00001000
++
++/* THDNR */
++#define THDNR_FT3DNR_PA_COUNT   1
++#define THDNR_FT3DNR_PA_BASE    0x9b700000
++#define THDNR_FT3DNR_PA_LIMIT   0x9b7007FF
++#define THDNR_FT3DNR_PA_SIZE    0x00000800
++#define THDNR_FT3DNR_0_PA_BASE  0x9b700000
++#define THDNR_FT3DNR_0_PA_LIMIT 0x9b7007FF
++#define THDNR_FT3DNR_0_PA_SIZE  0x00000800
++
++/* IR_DET */
++#define IR_DET_FTIRDET_PA_COUNT	1
++#define IR_DET_FTIRDET_PA_BASE	0x91600000
++#define IR_DET_FTIRDET_PA_LIMIT	0x91600FFF
++#define IR_DET_FTIRDET_PA_SIZE	0x00001000
++#define IR_DET_FTIRDET_0_PA_BASE	0x91600000
++#define IR_DET_FTIRDET_0_PA_LIMIT	0x91600FFF
++#define IR_DET_FTIRDET_0_PA_SIZE	0x00001000
++
++/* RTC */
++#define RTC_FTRTC_PA_COUNT      1
++#define RTC_FTRTC_PA_BASE       0x91C00000
++#define RTC_FTRTC_PA_LIMIT      0x91C00FFF
++#define RTC_FTRTC_PA_SIZE       0x00001000
++#define RTC_FTRTC_0_PA_BASE     0x91C00000
++#define RTC_FTRTC_0_PA_LIMIT    0x91C00FFF
++#define RTC_FTRTC_0_PA_SIZE     0x00001000
++
++/* ADC */
++#define ADC_WRAP_PA_COUNT	1
++#define ADC_WRAP_PA_BASE	0x90A00000
++#define ADC_WRAP_PA_LIMIT	0x90A00FFF
++#define ADC_WRAP_PA_SIZE	0x00001000
++#define ADC_WRAP_0_PA_BASE	0x90A00000
++#define ADC_WRAP_0_PA_LIMIT	0x90A00FFF
++#define ADC_WRAP_0_PA_SIZE	0x00001000
++
++/* ADDA */
++#define ADDA_WRAP_PA_COUNT	1
++#define ADDA_WRAP_PA_BASE	0x90B00000
++#define ADDA_WRAP_PA_LIMIT	0x90B00FFF
++#define ADDA_WRAP_PA_SIZE	0x00001000
++#define ADDA_WRAP_0_PA_BASE	0x90B00000
++#define ADDA_WRAP_0_PA_LIMIT	0x90B00FFF
++#define ADDA_WRAP_0_PA_SIZE	0x00001000
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_PA_COUNT 1
++#define DMAC_FTDMAC020_PA_BASE  0x92600000
++#define DMAC_FTDMAC020_PA_LIMIT 0x92600FFF
++#define DMAC_FTDMAC020_PA_SIZE  0x0001000
++#define DMAC_FTDMAC020_0_PA_BASE	0x92600000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0x92600FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++
++/* APBBRG */
++#define APBBRG_FTAPBBRG020S_PA_COUNT	1
++#define APBBRG_FTAPBBRG020S_PA_BASE	0x90000000
++#define APBBRG_FTAPBBRG020S_PA_LIMIT	0x900FFFFF
++#define APBBRG_FTAPBBRG020S_PA_SIZE	0x00100000
++#define APBBRG_FTAPBBRG020S_0_PA_BASE	0x90000000
++#define APBBRG_FTAPBBRG020S_0_PA_LIMIT	0x900FFFFF
++#define APBBRG_FTAPBBRG020S_0_PA_SIZE	0x00100000
++
++/* DDRC */
++#define DDRC_FTDDRC010_PA_COUNT	1
++#define DDRC_FTDDRC010_PA_BASE	0x9A100000
++#define DDRC_FTDDRC010_PA_LIMIT	0x9A100FFF
++#define DDRC_FTDDRC010_PA_SIZE	0x00001000
++
++/*THINK 2D*/
++#define GRA_FT2DGRA_PA_BASE     0x92200000
++#define GRA_FT2DGRA_PA_LIMIT    0x92200FFF
++#define GRA_FT2DGRA_PA_SIZE     0x00001000
++
++/* GPENC */
++#define GRAPHIC_ENC_PA_BASE     0x9B200000
++#define GRAPHIC_ENC_PA_LIMIT    0x9B200FFF
++#define GRAPHIC_ENC_PA_SIZE     0x00001000
++
++/* GPDEC */
++#define GRAPHIC_DEC_PA_BASE     0x9B300000
++#define GRAPHIC_DEC_PA_LIMIT    0x9B300FFF
++#define GRAPHIC_DEC_PA_SIZE     0x00001000
++#define GRAPHIC_DEC_0_PA_BASE   0x9B300000
++#define GRAPHIC_DEC_0_PA_LIMIT  0x9B300FFF
++#define GRAPHIC_DEC_0_PA_SIZE   0x00001000
++
++#define PMONITOR_PA_BASE	0x91D00000
++#define PMONITOR_PA_LIMIT	0x91D00FFF
++#define PMONITOR_PA_SIZE	0x00001000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++#define PLATFORM_IRQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL1	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL1	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL3	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL3	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL4	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL4	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL5	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL5	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL6	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL6	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL7	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL7	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL8	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL8	0xFFFFFFFF
++
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/pmu.h b/arch/arm/mach-GM/include/mach/platform-GM8139/pmu.h
+new file mode 100644
+index 00000000..00e0588a
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/pmu.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++
++
++unsigned int pmu_get_apb_clk(void);
++int platform_check_flash_type(void);
++int platform_spi_four_byte_mode(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/serial.h b/arch/arm/mach-GM/include/mach/platform-GM8139/serial.h
+new file mode 100644
+index 00000000..05223247
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/serial.h
+@@ -0,0 +1,59 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 4 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ *  Luke Lee  11/16/2005  Add conditional compilation.
++ */
++
++#ifdef CONFIG_FPGA
++#define CONFIG_UART_CLK			12000000
++#else
++#define CONFIG_UART_CLK			25000000
++#endif
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#ifdef CONFIG_SERIAL_UART1_IP
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++#else
++#define EXTENDED_UART_1 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART2_IP
++#define EXTENDED_UART_2 \
++     { 0, BASE_BAUD, UART_FTUART010_2_VA_BASE, UART_FTUART010_2_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS2 */
++#else
++#define EXTENDED_UART_2 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1            \
++        EXTENDED_UART_2
++
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/system.h b/arch/arm/mach-GM/include/mach/platform-GM8139/system.h
+new file mode 100644
+index 00000000..e15380d5
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/system.h
+@@ -0,0 +1,78 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8129/system.h
++ *
++ *  Faraday Platform Dependent System Definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/22/2005  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++static inline void arch_reset(char mode, const char *cmd)
++{
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++
++    pmuReg_t regRSTArray[] = {
++        /* reg_off, bit_masks, lock_bits,init_val, init_mask */
++        {0xB8, (1<< 10), (1<< 10), 0, (1<< 10)},
++    };
++
++    pmuRegInfo_t rst_clk_info = {
++        "rst_clk",
++        ARRAY_SIZE(regRSTArray),
++        ATTR_TYPE_NONE,
++        regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<15)), (PMU_FTPMU010_VA_BASE + 0x3C));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C));        // reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));        // load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08));   // Magic number
++    writeb(0x03, (wdt_va_base + 0x0C));     // Enable WDT
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8139/vmalloc.h b/arch/arm/mach-GM/include/mach/platform-GM8139/vmalloc.h
+new file mode 100644
+index 00000000..320deb0c
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8139/vmalloc.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8129/vmalloc.h
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  10/06/2005  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/board.h b/arch/arm/mach-GM/include/mach/platform-GM8287/board.h
+new file mode 100644
+index 00000000..7916efb2
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/board.h
+@@ -0,0 +1,99 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/board.h
++ *  
++ *  GM board Independent Specification
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 
++ *
++ *  ChangeLog
++ *  
++ *   Harry  2012/3/6 03:15 created. 
++ */
++#ifndef __BOARD_H__
++#define __BOARD_H__
++
++#include <mach/platform/platform_io.h>
++#include <asm/pgtable.h>
++//#include <mach/platform/vmalloc.h>
++
++#define BOARD_NAME              "Grain-Media GM828x series"
++#define BOOT_PARAMETER_PA_OFFSET  0x100
++
++//starts from 0xFE000000 if VMALLOC_END is 0xFF000000
++#define IPTABLE_BASE            (VMALLOC_END - 0x1000000)   
++
++/*
++ * list the virtual address of IPs for the iotable.
++ */
++/* PMU */
++#define PMU_FTPMU010_PA_BASE        0x99000000
++#define PMU_FTPMU010_VA_BASE        IPTABLE_BASE
++#define PMU_FTPMU010_VA_SIZE        SZ_4K
++
++/* UART */
++#define UART_FTUART010_0_PA_BASE	0x98300000
++#define UART_FTUART010_0_VA_BASE    (PMU_FTPMU010_VA_BASE + PMU_FTPMU010_VA_SIZE)
++#define UART_FTUART010_0_VA_SIZE    SZ_4K
++#define UART_FTUART010_0_IRQ        9
++
++#define UART_FTUART010_1_PA_BASE    0x98400000
++#define UART_FTUART010_1_VA_BASE    (UART_FTUART010_0_VA_BASE + UART_FTUART010_0_VA_SIZE)
++#define UART_FTUART010_1_VA_SIZE    SZ_4K
++#define UART_FTUART010_1_IRQ        10
++
++#define UART_FTUART010_2_PA_BASE    0x98500000
++#define UART_FTUART010_2_VA_BASE    (UART_FTUART010_1_VA_BASE + UART_FTUART010_1_VA_SIZE)
++#define UART_FTUART010_2_VA_SIZE    SZ_4K
++#define UART_FTUART010_2_IRQ        20
++
++#define UART_FTUART010_3_PA_BASE    0x98800000
++#define UART_FTUART010_3_VA_BASE    (UART_FTUART010_2_VA_BASE + UART_FTUART010_2_VA_SIZE)
++#define UART_FTUART010_3_VA_SIZE    SZ_4K
++#define UART_FTUART010_3_IRQ        21
++
++/* TIMER */
++#define TIMER_FTTMR010_PA_BASE	    0x99100000
++#define TIMER_FTTMR010_VA_BASE	    (UART_FTUART010_3_VA_BASE + UART_FTUART010_3_VA_SIZE)
++#define TIMER_FTTMR010_VA_SIZE	    SZ_4K
++#define TIMER_FTTMR010_IRQ_COUNT    3
++#define TIMER_FTTMR010_IRQ0         14
++#define TIMER_FTTMR010_IRQ1         14
++#define TIMER_FTTMR010_IRQ2         14
++
++/* INTC030 */
++#define INTC_FTINTC030_PA_BASE      0x96000000
++#define INTC_FTINTC030_VA_BASE      (TIMER_FTTMR010_VA_BASE + TIMER_FTTMR010_VA_SIZE)
++#define INTC_FTINTC030_VA_SIZE	    SZ_4K
++
++/* define the address used in machine-start */
++#define PLATFORM_BOOTTIME_IO_PA_BASE    UART_FTUART010_0_PA_BASE
++#define PLATFORM_BOOTTIME_IO_VA_BASE    UART_FTUART010_0_VA_BASE
++/* for debug_macro.S */
++#define DEBUG_LL_FTUART010_PA_BASE      UART_FTUART010_0_PA_BASE    
++#define DEBUG_LL_FTUART010_VA_BASE      UART_FTUART010_0_VA_BASE
++
++
++#ifndef __ASSEMBLY__ 
++ #include <asm/setup.h>
++
++/* declare the function prototype
++ */
++void board_get_memory(struct meminfo **p_memory);
++void board_get_gmmemory(struct meminfo **p_memory);
++#endif /* __ASSEMBLY__  */
++
++#endif /* __BOARD_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/dma_route.h b/arch/arm/mach-GM/include/mach/platform-GM8287/dma_route.h
+new file mode 100644
+index 00000000..4fbf887a
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/dma_route.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
++ *
++ * 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.
++ * 
++ *
++ * The full GNU General Public License is included in this distribution in the
++ * file called COPYING.
++ */
++#ifndef __DMA_ROUTE_H__
++#define __DMA_ROUTE_H__
++
++/* define AHB DMA routing table 
++ */
++#define AHBDMA_REQ_SSP0_RX  0
++#define AHBDMA_REQ_SSP0_TX  1
++#define AHBDMA_REQ_SSP1_RX  2
++#define AHBDMA_REQ_SSP1_TX  3
++#define AHBDMA_REQ_SSP2_RX  4
++#define AHBDMA_REQ_SSP2_TX  5
++#define AHBDMA_REQ_SDC      6
++#define AHBDMA_REQ_NANDC    9
++#define AHBDMA_REQ_PWMTMR5  12
++#define AHBDMA_REQ_PWMTMR6  13
++#define AHBDMA_REQ_PWMTMR7  14
++#define AHBDMA_REQ_PWMTMR8  15
++
++/* define APB DMA routing table 
++ */
++#define APBDMA_REQ_UART0_RX 1
++#define APBDMA_REQ_UART0_TX 2
++#define APBDMA_REQ_UART1_RX 3
++#define APBDMA_REQ_UART1_TX 4
++#define APBDMA_REQ_UART2_RX 5
++#define APBDMA_REQ_UART2_TX 6
++#define APBDMA_REQ_UART3_RX 7  
++#define APBDMA_REQ_UART3_TX 8
++#define APBDMA_REQ_UART4_RX 9  
++#define APBDMA_REQ_UART4_TX 10
++#define APBDMA_REQ_PWMTMR1  12
++#define APBDMA_REQ_PWMTMR2  13
++#define APBDMA_REQ_PWMTMR3  14
++#define APBDMA_REQ_PWMTMR4  15
++
++
++#endif /* __DMA_ROUTE_H__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/gpio.h b/arch/arm/mach-GM/include/mach/platform-GM8287/gpio.h
+new file mode 100644
+index 00000000..258f0c49
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/gpio.h
+@@ -0,0 +1,15 @@
++#ifndef __GM8287_GPIO_H__
++#define __GM8287_GPIO_H__
++
++#define GM_GPIO010_NR_PORT		2
++#define GM_GPIO_NR_PIN_PER_PORT		32
++#define ARCH_NR_GPIOS			(GM_GPIO_NR_PIN_PER_PORT*GM_GPIO010_NR_PORT)
++
++static inline int gm_gpio_pin_index(unsigned port, unsigned pin)
++{
++	int ret = port*GM_GPIO_NR_PIN_PER_PORT + pin;
++	
++	return ret < ARCH_NR_GPIOS ? ret : -1;
++} 
++
++#endif//end of __GM8287_GPIO_H__
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/irqs.h b/arch/arm/mach-GM/include/mach/platform-GM8287/irqs.h
+new file mode 100644
+index 00000000..b35b5b22
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/irqs.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8287/irqs.h
++ *  
++ *  Faraday Platform Dependent IRQ Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ *  ChangeLog
++ *  
++ *   Luke Lee 10/06/2005 Created.
++ */
++
++#ifndef __GM_PLATFORM_IRQS_HEADER__
++#define __GM_PLATFORM_IRQS_HEADER__
++
++#include <mach/platform/platform_io.h>
++
++#define FIQ_START		    PLATFORM_FIQ_BASE
++#define MAX_FTINTC010_NR	2
++#define NR_IRQS             PLATFORM_INTERRUPTS
++
++#endif /* __GM_PLATFORM_IRQS_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/memory.h b/arch/arm/mach-GM/include/mach/platform-GM8287/memory.h
+new file mode 100644
+index 00000000..6b37c6ae
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/memory.h
+@@ -0,0 +1,63 @@
++/*
++ *  linux/include/asm-armnommu/arch-GM/platform-GM8287/memory.h
++ *  
++ *  GM Platform Dependent Memory Configuration
++ *  
++ * 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
++ *  
++ */
++#ifndef __MEMORY_H__
++#define __MEMORY_H__
++
++#ifndef __ASSEMBLY__
++
++#define PHYS_OFFSET     CPU_MEM_PA_BASE
++
++#endif /* __ASSEMBLY__ */
++/* The memory size DDR0_FMEM_SIZE / DDR1_FMEM_SIZE is allocated for Framamp management. 
++ *
++ * Users can adjust the memory size based on the real memory size requirement.  
++ * This definition is applied to DDR0 only.
++ */
++#define DDR0_FMEM_SIZE     0x1000000
++
++/* The memory size for Framamp management. Users can adjust the memory size based on the real
++ * memory size requirement. 
++ *
++ * This definition is applied to DDR1. -1 means to allocate almost whole memory.
++ */
++#define DDR1_FMEM_SIZE     -1
++
++
++/* HARRY: DO NOT CHANGE THIS VALUE. 
++ * The memory boundary is 16M alginment 
++ *
++ *
++ * Two definitions are required for sparsemem:
++ *
++ * MAX_PHYSMEM_BITS: The number of physical address bits required
++ *   to address the last byte of memory.
++ *
++ * SECTION_SIZE_BITS: The number of physical address bits to cover
++ *   the maximum amount of memory in a section.
++ *
++ * Eg, if you have 2 banks of up to 64MB at 0x80000000, 0x84000000,
++ * then MAX_PHYSMEM_BITS is 32, SECTION_SIZE_BITS is 26.
++ */
++#define SECTION_SIZE_BITS   24  /* 16M */
++#define MAX_PHYSMEM_BITS    27  /* 128M */
++
++#endif /* __MEMORY_H__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/platform_io.h b/arch/arm/mach-GM/include/mach/platform-GM8287/platform_io.h
+new file mode 100644
+index 00000000..80e92c94
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/platform_io.h
+@@ -0,0 +1,612 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8129/platform_io.h
++ *
++ *  Faraday GM platform dependent definitions
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * ChangeLog
++ *  Add IRQ number definition
++ *  Add IP module phy address definition
++ *
++ */
++#ifndef __PLATFORM_IO_H__
++#define __PLATFORM_IO_H__
++
++
++#define PLATFORM_FIQ_BASE       0
++#define PLATFORM_IRQ_TOTALCOUNT	96/* interrupt controller supports 96 interrupts */
++#define PLATFORM_INTERRUPTS     PLATFORM_IRQ_TOTALCOUNT
++#define CPU_MEM_PA_BASE         0x0     /* the memory physical start address(DDR) */
++
++/*
++ * Component counts
++ */
++
++/* PWMTMR */
++#define PWMTMR_COUNT	1
++#define PWMTMR_FTPWM010_COUNT	1
++/* WDT */
++#define WDT_COUNT	1
++#define WDT_FTWDT010_COUNT	1
++/* GPIO */
++#define GPIO_COUNT	2
++#define GPIO_FTGPIO010_COUNT	2
++/* I2C */
++#define I2C_COUNT	5
++#define I2C_FTI2C010_COUNT	5
++/* SSP */
++#define SSP_COUNT	3
++#define SSP_FTSSP010_COUNT	3
++/* SPI020 */
++#define SPI_COUNT	1
++#define SPI_FTSPI020_COUNT	1
++/* SDC */
++#define SDC_COUNT	1
++#define SDC_FTSDC021_COUNT	1
++/* NAND */
++#define NAND_COUNT	1
++#define NAND_FTNAND023_COUNT	1
++/* NANDDP */
++#define NANDDP_COUNT	1
++#define NANDDP_FTNAND023_COUNT	1
++/* SATA */
++#define SATA_COUNT	2
++#define SATA_FTSATA100_COUNT	2
++/* OTG */
++#define USB_COUNT       2
++#define USB_FOTG2XX_COUNT       2
++/* LCD */
++#define LCD_COUNT	2
++#define LCD_FTLCDC200_COUNT	2
++/* MAC */
++#define MAC_COUNT	1
++#define MAC_FTGMAC100_COUNT	1
++/* TVE */
++#define TVE_COUNT	1
++#define TVE_FTTVE100_COUNT	1
++/* AES */
++#define AES_COUNT	1
++#define AES_FTAES020_COUNT	1
++/* SCAL */
++#define SCAL_COUNT	1
++#define SCAL_FTSCAL300_COUNT	1
++/* CAP */
++#define CAP_COUNT	1
++#define CAP_FTCAP300_COUNT	1
++/* DI3D */
++#define DI3D_COUNT	1
++#define DI3D_FTDI3D_COUNT	1
++/* H264E */
++#define H264E_COUNT	1
++#define H264E_FTMCP280_COUNT	1
++/* H264D */
++#define H264D_COUNT	1
++#define H264D_FTMCP300_COUNT	1
++/* MCP */
++#define MCP_COUNT	1
++#define MCP_FTMCP100_COUNT	1
++/* IR_DET */
++#define IR_DET_COUNT	1
++#define IR_DET_FTIRDET_COUNT	1
++
++/* ADC */
++#define ADC_COUNT	1
++#define ADC_WRAP_COUNT	1
++
++/* DMAC */
++#define DMAC_COUNT	1
++#define DMAC_FTDMAC020_COUNT 1
++
++/* APBB */
++#define APBB_COUNT	1
++#define APBB_FTAPBB020_COUNT	1
++
++/* DDRC */
++#define DDRC_COUNT	1
++#define DDRC_FTDDRC010_COUNT	1
++
++/* KPD */
++#define KPD_COUNT	1
++#define KPD_FTKPD_COUNT	1
++/*
++ * Interrrupt numbers
++ */
++/* PWMTMR */
++#define PWMTMR_FTPWM010_IRQ_COUNT	1
++#define PWMTMR_FTPWM010_IRQ0	22
++#define PWMTMR_FTPWM010_0_IRQ0	22
++
++/* WDT */
++#define WDT_FTWDT010_IRQ_COUNT	1
++#define WDT_FTWDT010_IRQ	16
++#define WDT_FTWDT010_0_IRQ	16
++
++/* GPIO */
++#define GPIO_FTGPIO010_IRQ_COUNT	1
++#define GPIO_FTGPIO010_IRQ	13
++#define GPIO_FTGPIO010_0_IRQ	13
++#define GPIO_FTGPIO010_1_IRQ	63
++
++/* I2C */
++#define I2C_FTI2C010_IRQ_COUNT	1
++#define I2C_FTI2C010_IRQ	18
++#define I2C_FTI2C010_0_IRQ	18
++#define I2C_FTI2C010_1_IRQ	53
++#define I2C_FTI2C010_2_IRQ	50
++#define I2C_FTI2C010_3_IRQ	51
++#define I2C_FTI2C010_4_IRQ	52
++
++/* SSP */
++#define SSP_FTSSP010_IRQ_COUNT	1
++#define SSP_FTSSP010_IRQ	6
++#define SSP_FTSSP010_0_IRQ	6
++#define SSP_FTSSP010_1_IRQ	11
++#define SSP_FTSSP010_2_IRQ	7
++
++/* SPI */
++#define SPI_FTSPI020_IRQ_COUNT	1
++#define SPI_FTSPI020_IRQ	92
++#define SPI_FTSPI020_0_IRQ	92
++
++/* SDC */
++#define SDC_FTSDC021_IRQ_COUNT	1
++#define SDC_FTSDC021_IRQ	15
++#define SDC_FTSDC021_0_IRQ	15
++
++/* NAND */
++#define NAND_FTNAND023_IRQ_COUNT	1
++#define NAND_FTNAND023_IRQ	23
++#define NAND_FTNAND023_0_IRQ	23
++
++/* SATA */
++#define SATA_FTSATA100_IRQ_COUNT	1
++#define SATA_FTSATA100_IRQ	28
++#define SATA_FTSATA100_0_IRQ	28
++#define SATA_FTSATA100_1_IRQ	40
++
++/* OTG */
++#define USB_FOTG2XX_IRQ_COUNT	1
++#define USB_FOTG2XX_IRQ		93
++#define USB_FOTG2XX_0_IRQ	93
++#define USB_FOTG2XX_1_IRQ	94
++
++/* LCD */
++#define LCD_FTLCDC200_IRQ_COUNT	1
++#define LCD_FTLCDC200_IRQ	24
++#define LCD_FTLCDC200_0_IRQ	24
++#define LCD_FTLCDC200_2_IRQ	46
++
++/* 2D GRAPHIC */
++#define GRA_FT2DGRA_IRQ_COUNT	1
++#define GRA_FT2DGRA_IRQ	4
++#define GRA_FT2DGRA_0_IRQ	4
++
++/* MAC */
++#define MAC_FTGMAC100_IRQ_COUNT	1
++#define MAC_FTGMAC100_IRQ	3
++#define MAC_FTGMAC100_0_IRQ	3
++
++/* AES */
++#define AES_FTAES020_IRQ_COUNT	1
++#define AES_FTAES020_IRQ	19
++#define AES_FTAES020_0_IRQ	19
++
++/* SCAL */
++#define SCAL_FTSCAL300_IRQ_COUNT    1
++#define SCAL_FTSCAL300_IRQ  12
++#define SCAL_FTSCAL300_0_IRQ    12
++
++/* CAP */
++#define CAP_FTCAP300_IRQ_COUNT	1
++#define CAP_FTCAP300_IRQ	32
++#define CAP_FTCAP300_0_IRQ	32
++
++/* DI3D */
++#define DI3D_FTDI3D_IRQ_COUNT	1
++#define DI3D_FTDI3D_IRQ	41
++#define DI3D_FTDI3D_0_IRQ	41
++
++/* H264E */
++#define H264E_FTMCP280_IRQ_COUNT	1
++#define H264E_FTMCP280_IRQ	29
++#define H264E_FTMCP280_0_IRQ	29
++
++/* H264D */
++#define H264D_FTMCP300_IRQ_COUNT	1
++#define H264D_FTMCP300_IRQ	30
++#define H264D_FTMCP300_0_IRQ	30
++
++/* MCP */
++#define MCP_FTMCP100_IRQ_COUNT	1
++#define MCP_FTMCP100_IRQ	31
++#define MCP_FTMCP100_0_IRQ	31
++
++/* IR_DET */
++#define IR_DET_FTIRDET_IRQ_COUNT	1
++#define IR_DET_FTIRDET_IRQ	48
++#define IR_DET_FTIRDET_0_IRQ	48
++
++/* KPD */
++#define KPD_FTKPD_IRQ_COUNT	1
++#define KPD_FTKPD_IRQ	49
++#define KPD_FTKPD_0_IRQ	49
++
++/* ADC */
++#define ADC_WRAP_IRQ_COUNT	1
++#define ADC_WRAP_IRQ	35
++#define ADC_WRAP_0_IRQ	35
++#define ADC_WRAP_1_IRQ	38
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_IRQ_COUNT	1
++#define DMAC_FTDMAC020_IRQ		1
++#define DMAC_FTDMAC020_0_IRQ		1
++
++/* APBB */
++#define APBB_FTAPBB020_IRQ_COUNT	2
++#define APBB_FTAPBB020_IRQ		2
++#define APBB_FTAPBB020_0_IRQ		2
++#define APBB_FTAPBB020_1_IRQ		5
++
++/*
++ * Base addresses
++ */
++
++/* PWMTMR */
++#define PWMTMR_FTPWM010_PA_COUNT	1
++#define PWMTMR_FTPWM010_PA_BASE	    0x98A00000
++#define PWMTMR_FTPWM010_PA_LIMIT	0x98A0FFFF
++#define PWMTMR_FTPWM010_PA_SIZE	    0x00010000
++#define PWMTMR_FTPWM010_0_PA_BASE	0x98A00000
++#define PWMTMR_FTPWM010_0_PA_LIMIT	0x98A0FFFF
++#define PWMTMR_FTPWM010_0_PA_SIZE	0x00010000
++
++/* WDT */
++#define WDT_FTWDT010_PA_COUNT	1
++#define WDT_FTWDT010_PA_BASE	0x99200000
++#define WDT_FTWDT010_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_PA_SIZE	0x00001000
++#define WDT_FTWDT010_0_PA_BASE	0x99200000
++#define WDT_FTWDT010_0_PA_LIMIT	0x99200FFF
++#define WDT_FTWDT010_0_PA_SIZE	0x00001000
++
++/*THINK 2D*/
++#define GRA_FT2DGRA_PA_BASE     0x92200000
++#define GRA_FT2DGRA_PA_LIMIT    0x92200FFF
++#define GRA_FT2DGRA_PA_SIZE     0x00001000
++
++/* GPIO */
++#define GPIO_FTGPIO010_PA_COUNT	1
++#define GPIO_FTGPIO010_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_0_PA_BASE	0x99400000
++#define GPIO_FTGPIO010_0_PA_LIMIT	0x99400FFF
++#define GPIO_FTGPIO010_0_PA_SIZE	0x00001000
++#define GPIO_FTGPIO010_1_PA_BASE	0x98E00000
++#define GPIO_FTGPIO010_1_PA_LIMIT	0x98E00FFF
++#define GPIO_FTGPIO010_1_PA_SIZE	0x00001000
++
++/* I2C */
++#define I2C_FTI2C010_PA_COUNT	1
++#define I2C_FTI2C010_PA_BASE	0x99600000
++#define I2C_FTI2C010_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_PA_SIZE	0x00001000
++#define I2C_FTI2C010_0_PA_BASE	0x99600000
++#define I2C_FTI2C010_0_PA_LIMIT	0x99600FFF
++#define I2C_FTI2C010_0_PA_SIZE	0x00001000
++#define I2C_FTI2C010_1_PA_BASE	0x99800000
++#define I2C_FTI2C010_1_PA_LIMIT	0x99800FFF
++#define I2C_FTI2C010_1_PA_SIZE	0x00001000
++#define I2C_FTI2C010_2_PA_BASE	0x99900000
++#define I2C_FTI2C010_2_PA_LIMIT	0x99900FFF
++#define I2C_FTI2C010_2_PA_SIZE	0x00001000
++#define I2C_FTI2C010_3_PA_BASE	0x99A00000
++#define I2C_FTI2C010_3_PA_LIMIT	0x99A00FFF
++#define I2C_FTI2C010_3_PA_SIZE	0x00001000
++#define I2C_FTI2C010_4_PA_BASE	0x99B00000
++#define I2C_FTI2C010_4_PA_LIMIT	0x99B00FFF
++#define I2C_FTI2C010_4_PA_SIZE	0x00001000
++
++/* SSP */
++#define SSP_FTSSP010_PA_COUNT	1
++#define SSP_FTSSP010_PA_BASE	0x82000000
++#define SSP_FTSSP010_PA_LIMIT	0x82000FFF
++#define SSP_FTSSP010_PA_SIZE	0x00001000
++#define SSP_FTSSP010_0_PA_BASE	0x82000000
++#define SSP_FTSSP010_0_PA_LIMIT	0x82000FFF
++#define SSP_FTSSP010_0_PA_SIZE	0x00001000
++#define SSP_FTSSP010_1_PA_BASE	0x82100000
++#define SSP_FTSSP010_1_PA_LIMIT	0x82100FFF
++#define SSP_FTSSP010_1_PA_SIZE	0x00001000
++#define SSP_FTSSP010_2_PA_BASE	0x82200000
++#define SSP_FTSSP010_2_PA_LIMIT	0x82200FFF
++#define SSP_FTSSP010_2_PA_SIZE	0x00001000
++
++/* SPI */
++#define SPI_FTSPI020_PA_COUNT	1
++#define SPI_FTSPI020_PA_BASE	0x80300000
++#define SPI_FTSPI020_PA_LIMIT	0x80300FFF
++#define SPI_FTSPI020_PA_SIZE	0x00001000
++#define SPI_FTSPI020_0_PA_BASE	0x80300000
++#define SPI_FTSPI020_0_PA_LIMIT	0x80300FFF
++#define SPI_FTSPI020_0_PA_SIZE	0x00001000
++
++/* SDC */
++#define SDC_FTSDC021_PA_COUNT	1
++#define SDC_FTSDC021_PA_BASE	0x92800000
++#define SDC_FTSDC021_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_PA_SIZE	0x00001000
++#define SDC_FTSDC021_0_PA_BASE	0x92800000
++#define SDC_FTSDC021_0_PA_LIMIT	0x92800FFF
++#define SDC_FTSDC021_0_PA_SIZE	0x00001000
++
++/* NAND */
++#define NAND_FTNAND023_PA_COUNT	1
++#define NAND_FTNAND023_PA_BASE	0x80000000
++#define NAND_FTNAND023_PA_LIMIT	0x800FFFFF
++#define NAND_FTNAND023_PA_SIZE	0x00100000
++#define NAND_FTNAND023_0_PA_BASE	0x80000000
++#define NAND_FTNAND023_0_PA_LIMIT	0x800FFFFF
++#define NAND_FTNAND023_0_PA_SIZE	0x00100000
++
++/* NAND Data Port */
++#define NANDDP_FTNAND023_PA_COUNT	1
++#define NANDDP_FTNAND023_PA_BASE	0x80100000
++#define NANDDP_FTNAND023_PA_LIMIT	0x801FFFFF
++#define NANDDP_FTNAND023_PA_SIZE	0x00100000
++#define NANDDP_FTNAND023_0_PA_BASE	0x80100000
++#define NANDDP_FTNAND023_0_PA_LIMIT	0x801FFFFF
++#define NANDDP_FTNAND023_0_PA_SIZE	0x00100000
++
++/* SATA */
++#define SATA_FTSATA100_PA_COUNT	    2
++#define SATA_FTSATA100_PA_BASE      0x93200000
++#define SATA_FTSATA100_PA_LIMIT     0x93200FFF
++#define SATA_FTSATA100_PA_SIZE      0x00001000
++#define SATA_FTSATA100_0_PA_BASE    0x93200000
++#define SATA_FTSATA100_0_PA_LIMIT   0x93200FFF
++#define SATA_FTSATA100_0_PA_SIZE    0x00001000
++#define SATA_FTSATA100_1_PA_BASE    0x93300000
++#define SATA_FTSATA100_1_PA_LIMIT   0x93300FFF
++#define SATA_FTSATA100_1_PA_SIZE    0x00001000
++
++/* OTG */
++#define USB_FOTG2XX_PA_COUNT	1
++#define USB_FOTG2XX_PA_BASE	0x93000000
++#define USB_FOTG2XX_PA_LIMIT	0x93000FFF
++#define USB_FOTG2XX_PA_SIZE	0x00001000
++#define USB_FOTG2XX_0_PA_BASE	0x93000000
++#define USB_FOTG2XX_0_PA_LIMIT	0x93000FFF
++#define USB_FOTG2XX_0_PA_SIZE	0x00001000
++#define USB_FOTG2XX_1_PA_BASE	0x93100000
++#define USB_FOTG2XX_1_PA_LIMIT	0x93100FFF
++#define USB_FOTG2XX_1_PA_SIZE	0x00001000
++
++/* LCD */
++#define LCD_FTLCDC200_PA_COUNT	    2
++#define LCD_FTLCDC200_PA_BASE	    0x9A800000
++#define LCD_FTLCDC200_PA_LIMIT	    0x9A80CFFF
++#define LCD_FTLCDC200_PA_SIZE	    0x0000D000
++#define LCD_FTLCDC200_0_PA_BASE	    0x9A800000
++#define LCD_FTLCDC200_0_PA_LIMIT	0x9A80CFFF
++#define LCD_FTLCDC200_0_PA_SIZE	    0x0000D000
++#define LCD_FTLCDC200_2_PA_BASE	    0x9B800000
++#define LCD_FTLCDC200_2_PA_LIMIT	0x9B80CFFF
++#define LCD_FTLCDC200_2_PA_SIZE	    0x0000D000
++
++/* Graphic Plance Encoder */
++#define GRAPHIC_ENC_PA_COUNT    1
++#define GRAPHIC_ENC_PA_BASE	    0x9B300000
++#define GRAPHIC_ENC_PA_LIMIT	0x9B300FFF
++#define GRAPHIC_ENC_PA_SIZE	    0x00001000
++#define GRAPHIC_ENC_0_PA_BASE	0x9B300000
++#define GRAPHIC_ENC_0_PA_LIMIT	0x9B300FFF
++#define GRAPHIC_ENC_0_PA_SIZE	0x00001000
++
++/* Graphic Plance Decoder */
++#define GRAPHIC_DEC_PA_COUNT	2
++#define GRAPHIC_DEC_PA_BASE	    0x9B400000
++#define GRAPHIC_DEC_PA_LIMIT	0x9B400FFF
++#define GRAPHIC_DEC_PA_SIZE	    0x00001000
++#define GRAPHIC_DEC_0_PA_BASE	0x9B400000
++#define GRAPHIC_DEC_0_PA_LIMIT	0x9B400FFF
++#define GRAPHIC_DEC_0_PA_SIZE	0x00001000
++#define GRAPHIC_DEC_2_PA_BASE	0x9B600000
++#define GRAPHIC_DEC_2_PA_LIMIT	0x9B600FFF
++#define GRAPHIC_DEC_2_PA_SIZE	0x00001000
++
++/* MAC */
++#define MAC_FTGMAC100_PA_COUNT	1
++#define MAC_FTGMAC100_PA_BASE	0x92500000
++#define MAC_FTGMAC100_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_PA_SIZE	0x00001000
++#define MAC_FTGMAC100_0_PA_BASE	0x92500000
++#define MAC_FTGMAC100_0_PA_LIMIT	0x92500FFF
++#define MAC_FTGMAC100_0_PA_SIZE	0x00001000
++
++/* TVE */
++#define TVE_FTTVE100_PA_COUNT	1
++#define TVE_FTTVE100_PA_BASE	0x93400000
++#define TVE_FTTVE100_PA_LIMIT	0x93400FFF
++#define TVE_FTTVE100_PA_SIZE	0x00001000
++#define TVE_FTTVE100_0_PA_BASE	0x93400000
++#define TVE_FTTVE100_0_PA_LIMIT	0x93400FFF
++#define TVE_FTTVE100_0_PA_SIZE	0x00001000
++
++/* AES */
++#define AES_FTAES020_PA_COUNT	1
++#define AES_FTAES020_PA_BASE	0x92700000
++#define AES_FTAES020_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_PA_SIZE	0x00001000
++#define AES_FTAES020_0_PA_BASE	0x92700000
++#define AES_FTAES020_0_PA_LIMIT	0x92700FFF
++#define AES_FTAES020_0_PA_SIZE	0x00001000
++
++/* SCAL */
++#define SCAL_FTSCAL300_PA_COUNT 1
++#define SCAL_FTSCAL300_PA_BASE  0x96200000
++#define SCAL_FTSCAL300_PA_LIMIT 0x962427FF
++#define SCAL_FTSCAL300_PA_SIZE  0x00042800
++#define SCAL_FTSCAL300_0_PA_BASE    0x96200000
++#define SCAL_FTSCAL300_0_PA_LIMIT   0x962427FF
++#define SCAL_FTSCAL300_0_PA_SIZE    0x00042800
++
++/* CAP */
++#define CAP_FTCAP300_PA_COUNT	1
++#define CAP_FTCAP300_PA_BASE	0x96100000
++#define CAP_FTCAP300_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_PA_SIZE	0x00001000
++#define CAP_FTCAP300_0_PA_BASE	0x96100000
++#define CAP_FTCAP300_0_PA_LIMIT	0x96100FFF
++#define CAP_FTCAP300_0_PA_SIZE	0x00001000
++
++/* DI3D */
++#define DI3D_FTDI3D_PA_COUNT	1
++#define DI3D_FTDI3D_PA_BASE	    0x9B100000
++#define DI3D_FTDI3D_PA_LIMIT	0x9B100FFF
++#define DI3D_FTDI3D_PA_SIZE	    0x00001000
++#define DI3D_FTDI3D_0_PA_BASE	0x9B100000
++#define DI3D_FTDI3D_0_PA_LIMIT	0x9B100FFF
++#define DI3D_FTDI3D_0_PA_SIZE	0x00001000
++
++/* H264E */
++#define H264E_FTMCP280_PA_COUNT	1
++#define H264E_FTMCP280_PA_BASE	0x90000000
++#define H264E_FTMCP280_PA_LIMIT	0x900FFFFF
++#define H264E_FTMCP280_PA_SIZE	0x00100000
++#define H264E_FTMCP280_0_PA_BASE	0x90000000
++#define H264E_FTMCP280_0_PA_LIMIT	0x900FFFFF
++#define H264E_FTMCP280_0_PA_SIZE	0x00100000
++
++/* H264D */
++#define H264D_FTMCP300_PA_COUNT	1
++#define H264D_FTMCP300_PA_BASE	0x94200000
++#define H264D_FTMCP300_PA_LIMIT	0x942FFFFF
++#define H264D_FTMCP300_PA_SIZE	0x00100000
++#define H264D_FTMCP300_0_PA_BASE	0x94200000
++#define H264D_FTMCP300_0_PA_LIMIT	0x942FFFFF
++#define H264D_FTMCP300_0_PA_SIZE	0x00100000
++
++/* MCP */
++#define MCP_FTMCP100_PA_COUNT	1
++#define MCP_FTMCP100_PA_BASE	0x92000000
++#define MCP_FTMCP100_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_PA_SIZE	0x00100000
++#define MCP_FTMCP100_0_PA_BASE	0x92000000
++#define MCP_FTMCP100_0_PA_LIMIT	0x920FFFFF
++#define MCP_FTMCP100_0_PA_SIZE	0x00100000
++
++/* IR_DET */
++#define IR_DET_FTIRDET_PA_COUNT	1
++#define IR_DET_FTIRDET_PA_BASE	0x99C00000
++#define IR_DET_FTIRDET_PA_LIMIT	0x99C00FFF
++#define IR_DET_FTIRDET_PA_SIZE	0x00001000
++#define IR_DET_FTIRDET_0_PA_BASE	0x99C00000
++#define IR_DET_FTIRDET_0_PA_LIMIT	0x99C00FFF
++#define IR_DET_FTIRDET_0_PA_SIZE	0x00001000
++
++/* ADC */
++#define ADC_WRAP_PA_COUNT	2
++#define ADC_WRAP_PA_BASE	0x98B00000
++#define ADC_WRAP_PA_LIMIT	0x98B00FFF
++#define ADC_WRAP_PA_SIZE	0x00001000
++#define ADC_WRAP_0_PA_BASE	0x98B00000
++#define ADC_WRAP_0_PA_LIMIT	0x98B00FFF
++#define ADC_WRAP_0_PA_SIZE	0x00001000
++#define ADC_WRAP_1_PA_BASE	0x98F00000
++#define ADC_WRAP_1_PA_LIMIT	0x98F00FFF
++#define ADC_WRAP_1_PA_SIZE	0x00001000
++
++/* DMAC020 */
++#define DMAC_FTDMAC020_PA_COUNT 1
++#define DMAC_FTDMAC020_PA_BASE  0x92600000
++#define DMAC_FTDMAC020_PA_LIMIT 0x92600FFF
++#define DMAC_FTDMAC020_PA_SIZE  0x00001000
++#define DMAC_FTDMAC020_0_PA_BASE	0x92600000
++#define DMAC_FTDMAC020_0_PA_LIMIT	0x92600FFF
++#define DMAC_FTDMAC020_0_PA_SIZE	0x00001000
++
++/* APBB */
++#define APBB_FTAPBB020_PA_COUNT		3
++#define APBB_FTAPBB020_PA_BASE		0x92A00000
++#define APBB_FTAPBB020_PA_LIMIT		0x92A00FFF
++#define APBB_FTAPBB020_PA_SIZE		0x00001000
++#define APBB_FTAPBB020_0_PA_BASE	0x92A00000
++#define APBB_FTAPBB020_0_PA_LIMIT	0x92A00FFF
++#define APBB_FTAPBB020_0_PA_SIZE	0x00001000
++#define APBB_FTAPBB020_1_PA_BASE	0x9A000000
++#define APBB_FTAPBB020_1_PA_LIMIT	0x9A000FFF
++#define APBB_FTAPBB020_1_PA_SIZE	0x00001000
++
++/* DDRC */
++#define DDRC_FTDDRC010_PA_COUNT	1
++#define DDRC_FTDDRC010_PA_BASE	0x99300000
++#define DDRC_FTDDRC010_PA_LIMIT	0x99300FFF
++#define DDRC_FTDDRC010_PA_SIZE	0x00001000
++
++/* KPD */
++#define KPD_FTKPD_PA_COUNT	1
++#define KPD_FTKPD_PA_BASE	0x99D00000
++#define KPD_FTKPD_PA_LIMIT	0x99D00FFF
++#define KPD_FTKPD_PA_SIZE	0x00001000
++
++/*
++ * IRQ/FIQ trigger level and trigger mode
++ */
++#define PLATFORM_IRQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL1	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE1	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL1	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL2	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE2	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL2	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL3	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE3	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL3	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL4	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE4	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL4	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL5	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE5	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL5	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL6	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE6	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL6	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL7	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE7	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL7	0xFFFFFFFF
++
++#define PLATFORM_IRQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_IRQ_TRIGGER_LEVEL8	0xFFFFFFFF
++#define PLATFORM_FIQ_TRIGGER_MODE8	0x00000000
++#define PLATFORM_FIQ_TRIGGER_LEVEL8	0xFFFFFFFF
++
++#endif /* __PLATFORM_IO_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/pmu.h b/arch/arm/mach-GM/include/mach/platform-GM8287/pmu.h
+new file mode 100644
+index 00000000..622b30a8
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/pmu.h
+@@ -0,0 +1,30 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform/pmu.h
++ *
++ *  Copyright (C) 2009 Faraday Technology.
++ *
++ * 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
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++unsigned int pmu_get_apb0_clk(void);
++unsigned int pmu_get_apb1_clk(void);
++unsigned int pmu_get_apb2_clk(void);
++int platform_check_flash_type(void);
++void pmu_earlyinit(void __iomem *base);
++
++#endif	/* __PMU_H__ */
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/serial.h b/arch/arm/mach-GM/include/mach/platform-GM8287/serial.h
+new file mode 100644
+index 00000000..fa1fd6f0
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/serial.h
+@@ -0,0 +1,64 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM/serial.h
++ *
++ *  Serial port definition
++ *
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Note
++ *
++ *  There are 4 UARTs (FTUART010) in GM platform
++ *
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ *  Luke Lee  11/16/2005  Add conditional compilation.
++ */
++
++#define CONFIG_UART_CLK			25000000
++
++     /* UART CLK        PORT                      IRQ                   FLAGS       hub6 io_type iomem_base reg_shift*/
++#ifdef CONFIG_SERIAL_UART1_IP
++#define EXTENDED_UART_1 \
++     { 0, BASE_BAUD, UART_FTUART010_1_VA_BASE, UART_FTUART010_1_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS1 */
++#else
++#define EXTENDED_UART_1 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART2_IP
++#define EXTENDED_UART_2 \
++     { 0, BASE_BAUD, UART_FTUART010_2_VA_BASE, UART_FTUART010_2_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS2 */
++#else
++#define EXTENDED_UART_2 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#ifdef CONFIG_SERIAL_UART3_IP
++#define EXTENDED_UART_3 \
++     { 0, BASE_BAUD, UART_FTUART010_3_VA_BASE, UART_FTUART010_3_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS3 */
++#else
++#define EXTENDED_UART_3 \
++     { 0, 0, 0, 0, 0, 0, 0, NULL, 0 },
++#endif
++
++#define PLATFORM_MORE_SERIAL_PORTS \
++        EXTENDED_UART_1            \
++        EXTENDED_UART_2            \
++        EXTENDED_UART_3
++
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/system.h b/arch/arm/mach-GM/include/mach/platform-GM8287/system.h
+new file mode 100644
+index 00000000..d82e7383
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/system.h
+@@ -0,0 +1,77 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-a320/system.h
++ *  
++ *  Faraday Platform Dependent System Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *
++ * Description
++ *
++ *  This file is an example for all Faraday platforms that how to define
++ *  a non-macro inline function while still be able to be checked by
++ *  '#ifdef' or '#ifndef' preprocessor compilation directives.
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/22/2005  Created.
++ */
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++
++#ifndef __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__
++
++/*
++ * Define the macro name exactly the same as the function name,
++ * so that it can be checked by '#ifdef'. When this macro is
++ * expanded, it is expanded to itself.
++ */
++#define arch_reset arch_reset
++static inline void arch_reset(char mode, const char *cmd)
++{
++#define BIT13 (0x1<<13)
++    void __iomem *wdt_va_base = NULL;
++    int rst_fd = -1;
++    pmuReg_t regRSTArray[] = {
++    	/* reg_off,bit_masks,lock_bits,init_val,init_mask */
++	{0xB8, BIT13, BIT13, 0, BIT13},
++    };
++    pmuRegInfo_t rst_clk_info = {
++    	"rst_clk",
++	ARRAY_SIZE(regRSTArray),
++	ATTR_TYPE_NONE,
++	regRSTArray,
++    };
++
++    wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++    if (!wdt_va_base) {
++        printk(KERN_INFO "Remap is failed\n");
++        return;
++    }
++
++    //outw((~(0x1<<15)), (PMU_FTPMU010_VA_BASE + 0x3C));
++    rst_fd = ftpmu010_register_reg(&rst_clk_info);
++    writeb(0, (wdt_va_base + 0x0C)); //reset WDT ctrl reg
++    writel(0, (wdt_va_base + 0x04));//load margin conter
++    writel(0x5ab9, (wdt_va_base + 0x08)); /*Magic number*/
++    writeb(0x03, (wdt_va_base + 0x0C)); /*Enable WDT */
++}
++
++#endif /* __GM_PLATFORM_DEPENDENT_SYSTEM_HEADER__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/platform-GM8287/vmalloc.h b/arch/arm/mach-GM/include/mach/platform-GM8287/vmalloc.h
+new file mode 100644
+index 00000000..e31b9512
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/platform-GM8287/vmalloc.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-GM/include/mach/platform-GM8287/vmalloc.h
++ *  
++ *  Faraday Platform Dependent Virtual Memory Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  10/06/2005  Created
++ */
++
++#ifndef __GM_PLATFORM_VMALLOC_HEADER__
++#define __GM_PLATFORM_VMALLOC_HEADER__
++
++/* Note: this file is deprecated.
++ *
++ * I leave this file for reference only. Its defintion is in arch/arm/include/asm/pgtable.h
++ */
++#define VMALLOC_END	0xff000000
++
++#endif /* __GM_PLATFORM_VMALLOC_HEADER__ */
+diff --git a/arch/arm/mach-GM/include/mach/serial.h b/arch/arm/mach-GM/include/mach/serial.h
+new file mode 100644
+index 00000000..8e282348
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/serial.h
+@@ -0,0 +1,64 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/serial.h
++ *  
++ *  Platform Independent UART Console Configuration
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * Note
++ *
++ *  The first UART (FTUART010) in the system is used as the console.
++ * 
++ * ChangeLog
++ *
++ *  Luke Lee  09/15/2005  Created.
++ */
++
++#ifndef __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__
++#define __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__
++
++#ifndef __ASSEMBLY__
++
++#include <mach/platform/board.h>
++#include <linux/serial.h>
++/* Include platform *dependent* UART console configuration */
++#include <mach/platform/serial.h>
++
++#ifndef STD_COM_FLAGS
++#define STD_COM_FLAGS  (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
++#endif
++
++#ifndef PLATFORM_MORE_SERIAL_PORTS
++#define PLATFORM_MORE_SERIAL_PORTS
++#endif
++
++#ifndef SERIAL_PORT_DFNS
++     /* UART CLK        PORT                 IRQ                 FLAGS          hub6 io_type iomem_base reg_shift*/
++#define SERIAL_PORT_DFNS	\
++     { 0, BASE_BAUD, UART_FTUART010_0_VA_BASE, UART_FTUART010_0_IRQ, STD_COM_FLAGS,   0,    0,     NULL,       2 }, /* ttyS0 */ \
++     PLATFORM_MORE_SERIAL_PORTS
++#endif
++
++/*
++ * We use a 18.432MHz clock rather than typical 1.8432 MHz clock for UART.
++ */
++#define BASE_BAUD       (CONFIG_UART_CLK / 16)
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __FARADAY_PLATFORM_INDEPENDENT_SERIAL_HEADER__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/system.h b/arch/arm/mach-GM/include/mach/system.h
+new file mode 100644
+index 00000000..20dfbefd
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/system.h
+@@ -0,0 +1,49 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/system.h
++ *  
++ *  Faraday Platform Independent System Definitions
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ */
++
++#ifndef __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__
++#define __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__
++
++/* Include platform *dependent* system definitions */
++#include <mach/platform/system.h>
++
++#include <asm/proc-fns.h>
++#ifndef arch_idle
++static inline void arch_idle(void)
++{
++	cpu_do_idle();
++}
++#endif
++
++#ifndef arch_reset
++extern inline void arch_reset(char mode, const char *cmd)
++{
++	/* NOP */
++}
++#endif
++
++#endif /* __GM_PLATFORM_INDEPENDENT_SYSTEM_HEADER__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/timex.h b/arch/arm/mach-GM/include/mach/timex.h
+new file mode 100644
+index 00000000..24672316
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/timex.h
+@@ -0,0 +1,33 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/timex.h
++ *  
++ *  Faraday Platform Independent Clock Tick Rate Definition
++ *  
++ *  Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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
++ *  
++ * ChangeLog
++ *
++ *  Luke Lee  09/16/2005  Created.
++ */
++
++#ifndef __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__
++#define __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__
++
++#define CLOCK_TICK_RATE	CONFIG_CLOCK_TICK_RATE
++
++#endif /* __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__ */
++
+diff --git a/arch/arm/mach-GM/include/mach/uncompress.h b/arch/arm/mach-GM/include/mach/uncompress.h
+new file mode 100644
+index 00000000..9766482e
+--- /dev/null
++++ b/arch/arm/mach-GM/include/mach/uncompress.h
+@@ -0,0 +1,51 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/uncompress.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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 <mach/platform/board.h>
++
++#define SERIAL_THR	0x00
++#define SERIAL_LSR	0x14
++#define SERIAL_LSR_THRE	0x20
++
++#define readl(a)	(*(volatile unsigned int *)(a))
++#define writel(v,a)	(*(volatile unsigned int *)(a) = (v))
++
++/*
++ * This does not append a newline
++ */
++static inline void putc(int c)
++{
++	unsigned long base = DEBUG_LL_FTUART010_PA_BASE;
++
++	while ((readl(base + SERIAL_LSR) & SERIAL_LSR_THRE) == 0)
++		barrier();
++
++	writel(c, base + SERIAL_THR);
++}
++
++static inline void flush(void)
++{
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
+diff --git a/arch/arm/mach-GM/platform-GM8126/Kconfig b/arch/arm/mach-GM/platform-GM8126/Kconfig
+new file mode 100644
+index 00000000..d657d206
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8126/Kconfig
+@@ -0,0 +1,22 @@
++#
++# arch/arm/mach-GM/platform-GM8126/Kconfig
++
++if PLATFORM_GM8126
++
++#config SYS_CLK
++config CLOCK_TICK_RATE	
++        int "AHB System Clock"
++        default 240000000
++        help
++          Manual setting of AHB clock, must match the jumper setting on
++          the board, or the system time won't be correctly calculated.
++          Notice that even when AUTO_SYS_CLK is ON, this value is still
++          required for adjusting minor time offsets. However, the influence
++          should be within micro-second to nano-second scale.
++
++config FTINTC010EX
++	bool "FTINTC010EX supports 64 IRQs"
++	default y
++
++endif
++
+diff --git a/arch/arm/mach-GM/platform-GM8126/Makefile b/arch/arm/mach-GM/platform-GM8126/Makefile
+new file mode 100644
+index 00000000..beb66a1b
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8126/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the GM platform dependent files
++
++# Object file lists.
++
++obj-y		:= board.o pmu.o timer_fixup.o platform.o
++
+diff --git a/arch/arm/mach-GM/platform-GM8126/board.c b/arch/arm/mach-GM/platform-GM8126/board.c
+new file mode 100644
+index 00000000..3c55cbda
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8126/board.c
+@@ -0,0 +1,187 @@
++/*
++ *  board depdenent initialization
++ *  
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/setup.h>
++#include <mach/platform/board.h>
++#include <mach/platform/pmu.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftintc010.h>
++#include <mach/fttmr010.h>
++#include <mach/fmem.h>
++#include <linux/dma-mapping.h> /* NISH_20121015 add for init_consistent_dma_size() */
++
++/* External functions and variables declaration
++ */
++extern void platform_devices_init(void);
++
++/* Local variables declaration
++ */
++void __iomem *ftintc010_base_addr;
++
++/******************************************************************************
++ * IPs virtual address mapping
++ *****************************************************************************/
++static struct map_desc board_io_desc[] __initdata = {
++    /* PMU */
++    {
++        .virtual	= PMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PMU_FTPMU010_PA_BASE),
++		.length		= PMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART0 */
++    {
++        .virtual	= UART_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_0_PA_BASE),
++		.length		= UART_FTUART010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* TIMER */
++    {
++        .virtual	= TIMER_FTTMR010_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_PA_BASE),
++		.length		= TIMER_FTTMR010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC */
++    {
++        .virtual	= INTC_FTINTC010_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC010_PA_BASE),
++		.length		= INTC_FTINTC010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++};
++
++/* fixup the memory for MACHINE_START. The parameters come from commandline of menuconfig
++ */
++static void __init board_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    fmem_fixup_memory(tag, cmdline, mi);
++}    
++
++/* 2. create the iotable for IPs in MACHINE_START
++ */
++static void __init board_map_io(void) 
++{
++    iotable_init(&board_io_desc[0], ARRAY_SIZE(board_io_desc));
++    
++    /* set the base to pmu module */
++    pmu_earlyinit((void *)PMU_FTPMU010_VA_BASE);
++
++    /* init dma coherent mapping size,      
++     * CONSISTENT_DMA_SIZE is defined in memory.h     
++     * max allowable dma consistent size is 14M (0xFFE0_0000 - 0xFF00_00000)    
++     * set as 12M to avoid unexpected data overlay, NISH_20121015      
++     */
++    #ifdef CONSISTENT_DMA_SIZE	
++    init_consistent_dma_size(CONSISTENT_DMA_SIZE);    
++    #endif
++}
++
++static void __init board_init_irq(void)
++{        
++    struct ftintc010_trigger_type master_trigger_type = {
++		.irqmode	= PLATFORM_IRQ_TRIGGER_MODE2,
++		.irqlevel	= ~PLATFORM_IRQ_TRIGGER_LEVEL2,
++		.fiqmode	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel	= ~PLATFORM_FIQ_TRIGGER_LEVEL2,
++#ifdef CONFIG_FTINTC010EX
++        .irqmodeex	= PLATFORM_IRQ_TRIGGER_MODEEX2,
++		.irqlevelex	= ~PLATFORM_IRQ_TRIGGER_LEVELEX2,
++		.fiqmodeex	= PLATFORM_FIQ_TRIGGER_MODEEX2,
++		.fiqlevelex	= ~PLATFORM_FIQ_TRIGGER_LEVELEX2,
++#endif
++	};
++    
++	/*
++	 * initialize primary interrupt controller
++	 */
++	ftintc010_base_addr = __io(INTC_FTINTC010_VA_BASE);
++	ftintc010_init(0, ftintc010_base_addr, 0, &master_trigger_type);
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {	
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 1,
++};
++
++static void __init board_sys_timer_init(void)
++{
++    unsigned int pclk = pmu_get_apb_clk();
++
++	fttmr010_0_clockevent.freq = pclk;
++	fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++	fttmr010_1_clocksource.freq = pclk;
++	fttmr010_clocksource_init(&fttmr010_1_clocksource);
++}
++
++struct sys_timer board_sys_timer = {
++	.init	= board_sys_timer_init,
++};
++
++/* board init */
++static void __init board_init_machine(void)
++{
++    int i;
++    
++    platform_devices_init();
++#ifdef CONFIG_GM_PHY    
++    //set PHY ID
++    outl(0x321123, PMU_FTPMU010_VA_BASE + 0x88);	
++#endif    
++    
++    /* dump iotable information 
++     */
++    for (i = 0; i < ARRAY_SIZE(board_io_desc); i ++) {
++        printk("iotable: VA: 0x%x, PA: 0x%x, Length: %d \n", 
++                (u32)board_io_desc[i].virtual, 
++                (u32)board_io_desc[i].pfn << PAGE_SHIFT,
++                (u32)board_io_desc[i].length);
++    }
++}
++
++MACHINE_START(GM, BOARD_NAME)
++	.atag_offset	= BOOT_PARAMETER_PA_BASE,   //boot command line
++	.map_io		    = board_map_io,
++	.init_irq	    = board_init_irq,
++	.timer		    = &board_sys_timer,
++	.fixup          = board_fixup_memory,
++	.init_machine	= board_init_machine,
++MACHINE_END
+diff --git a/arch/arm/mach-GM/platform-GM8126/platform.c b/arch/arm/mach-GM/platform-GM8126/platform.c
+new file mode 100644
+index 00000000..4acf4099
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8126/platform.c
+@@ -0,0 +1,185 @@
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach-types.h>
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++/* i2c:0 */ 
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start  = I2C_FTI2C010_0_PA_BASE,
++		.end    = I2C_FTI2C010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_0_IRQ,
++		.end	= I2C_FTI2C010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		    = 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++
++/******************************************************************************
++ * MAC devices
++ *****************************************************************************/
++/*MAC 0*/
++static struct resource ftmac110_0_resource[] = {
++	{
++         	.start  = MAC_FTMAC110_PA_BASE,
++         	.end   	= MAC_FTMAC110_PA_LIMIT,
++         	.flags  = IORESOURCE_MEM,
++	},
++	{
++         	.start  = MAC_FTMAC110_IRQ,
++         	.end   	= MAC_FTMAC110_IRQ,
++         	.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 ftmac100_0_dmamask = 0xFFFFFFUL;
++static struct platform_device ftmac100_0_device = {
++	.name		= "ftmac110",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftmac110_0_resource),
++	.resource	= ftmac110_0_resource,
++	.dev = {
++		.dma_mask = &ftmac100_0_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},	
++};
++
++/******************************************************************************
++ * OTG devices
++ *****************************************************************************/
++/* OTG:0 */
++static struct resource fotg210_0_resources[] = {
++	{
++		.start  = USB_FOTG2XX_0_PA_BASE,
++		.end    = USB_FOTG2XX_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_0_IRQ,
++		.end    = USB_FOTG2XX_0_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_0_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_0_device = {
++	.name           = "fotg210",
++	.id             = -1,
++	.num_resources  = ARRAY_SIZE(fotg210_0_resources),
++	.resource       = fotg210_0_resources,
++	.dev = {
++		.dma_mask = &fotg210_0_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/******************************************************************************
++ * GPIO devices
++ *****************************************************************************/
++/* GPIO 0 */
++static struct resource ftgpio010_0_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_PA_BASE,
++		.end 	= GPIO_FTGPIO010_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_0_IRQ,
++		.end	= GPIO_FTGPIO010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_0_device = {
++	.name	= "ftgpio010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgpio010_0_resource),
++	.resource	= ftgpio010_0_resource
++};
++
++/* GPIO 1 */
++static struct resource ftgpio010_1_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_1_PA_BASE,
++		.end 	= GPIO_FTGPIO010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_1_IRQ,
++		.end	= GPIO_FTGPIO010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_1_device = {
++	.name	= "ftgpio010",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgpio010_1_resource),
++	.resource	= ftgpio010_1_resource
++};
++
++/* GPIO 2 */
++static struct resource ftgpio010_2_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_2_PA_BASE,
++		.end 	= GPIO_FTGPIO010_2_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_2_IRQ,
++		.end	= GPIO_FTGPIO010_2_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_2_device = {
++	.name	= "ftgpio010",
++	.id		= 2,
++	.num_resources	= ARRAY_SIZE(ftgpio010_2_resource),
++	.resource	= ftgpio010_2_resource
++};
++
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/ 
++static struct platform_device *gm_devices[] __initdata = 
++{
++	/* I2C */
++	&ftiic010_0_device,
++	/* MAC */	
++	&ftmac100_0_device,	
++	/* OTG */
++	&fotg210_0_device,
++	/* GPIO */
++	&ftgpio010_0_device,
++	&ftgpio010_1_device,
++	&ftgpio010_2_device,
++};
++
++void __init platform_devices_init(void)
++{
++    /* add platform devices here 
++     */
++     
++    /* will invoke platform_device_register() to register all platform devices 
++     */
++	platform_add_devices(gm_devices, ARRAY_SIZE(gm_devices));
++}
++
+diff --git a/arch/arm/mach-GM/platform-GM8126/pmu.c b/arch/arm/mach-GM/platform-GM8126/pmu.c
+new file mode 100644
+index 00000000..0f84609e
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8126/pmu.c
+@@ -0,0 +1,255 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++
++#define SYS_CLK 30000000    /* 30Mhz */
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++static int gpio_fd = -1;
++static int dmac_fd = -1;
++
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x3C, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)},
++    {0x44, (0xF << 12), (0xF << 12), (0x1 << 12), (0x1 << 12)},
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk", 
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* GPIO
++ */ 
++static pmuReg_t regGPIOArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x3C, (0x7 << 9), (0x7 << 9), (0x0 << 9), (0x7 << 9)},
++};
++
++static pmuRegInfo_t gpio_clk_info = {
++    "gpio_clk", 
++    ARRAY_SIZE(regGPIOArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regGPIOArray
++};
++
++/* DMAC 
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x38, (0x1 << 11), (0x1 << 11), (0x0 << 11), (0x1 << 11)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "DMAC_CLK", 
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regDMACArray
++};
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++
++	/*
++	 * Version ID:
++	 *     812610: 8126
++	 *     812620: 8126 MP
++     *     812621: 8128
++	 */
++	if (!version) {	    
++	    version = ioread32(pmu_base_addr) >> 8;
++        switch (version)
++	    {
++	      case GM8126_TEST_CHIP_ID:
++	        printk("IC: GM8126 \n");
++	        break;
++	      case GM8126_MP2_CHIP_ID:
++	        printk("IC: GM8126 MP\n");
++	        break;
++          case GM8128_MP_CHIP_ID:
++            printk("IC: GM8128 MP\n");
++            break;  
++	      default:
++	        printk("IC: Uknown!!!!!! %x\n", version);
++	        break;
++        }
++	}
++
++	return version;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    if(pmu_get_version() == GM8126_TEST_CHIP_ID) {
++	    return ((readl(pmu_base_addr + 0x30)) >> 24) & 0xff;
++    } else {
++        return ((readl(pmu_base_addr + 0x30)) >> 25) & 0xff;
++    }
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++	u32 mul, div;
++
++    if(pmu_get_version() == GM8126_TEST_CHIP_ID) {
++        mul = (readl(pmu_base_addr + 0x30) >>  3) & 0x1ff;
++        div = (readl(pmu_base_addr + 0x30) >> 12) & 0x1f;
++    } else {
++        mul = (readl(pmu_base_addr + 0x30) >>  4) & 0x1ff;
++        div = (readl(pmu_base_addr + 0x30) >> 13) & 0x1f;
++    }
++
++	return (SYS_CLK / div * mul);
++}
++
++static inline u32 pmu_read_pll2out(void)
++{
++	u32 mul, div;
++
++	mul = (readl(pmu_base_addr + 0x34) >> 3) & 0x1ff;
++	div = (readl(pmu_base_addr + 0x34) >> 12) & 0x1f;
++
++	return (SYS_CLK / div * mul);
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++	u32 fclk_mode, hclk_mode;
++	u32 pll1_out, pll2_out, hclk = 0, fclk = 0;
++	static u32 print_info_1st = 0;
++
++	pll1_out = pmu_read_pll1out();	
++    pll2_out = pmu_read_pll2out();
++	fclk_mode = (pmu_read_cpumode() >> 2) & 0x3;
++	hclk_mode = (pmu_read_cpumode() >> 0) & 0x3;
++
++	if (fclk_mode == 0)
++		fclk = pll1_out / 1;
++	else if (fclk_mode == 1)
++		fclk = pll1_out / 2;
++	else if (fclk_mode == 2)
++		fclk = (pll1_out * 2) / 3;
++	else
++		fclk = pll2_out;
++
++	if (hclk_mode == 0)
++		hclk = pll1_out / 1;
++	else if (hclk_mode == 1)
++		hclk = pll1_out / 2;
++	else if (hclk_mode == 2)
++		hclk = pll1_out / 3;
++	else
++		hclk = pll2_out / 2;
++
++	if (!print_info_1st++) {
++		printk("GM Clock: CPU = %d MHz, AHBCLK = %d MHz, PLL1CLK = %d MHz, PLL2CLK = %d MHz\n", 
++		    fclk / 1000000, hclk / 1000000, pll1_out/1000000, pmu_read_pll2out()/1000000);
++    }
++    
++	return hclk;
++}
++
++unsigned int pmu_get_apb_clk(void)
++{
++    return pmu_get_ahb_clk() / 2;
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    u32 fclk_mode;
++	u32 pll1_out, pll2_out, fclk = 0;
++	
++	pll1_out = pmu_read_pll1out();
++    pll2_out = pmu_read_pll2out();
++    fclk_mode = (pmu_read_cpumode() >> 4) & 0x3;
++printk("%s:%d <fclk_mode=%d, pll2_out=%d>\n",__FUNCTION__,__LINE__, fclk_mode, pll2_out);
++	
++	if (fclk_mode == 0)
++		fclk = pll1_out / 1;
++	else if (fclk_mode == 1)
++		fclk = pll1_out / 2;
++	else if (fclk_mode == 2)
++		fclk = (pll1_out * 2) / 3;
++	else
++		fclk = pll2_out;
++
++	return fclk;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk}, 
++    {{"pclk",   ATTR_TYPE_APB,    0}, pmu_get_apb_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll2",   ATTR_TYPE_PLL2,   0}, pmu_read_pll2out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++};
++
++static int __init pmu_postinit(void)
++{    
++    int i;
++    
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++        
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, NULL, NULL);
++    
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++        
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++    
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++    
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("DMAC registers to PMU fail! \n");
++    }
++
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file 
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM/platform-GM8126/timer_fixup.c b/arch/arm/mach-GM/platform-GM8126/timer_fixup.c
+new file mode 100644
+index 00000000..19f4b378
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8126/timer_fixup.c
+@@ -0,0 +1,126 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/ftpmu010.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/fiq.h>
++#include <mach/platform/board.h>
++
++#define CONFIG_MAX_TICK     0xffffffff
++static int timer_init_ready = 0;
++
++/*
++ * Get the max ms the this timer
++ */
++unsigned int video_gettime_max_ms(void)
++{
++    return (CONFIG_MAX_TICK / APB_CLK_IN) * 1000;
++}
++
++/* calculate the max hz in max_ms
++ */
++unsigned int video_gettime_max_hz(void)
++{
++    unsigned int max_hz;
++    
++    /* calculate the max hz in max_ms */
++    max_hz = (video_gettime_max_ms() * APB_CLK_IN) / 1000;
++    
++    return max_hz;
++}
++
++unsigned int video_gettime_ms(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++unsigned int video_gettime_us(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++/*
++ * Entry Point of this module. It may be declared by arch_initcall section
++ */
++static int __init fixup_timer_init(void)
++{
++    //use timer3, 42s will overflow in AHB clock 200HZ
++    unsigned int ft_apb_clk = APB_CLK_IN;
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++    unsigned int max_tick;
++    
++    if (*(unsigned int *)(timer_base + 0x30) & (0x1 << 6))
++    {
++        printk("Timer3 is alredy been used!\n");
++        return 0;
++    }
++
++    max_tick = (video_gettime_max_ms() / 1000) * ft_apb_clk;    //the max hz count in TmxCounter
++    
++    printk("Video Timer(timer3) Max %dms in 0x%x HZ.\n", video_gettime_max_ms(), max_tick);
++    
++    /* the following configuration is for TIMER3 */
++    *(volatile unsigned int *)(timer_base + 0x20) = CONFIG_MAX_TICK - max_tick; //keep the start count in start counter
++    *(volatile unsigned int *)(timer_base + 0x24) = CONFIG_MAX_TICK - max_tick; //reLoad counter
++    *(volatile unsigned int *)(timer_base + 0x38) |= (0x7 << 6);   //IRQ disable
++    *(volatile unsigned int *)(timer_base + 0x30) |= ((0x1 << 6) | (0x1 << 11));    //enable timer3, count up
++    timer_init_ready = 1;
++    
++    return 0;
++}
++
++static void fixup_timer_exit(void)
++{
++    if (timer_init_ready == 1)
++    {
++        unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        *(volatile unsigned int *)(timer_base + 0x30) &= ~(0x1 << 6);//disable timer2, count up
++        timer_init_ready = 0;
++    }
++	printk("%s: cleaning up\n",__func__);
++}
++
++module_init(fixup_timer_init);
++module_exit(fixup_timer_exit);
++
++EXPORT_SYMBOL(video_gettime_ms);
++EXPORT_SYMBOL(video_gettime_us);
++EXPORT_SYMBOL(video_gettime_max_ms);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("FIXUP timer driver");
+diff --git a/arch/arm/mach-GM/platform-GM8136/Kconfig b/arch/arm/mach-GM/platform-GM8136/Kconfig
+new file mode 100644
+index 00000000..28802e40
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8136/Kconfig
+@@ -0,0 +1,33 @@
++#
++# arch/arm/mach-GM/platform-GM8136/Kconfig
++
++if PLATFORM_GM8136
++
++#config SYS_CLK
++config CLOCK_TICK_RATE	
++        int "AHB System Clock"
++        default 240000000
++        help
++          Manual setting of AHB clock, must match the jumper setting on
++          the board, or the system time won't be correctly calculated.
++          Notice that even when AUTO_SYS_CLK is ON, this value is still
++          required for adjusting minor time offsets. However, the influence
++          should be within micro-second to nano-second scale.
++
++config FTINTC030
++	bool "FTINTC030 support"
++	default y
++
++config FPGA
++	bool "FPGA Verify"
++	default n
++
++config VIDEO_FASTTHROUGH
++	bool "Video Fast Through"
++	default y
++	help
++	  When this function is on, video related drivers need to work in
++	  atomic context for fast passing job to next stage.
++
++endif
++
+diff --git a/arch/arm/mach-GM/platform-GM8136/Makefile b/arch/arm/mach-GM/platform-GM8136/Makefile
+new file mode 100644
+index 00000000..beb66a1b
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8136/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the GM platform dependent files
++
++# Object file lists.
++
++obj-y		:= board.o pmu.o timer_fixup.o platform.o
++
+diff --git a/arch/arm/mach-GM/platform-GM8136/board.c b/arch/arm/mach-GM/platform-GM8136/board.c
+new file mode 100644
+index 00000000..8f413f83
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8136/board.c
+@@ -0,0 +1,249 @@
++/*
++ *  board depdenent initialization
++ *
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/setup.h>
++#include <mach/platform/board.h>
++#include <mach/platform/pmu.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/system.h>
++#include <mach/ftintc030.h>
++#include <mach/fttmr010.h>
++#include <mach/fmem.h>
++#include <linux/dma-mapping.h>
++
++#if 0//def CONFIG_CACHE_FTL2CC031
++#include <asm/hardware/cache-ftl2cc031.h>
++#endif
++
++/* External functions and variables declaration
++ */
++extern void platform_devices_init(void);
++
++/* Local variables declaration
++ */
++void __iomem *ftintc030_base_addr;
++void __iomem *ftintc030_base_cpu_0_irq_base; //entry-macro.S will reference it
++
++/******************************************************************************
++ * IPs virtual address mapping
++ *****************************************************************************/
++static struct map_desc board_io_desc[] __initdata = {
++    /* PMU */
++    {
++        .virtual	= PMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PMU_FTPMU010_PA_BASE),
++		.length		= PMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART0 */
++    {
++        .virtual	= UART_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_0_PA_BASE),
++		.length		= UART_FTUART010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART1 */
++    {
++        .virtual	= UART_FTUART010_1_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_1_PA_BASE),
++		.length		= UART_FTUART010_1_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART2 */
++    {
++        .virtual	= UART_FTUART010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_2_PA_BASE),
++		.length		= UART_FTUART010_2_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* TIMER */
++    {
++        .virtual	= TIMER_FTTMR010_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_PA_BASE),
++		.length		= TIMER_FTTMR010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC030 */
++    {
++        .virtual	= INTC_FTINTC030_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC030_PA_BASE),
++		.length		= INTC_FTINTC030_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#if 0//def CONFIG_CACHE_FTL2CC031
++    /* L2 cache */
++	{
++		.virtual	= L2CACHE_FTL2CC031_VA_BASE,
++		.pfn		= __phys_to_pfn(L2CACHE_FTL2CC031_PA_BASE),
++		.length		= L2CACHE_FTL2CC031_VA_SIZE,
++		.type		= MT_DEVICE,
++	},
++#endif
++};
++
++/* fixup the memory for MACHINE_START. The parameters come from commandline of menuconfig
++ */
++static void __init board_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    fmem_fixup_memory(tag, cmdline, mi);
++}
++
++/* 2. create the iotable for IPs in MACHINE_START
++ */
++static void __init board_map_io(void)
++{
++    iotable_init(&board_io_desc[0], ARRAY_SIZE(board_io_desc));
++
++    /* set the base to pmu module */
++    pmu_earlyinit((void *)PMU_FTPMU010_VA_BASE);
++
++    /* init dma coherent mapping size,
++     * CONSISTENT_DMA_SIZE is defined in memory.h
++     * max allowable dma consistent size is 14M (0xFFE0_0000 - 0xFF00_00000)
++     * set as 12M to avoid unexpected data overlay, NISH_20121015
++     */
++    #ifdef CONSISTENT_DMA_SIZE
++    init_consistent_dma_size(CONSISTENT_DMA_SIZE);
++    #endif
++}
++
++static void __init board_init_irq(void)
++{
++	struct ftintc030_trigger_type trigger_type = {
++		.irqmode[0]	= PLATFORM_IRQ_TRIGGER_MODE1,
++		.irqlevel[0]	= ~PLATFORM_IRQ_TRIGGER_LEVEL1,
++		.fiqmode[0]	= PLATFORM_FIQ_TRIGGER_MODE1,
++		.fiqlevel[0]	= ~PLATFORM_FIQ_TRIGGER_LEVEL1,
++
++		.irqmode[1]	= PLATFORM_IRQ_TRIGGER_MODE2,
++		.irqlevel[1]	= ~PLATFORM_IRQ_TRIGGER_LEVEL2,
++		.fiqmode[1]	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel[1]	= ~PLATFORM_FIQ_TRIGGER_LEVEL2,
++
++		.irqmode[2]	= PLATFORM_IRQ_TRIGGER_MODE3,
++		.irqlevel[2]	= ~PLATFORM_IRQ_TRIGGER_LEVEL3,
++		.fiqmode[2]	= PLATFORM_FIQ_TRIGGER_MODE3,
++		.fiqlevel[2]	= ~PLATFORM_FIQ_TRIGGER_LEVEL3,
++
++		.irqmode[3]	= PLATFORM_IRQ_TRIGGER_MODE4,
++		.irqlevel[3]	= ~PLATFORM_IRQ_TRIGGER_LEVEL4,
++		.fiqmode[3]	= PLATFORM_FIQ_TRIGGER_MODE4,
++		.fiqlevel[3]	= ~PLATFORM_FIQ_TRIGGER_LEVEL4,
++
++		.irqmode[4]	= PLATFORM_IRQ_TRIGGER_MODE5,
++		.irqlevel[4]	= ~PLATFORM_IRQ_TRIGGER_LEVEL5,
++		.fiqmode[4]	= PLATFORM_FIQ_TRIGGER_MODE5,
++		.fiqlevel[4]	= ~PLATFORM_FIQ_TRIGGER_LEVEL5,
++
++		.irqmode[5]	= PLATFORM_IRQ_TRIGGER_MODE6,
++		.irqlevel[5]	= ~PLATFORM_IRQ_TRIGGER_LEVEL6,
++		.fiqmode[5]	= PLATFORM_FIQ_TRIGGER_MODE6,
++		.fiqlevel[5]	= ~PLATFORM_FIQ_TRIGGER_LEVEL6,
++
++		.irqmode[6]	= PLATFORM_IRQ_TRIGGER_MODE7,
++		.irqlevel[6]	= ~PLATFORM_IRQ_TRIGGER_LEVEL7,
++		.fiqmode[6]	= PLATFORM_FIQ_TRIGGER_MODE7,
++		.fiqlevel[6]	= ~PLATFORM_FIQ_TRIGGER_LEVEL7,
++
++		.irqmode[7]	= PLATFORM_IRQ_TRIGGER_MODE8,
++		.irqlevel[7]	= ~PLATFORM_IRQ_TRIGGER_LEVEL8,
++		.fiqmode[7]	= PLATFORM_FIQ_TRIGGER_MODE8,
++		.fiqlevel[7]	= ~PLATFORM_FIQ_TRIGGER_LEVEL8,
++	};
++
++	/*
++	 * initialize primary interrupt controller
++	 */
++	ftintc030_base_addr = __io(INTC_FTINTC030_VA_BASE);
++	ftintc030_base_cpu_0_irq_base = __io(INTC_FTINTC030_VA_BASE + FTINTC030_OFFSET_CPU_0_IRQ);
++
++	ftintc030_init(0, ftintc030_base_addr, 0, &trigger_type);
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 1,
++};
++
++static void __init board_sys_timer_init(void)
++{
++    unsigned int pclk = pmu_get_apb_clk();
++
++	fttmr010_0_clockevent.freq = pclk;
++	fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++	fttmr010_1_clocksource.freq = pclk;
++	fttmr010_clocksource_init(&fttmr010_1_clocksource);
++}
++
++struct sys_timer board_sys_timer = {
++	.init	= board_sys_timer_init,
++};
++
++/* board init */
++static void __init board_init_machine(void)
++{
++    int i;
++
++    platform_devices_init();
++
++    /* dump iotable information
++     */
++    for (i = 0; i < ARRAY_SIZE(board_io_desc); i ++) {
++        printk(KERN_INFO "iotable: VA: 0x%x, PA: 0x%x, Length: %d \n",
++                (u32)board_io_desc[i].virtual,
++                (u32)board_io_desc[i].pfn << PAGE_SHIFT,
++                (u32)board_io_desc[i].length);
++    }
++
++#if 0//def CONFIG_CACHE_FTL2CC031
++    /* 256 KB (32KB/way), 8-way associativity, parity enabled */
++	ftl2cc031_init(__io(L2CACHE_FTL2CC031_VA_BASE), (AUX_WAYSIZE(WAYSIZE_32KB) | AUX_PAR_CHK_EN | 0x23), 0xF3777);
++#endif
++}
++
++MACHINE_START(GM, BOARD_NAME)
++	.atag_offset	= BOOT_PARAMETER_PA_OFFSET,   //boot command line, after kernel 3.2 change as relative address
++	.map_io		    = board_map_io,
++	.init_irq	    = board_init_irq,
++	.timer		    = &board_sys_timer,
++	.fixup          = board_fixup_memory,
++	.init_machine	= board_init_machine,
++	.restart	= arch_reset,
++MACHINE_END
+diff --git a/arch/arm/mach-GM/platform-GM8136/platform.c b/arch/arm/mach-GM/platform-GM8136/platform.c
+new file mode 100644
+index 00000000..36edd619
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8136/platform.c
+@@ -0,0 +1,318 @@
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/dma-mapping.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach-types.h>
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++/* i2c:0 */
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start  = I2C_FTI2C010_0_PA_BASE,
++		.end    = I2C_FTI2C010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_0_IRQ,
++		.end	= I2C_FTI2C010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		    = 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++
++/******************************************************************************
++ * OTG devices
++ *****************************************************************************/
++#ifdef CONFIG_USB_SUPPORT
++/* OTG:0 */
++static struct resource fotg210_0_resources[] = {
++	{
++		.start  = USB_FOTG2XX_0_PA_BASE,
++		.end    = USB_FOTG2XX_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_0_IRQ,
++		.end    = USB_FOTG2XX_0_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_0_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_0_device = {
++	.name           = "fotg210",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(fotg210_0_resources),
++	.resource       = fotg210_0_resources,
++	.dev = {
++		.dma_mask = &fotg210_0_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif /* CONFIG_USB_SUPPORT */
++
++/******************************************************************************
++ * SDC devices
++ *****************************************************************************/
++/* FTSDC021 */
++#ifdef CONFIG_MMC_FTSDC021
++static u64 ftsdc021_dmamask = 0xFFFFFFUL;
++#endif
++#if defined(CONFIG_SDC0_IP)
++static struct resource ftsdc021_0_resource[] = {
++	[0] = {
++	       .start = SDC_FTSDC021_PA_BASE,
++	       .end = SDC_FTSDC021_PA_LIMIT,
++	       .flags = IORESOURCE_MEM,
++	       },
++	[1] = {
++	       .start = SDC_FTSDC021_0_IRQ,
++	       .end = SDC_FTSDC021_0_IRQ,
++	       .flags = IORESOURCE_IRQ,
++	       }
++};
++static struct platform_device ftsdc021_0_device = {
++	.name = "ftsdc021",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(ftsdc021_0_resource),
++	.resource = ftsdc021_0_resource,
++	.dev = {
++		.dma_mask = &ftsdc021_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif
++#if defined(CONFIG_SDC1_IP)
++static struct resource ftsdc021_1_resource[] = {
++        [0] = {
++               .start = SDC_FTSDC021_1_PA_BASE,
++               .end = SDC_FTSDC021_1_PA_LIMIT,
++               .flags = IORESOURCE_MEM,
++               },
++        [1] = {
++               .start = SDC_FTSDC021_1_IRQ,
++               .end = SDC_FTSDC021_1_IRQ,
++               .flags = IORESOURCE_IRQ,
++               }
++};
++static struct platform_device ftsdc021_1_device = {
++        .name = "ftsdc021",
++        .id = 1,
++        .num_resources = ARRAY_SIZE(ftsdc021_1_resource),
++        .resource = ftsdc021_1_resource,
++        .dev = {
++                .dma_mask = &ftsdc021_dmamask,
++                .coherent_dma_mask = 0xFFFFFFFF,
++        },
++};
++#endif
++
++/******************************************************************************
++ * GPIO devices
++ *****************************************************************************/
++/* GPIO 0 */
++static struct resource ftgpio010_0_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_PA_BASE,
++		.end 	= GPIO_FTGPIO010_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_0_IRQ,
++		.end	= GPIO_FTGPIO010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_0_device = {
++	.name	= "ftgpio010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgpio010_0_resource),
++	.resource	= ftgpio010_0_resource
++};
++
++/* GPIO 1 */
++static struct resource ftgpio010_1_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_1_PA_BASE,
++		.end 	= GPIO_FTGPIO010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_1_IRQ,
++		.end	= GPIO_FTGPIO010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_1_device = {
++	.name	= "ftgpio010",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgpio010_1_resource),
++	.resource	= ftgpio010_1_resource
++};
++
++/******************************************************************************
++ * AHB DMA controllers
++ *****************************************************************************/
++#ifdef CONFIG_FTDMAC020
++static struct resource ftdmac020_0_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_0_PA_BASE,
++		.end	= DMAC_FTDMAC020_0_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_0_IRQ,
++		.end    = DMAC_FTDMAC020_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_0_device = {
++	.name		= "ftdmac020",
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_0_resources),
++	.resource	= ftdmac020_0_resources,
++};
++#endif /* CONFIG_FTDMAC020 */
++
++/******************************************************************************
++ * SPI020 controllers
++ *****************************************************************************/
++#ifdef CONFIG_SPI_FTSPI020
++static struct resource ftspi020_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,     /* Register Base address */
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static u64 ftspi020_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftspi020_device = {
++    .name = "ftspi020",
++    .id = 0,//must match with bus_num
++    .num_resources = ARRAY_SIZE(ftspi020_resource),
++    .resource = ftspi020_resource,
++    .dev = {
++            .dma_mask = &ftspi020_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            },
++};
++#endif /* CONFIG_SPI_FTSPI020 */
++
++#ifdef CONFIG_SPI_FTSSP010
++static struct resource ftssp010_1_resources[] = {
++	{
++		.start	= SSP_FTSSP010_1_PA_BASE,
++		.end	= SSP_FTSSP010_1_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= SSP_FTSSP010_1_IRQ,
++		.end    = SSP_FTSSP010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftssp010_1_device = {
++	.name		= "ssp_spi",
++	.id		    = 1,
++	.num_resources	= ARRAY_SIZE(ftssp010_1_resources),
++	.resource	= ftssp010_1_resources,	
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++};
++
++static struct spi_board_info spi_devs_info[] __initdata = {
++    {
++            .modalias       = "spidev",//"imx138_spi",
++            .max_speed_hz   = 6000000,
++            .bus_num        = 1,    //use controller 1
++            .chip_select    = 0,    //chip select 0
++            .mode = SPI_MODE_3,
++    },
++#if 0
++    {
++            .modalias       = "device_1_spi",
++            .max_speed_hz   = 2000000,  //2MHz
++            .bus_num        = 1,    //use controller 1
++            .chip_select    = 1,    //chip select 1
++            .mode = SPI_MODE_3,
++    },
++    {
++            .modalias       = "device_2_spi",
++            .max_speed_hz   = 3000000,  //3MHz
++            .bus_num        = 1,    //use controller 1
++            .chip_select    = 2,    //chip select 2
++            .mode = SPI_MODE_3,
++    },
++#endif
++};
++#endif /* CONFIG_SPI_FTSSP010 */
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/
++static struct platform_device *gm_devices[] __initdata =
++{
++	/* I2C */
++	&ftiic010_0_device,
++	/* OTG */
++#ifdef CONFIG_USB_SUPPORT
++	&fotg210_0_device,
++#endif
++#if defined(CONFIG_SDC0_IP)
++    &ftsdc021_0_device,
++#endif
++#if defined(CONFIG_SDC1_IP)
++    &ftsdc021_1_device,
++#endif
++	/* GPIO */
++	&ftgpio010_0_device,
++	&ftgpio010_1_device,
++#ifdef CONFIG_FTDMAC020
++    &ftdmac020_0_device,
++#endif
++#ifdef CONFIG_SPI_FTSPI020
++    &ftspi020_device,
++#endif
++#ifdef CONFIG_SPI_FTSSP010
++    &ftssp010_1_device,
++#endif
++};
++
++void __init platform_devices_init(void)
++{
++    /* add platform devices here
++     */
++
++    /* will invoke platform_device_register() to register all platform devices
++     */
++	platform_add_devices(gm_devices, ARRAY_SIZE(gm_devices));
++#ifdef CONFIG_SPI_FTSSP010
++	spi_register_board_info(spi_devs_info, ARRAY_SIZE(spi_devs_info));
++#endif
++}
+diff --git a/arch/arm/mach-GM/platform-GM8136/pmu.c b/arch/arm/mach-GM/platform-GM8136/pmu.c
+new file mode 100644
+index 00000000..899dfb9b
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8136/pmu.c
+@@ -0,0 +1,473 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++#include <mach/fmem.h>
++
++#define SYS_CLK 30000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++#ifdef CONFIG_GPIO_FTGPIO010
++static int gpio_fd = -1;
++#endif
++static int dmac_fd = -1;
++static int gmac_fd = -1;
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x40, (0x1 << 14), (0x1 << 14), (0x1 << 14), (0x1 << 14)}, ///< Enable Schmitt-trigger control on I2C signal
++    {0x54, (0xF << 22), (0xF << 22), (0x5 << 22), (0xF << 22)},
++    {0xB8, (0x1 << 7),  (0x1 << 7),  (0x0 << 7),  (0x1 << 7)},
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 8), (0x1 << 8), (0x0 << 8), (0x1 << 8)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++/* MAC
++ */
++static pmuReg_t regGMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 11), (0x1 << 11), (0x1 << 11), (0x1 << 11)},
++};
++
++static pmuRegInfo_t gmac_clk_info = {
++    "GMAC_CLK",
++    ARRAY_SIZE(regGMACArray),
++    ATTR_TYPE_PLL2,
++    regGMACArray
++};
++
++/* GPIO
++ */
++#ifdef CONFIG_GPIO_FTGPIO010
++static pmuReg_t regGPIOArray[] = {
++	/* reg_off, bit_masks, lock_bits, init_val, init_mask */
++	{0xB8, 1 << 16, 1 << 16, 0, 1 << 16}, // FTGPIO010_0
++	{0xB8, 1 << 17, 1 << 17, 0, 1 << 17}, // FTGPIO010_1
++};
++static pmuRegInfo_t gpio_clk_info = {
++	"gpio_clk",
++	ARRAY_SIZE(regGPIOArray),
++	ATTR_TYPE_NONE,             /* no clock source */
++	regGPIOArray
++};
++#endif
++
++static unsigned int pmu_get_chip(void)
++{
++	static unsigned int ID = 0;
++	unsigned int product = 0;
++
++    ID = (ioread32(pmu_base_addr) >> 2) & 0x1F;
++
++	switch (ID) {
++	  case 0x4:case 0x10:case 0x8:case 0x18:
++	    product = 0x8135;
++	    break;
++	  case 0x14:case 0x1C:
++	    product = 0x8136;//8136S
++	    break;
++	  case 0x0:
++	    product = 0x8136;
++	    break;
++	  default:
++	  	printk(KERN_ERR "Not define this ID\n");
++	    break;
++	}
++
++	return product;
++}
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	pmuver_t pmuver;
++	//unsigned int product;
++
++	/*
++	 * Version ID:
++	 *     81360: 8136
++	 *     81361: 8136 B
++	 */
++	if (!version) {
++	    //product = (ioread32(pmu_base_addr) >> 16) & 0xFFFF;
++	    version = (ioread32(pmu_base_addr) >> 8) & 0xF;
++
++	    printk(KERN_INFO "IC: GM%x, version: 0x%x \n", pmu_get_chip(), version);
++	}
++
++	switch (version) {
++      case 0x00:
++        pmuver = PMUVER_A;
++        break;
++      case 0x01:
++        pmuver = PMUVER_B;
++        break;
++      default:
++        printk(KERN_ERR "@@@@@@@@@@@@@@@@@@@@@@@@ CHIP Version: unknown! @@@@@@@@@@@@@@@@@@@@@@@@\n");
++        pmuver = PMUVER_UNKNOWN;
++        break;
++    }
++
++	return (unsigned int)pmuver;
++}
++
++/* 0 for system running NAND, -1 for SPI NOR, 1 for SPI NAND */
++int platform_check_flash_type(void)
++{
++	static unsigned int jmp_data;
++	int ret = 0;
++
++	jmp_data = ioread32(pmu_base_addr + 0x4);
++
++    if (jmp_data & BIT7)
++        ret = 1;
++    else
++        ret = -1;
++
++	return ret;
++}
++
++/* 0: 3 byte, 1: 4 byte */
++int platform_spi_four_byte_mode(void)
++{
++	static unsigned int jmp_data;
++	int ret = 0;
++
++	jmp_data = ioread32(pmu_base_addr + 0x4);
++
++    if (jmp_data & BIT23)
++        ret = 1;
++    else
++        ret = 0;
++
++	return ret;
++}
++
++//format: xxxx_yyyy. xxxx: 8136, yyyy:IC revision
++unsigned int pmu_get_chipversion(void)
++{
++    unsigned int value = (pmu_get_chip() << 16);
++
++    value |= pmu_get_version();
++
++    return value;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return ((readl(pmu_base_addr + 0x30)) >> 16) & 0xffff;
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m;//, div;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    n = (value >> 4) & 0x7F;
++    m = (value >> 11) & 0x1F;
++    value = (SYS_CLK * n) / m;
++
++    //div = readl(pmu_base_addr + 0x28);
++    //div = (div >> 24) & 0x7;
++    
++    return value;// / (div + 1);
++#endif
++}
++
++static inline u32 pmu_read_pll2out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m;
++
++    value = ioread32(pmu_base_addr + 0x34);
++    n = (value >> 4) & 0x7F;
++    m = (value >> 11) & 0x1F;
++    value = (SYS_CLK * n) / m;
++
++    return value;
++#endif
++}
++
++static inline u32 pmu_read_pll3out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m;
++
++    value = ioread32(pmu_base_addr + 0x34);
++    n = (value >> 20) & 0x7F;
++    m = (value >> 27) & 0x1F;
++    value = (SYS_CLK * n) / m;
++
++    return value;
++#endif
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 18) & 0x3;
++
++	switch (value) {
++	  case 0:
++	    value = pmu_read_pll1out() / 3;
++	    break;
++	  case 1:
++	    value = pmu_read_pll2out() / 3;
++	    break;
++	  case 2:case 3:
++	    value = pmu_read_pll2out() / 4;
++	    break;
++	  default:
++	    break;
++	}
++
++    return value;
++#endif
++}
++
++static unsigned int pmu_get_axi0_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 50000000;
++#else
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 20) & 0x3;
++
++	switch (value) {
++	  case 0:
++	    value = pmu_read_pll1out() / 3;
++	    break;
++	  case 1:
++	    value = pmu_read_pll2out() / 3;
++	    break;
++	  case 2:case 3:
++	    value = pmu_read_pll2out() / 4;
++	    break;
++	  default:
++	    break;
++	}
++
++    return value;
++#endif
++}
++
++static unsigned int pmu_get_axi1_clk(void)
++{
++    return pmu_get_axi0_clk();
++}
++
++static unsigned int pmu_get_axi2_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 50000000;
++#else
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 24) & 0x3;
++
++	switch (value) {
++	  case 0:
++	    value = pmu_read_pll1out() / 2;
++	    break;
++	  case 1:
++	    value = pmu_read_pll2out() / 2;
++	    break;
++	  case 2:case 3:
++	    value = pmu_read_pll1out() / 3;
++	    break;
++	  default:
++	    break;
++	}
++
++    return value;
++#endif
++}
++
++unsigned int pmu_get_apb_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    return pmu_get_ahb_clk() / 2;
++#endif
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 22) & 0x1;
++
++    if (value)
++        value = pmu_read_pll2out();
++    else
++        value = pmu_read_pll1out();
++
++    return value;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk0",  ATTR_TYPE_AXI0,   0}, pmu_get_axi0_clk},
++    {{"aclk1",  ATTR_TYPE_AXI1,   0}, pmu_get_axi1_clk},
++    {{"aclk2",  ATTR_TYPE_AXI2,   0}, pmu_get_axi2_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    {{"pclk",   ATTR_TYPE_APB,    0}, pmu_get_apb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll2",   ATTR_TYPE_PLL2,   0}, pmu_read_pll2out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++    {{"chipver", ATTR_TYPE_CHIPVER, 0}, pmu_get_chipversion},
++};
++
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(clock_info); tmp ++) {
++            if (clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (clock_info[tmp].clock_fun) {
++                clock_info[tmp].clock.value = clock_info[tmp].clock_fun();
++                ftpmu010_deregister_attr(&clock_info[tmp].clock);
++                ret = ftpmu010_register_attr(&clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk(KERN_INFO "PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk(KERN_ERR "I2C registers to PMU fail! \n");
++    }
++#ifdef CONFIG_GPIO_FTGPIO010
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk(KERN_ERR "GPIO registers to PMU fail! \n");
++    }
++#endif
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk(KERN_ERR "AHB DMAC registers to PMU fail! \n");
++    }
++
++    /* disable MAC clock, wait insmod MAC driver and enable it */
++    gmac_fd = ftpmu010_register_reg(&gmac_clk_info);
++    if (unlikely(gmac_fd < 0)){
++        printk(KERN_ERR "GMAC registers to PMU fail! \n");
++    }
++    ftpmu010_deregister_reg(gmac_fd);
++        
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM/platform-GM8136/timer_fixup.c b/arch/arm/mach-GM/platform-GM8136/timer_fixup.c
+new file mode 100644
+index 00000000..4d58a855
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8136/timer_fixup.c
+@@ -0,0 +1,126 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/ftpmu010.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/fiq.h>
++#include <mach/platform/board.h>
++
++#define CONFIG_MAX_TICK     0xffffffff
++static int timer_init_ready = 0;
++
++/*
++ * Get the max ms the this timer
++ */
++unsigned int video_gettime_max_ms(void)
++{
++    return (CONFIG_MAX_TICK / APB_CLK_IN) * 1000;
++}
++
++/* calculate the max hz in max_ms
++ */
++unsigned int video_gettime_max_hz(void)
++{
++    unsigned int max_hz;
++    
++    /* calculate the max hz in max_ms */
++    max_hz = (video_gettime_max_ms() * APB_CLK_IN) / 1000;
++    
++    return max_hz;
++}
++
++unsigned int video_gettime_ms(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++unsigned int video_gettime_us(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++/*
++ * Entry Point of this module. It may be declared by arch_initcall section
++ */
++static int __init fixup_timer_init(void)
++{
++    //use timer3, 42s will overflow in AHB clock 200HZ
++    unsigned int ft_apb_clk = APB_CLK_IN;
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++    unsigned int max_tick;
++    
++    if (*(unsigned int *)(timer_base + 0x30) & (0x1 << 6))
++    {
++        printk(KERN_INFO "Timer3 is alredy been used!\n");
++        return 0;
++    }
++
++    max_tick = video_gettime_max_ms() * (ft_apb_clk / 1000);    //the max hz count in TmxCounter
++    
++    printk(KERN_INFO "Video Timer(timer3) Max %dms in 0x%x HZ.\n", video_gettime_max_ms(), max_tick);
++    
++    /* the following configuration is for TIMER3 */
++    *(volatile unsigned int *)(timer_base + 0x20) = CONFIG_MAX_TICK - max_tick; //keep the start count in start counter
++    *(volatile unsigned int *)(timer_base + 0x24) = CONFIG_MAX_TICK - max_tick; //reLoad counter
++    *(volatile unsigned int *)(timer_base + 0x38) |= (0x7 << 6);   //IRQ disable
++    *(volatile unsigned int *)(timer_base + 0x30) |= ((0x1 << 6) | (0x1 << 11));    //enable timer3, count up
++    timer_init_ready = 1;
++    
++    return 0;
++}
++
++static void fixup_timer_exit(void)
++{
++    if (timer_init_ready == 1)
++    {
++        unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        *(volatile unsigned int *)(timer_base + 0x30) &= ~(0x1 << 6);//disable timer2, count up
++        timer_init_ready = 0;
++    }
++	printk(KERN_INFO "%s: cleaning up\n",__func__);
++}
++
++module_init(fixup_timer_init);
++module_exit(fixup_timer_exit);
++
++EXPORT_SYMBOL(video_gettime_ms);
++EXPORT_SYMBOL(video_gettime_us);
++EXPORT_SYMBOL(video_gettime_max_ms);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("FIXUP timer driver");
+diff --git a/arch/arm/mach-GM/platform-GM8139/Kconfig b/arch/arm/mach-GM/platform-GM8139/Kconfig
+new file mode 100644
+index 00000000..69a018e8
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8139/Kconfig
+@@ -0,0 +1,26 @@
++#
++# arch/arm/mach-GM/platform-GM8139/Kconfig
++
++if PLATFORM_GM8139
++
++#config SYS_CLK
++config CLOCK_TICK_RATE	
++        int "AHB System Clock"
++        default 240000000
++        help
++          Manual setting of AHB clock, must match the jumper setting on
++          the board, or the system time won't be correctly calculated.
++          Notice that even when AUTO_SYS_CLK is ON, this value is still
++          required for adjusting minor time offsets. However, the influence
++          should be within micro-second to nano-second scale.
++
++config FTINTC030
++	bool "FTINTC030 support"
++	default y
++
++config FPGA
++	bool "FPGA Verify"
++	default n
++
++endif
++
+diff --git a/arch/arm/mach-GM/platform-GM8139/Makefile b/arch/arm/mach-GM/platform-GM8139/Makefile
+new file mode 100644
+index 00000000..beb66a1b
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8139/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the GM platform dependent files
++
++# Object file lists.
++
++obj-y		:= board.o pmu.o timer_fixup.o platform.o
++
+diff --git a/arch/arm/mach-GM/platform-GM8139/board.c b/arch/arm/mach-GM/platform-GM8139/board.c
+new file mode 100644
+index 00000000..c0dfb948
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8139/board.c
+@@ -0,0 +1,249 @@
++/*
++ *  board depdenent initialization
++ *
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/setup.h>
++#include <mach/platform/board.h>
++#include <mach/platform/pmu.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/system.h>
++#include <mach/ftintc030.h>
++#include <mach/fttmr010.h>
++#include <mach/fmem.h>
++#include <linux/dma-mapping.h>
++
++#ifdef CONFIG_CACHE_FTL2CC031
++#include <asm/hardware/cache-ftl2cc031.h>
++#endif
++
++/* External functions and variables declaration
++ */
++extern void platform_devices_init(void);
++
++/* Local variables declaration
++ */
++void __iomem *ftintc030_base_addr;
++void __iomem *ftintc030_base_cpu_0_irq_base; //entry-macro.S will reference it
++
++/******************************************************************************
++ * IPs virtual address mapping
++ *****************************************************************************/
++static struct map_desc board_io_desc[] __initdata = {
++    /* PMU */
++    {
++        .virtual	= PMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PMU_FTPMU010_PA_BASE),
++		.length		= PMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART0 */
++    {
++        .virtual	= UART_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_0_PA_BASE),
++		.length		= UART_FTUART010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART1 */
++    {
++        .virtual	= UART_FTUART010_1_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_1_PA_BASE),
++		.length		= UART_FTUART010_1_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART2 */
++    {
++        .virtual	= UART_FTUART010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_2_PA_BASE),
++		.length		= UART_FTUART010_2_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* TIMER */
++    {
++        .virtual	= TIMER_FTTMR010_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_PA_BASE),
++		.length		= TIMER_FTTMR010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC030 */
++    {
++        .virtual	= INTC_FTINTC030_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC030_PA_BASE),
++		.length		= INTC_FTINTC030_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++#ifdef CONFIG_CACHE_FTL2CC031
++    /* L2 cache */
++	{
++		.virtual	= L2CACHE_FTL2CC031_VA_BASE,
++		.pfn		= __phys_to_pfn(L2CACHE_FTL2CC031_PA_BASE),
++		.length		= L2CACHE_FTL2CC031_VA_SIZE,
++		.type		= MT_DEVICE,
++	},
++#endif
++};
++
++/* fixup the memory for MACHINE_START. The parameters come from commandline of menuconfig
++ */
++static void __init board_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    fmem_fixup_memory(tag, cmdline, mi);
++}
++
++/* 2. create the iotable for IPs in MACHINE_START
++ */
++static void __init board_map_io(void)
++{
++    iotable_init(&board_io_desc[0], ARRAY_SIZE(board_io_desc));
++
++    /* set the base to pmu module */
++    pmu_earlyinit((void *)PMU_FTPMU010_VA_BASE);
++
++    /* init dma coherent mapping size,
++     * CONSISTENT_DMA_SIZE is defined in memory.h
++     * max allowable dma consistent size is 14M (0xFFE0_0000 - 0xFF00_00000)
++     * set as 12M to avoid unexpected data overlay, NISH_20121015
++     */
++    #ifdef CONSISTENT_DMA_SIZE
++    init_consistent_dma_size(CONSISTENT_DMA_SIZE);
++    #endif
++}
++
++static void __init board_init_irq(void)
++{
++	struct ftintc030_trigger_type trigger_type = {
++		.irqmode[0]	= PLATFORM_IRQ_TRIGGER_MODE1,
++		.irqlevel[0]	= ~PLATFORM_IRQ_TRIGGER_LEVEL1,
++		.fiqmode[0]	= PLATFORM_FIQ_TRIGGER_MODE1,
++		.fiqlevel[0]	= ~PLATFORM_FIQ_TRIGGER_LEVEL1,
++
++		.irqmode[1]	= PLATFORM_IRQ_TRIGGER_MODE2,
++		.irqlevel[1]	= ~PLATFORM_IRQ_TRIGGER_LEVEL2,
++		.fiqmode[1]	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel[1]	= ~PLATFORM_FIQ_TRIGGER_LEVEL2,
++
++		.irqmode[2]	= PLATFORM_IRQ_TRIGGER_MODE3,
++		.irqlevel[2]	= ~PLATFORM_IRQ_TRIGGER_LEVEL3,
++		.fiqmode[2]	= PLATFORM_FIQ_TRIGGER_MODE3,
++		.fiqlevel[2]	= ~PLATFORM_FIQ_TRIGGER_LEVEL3,
++
++		.irqmode[3]	= PLATFORM_IRQ_TRIGGER_MODE4,
++		.irqlevel[3]	= ~PLATFORM_IRQ_TRIGGER_LEVEL4,
++		.fiqmode[3]	= PLATFORM_FIQ_TRIGGER_MODE4,
++		.fiqlevel[3]	= ~PLATFORM_FIQ_TRIGGER_LEVEL4,
++
++		.irqmode[4]	= PLATFORM_IRQ_TRIGGER_MODE5,
++		.irqlevel[4]	= ~PLATFORM_IRQ_TRIGGER_LEVEL5,
++		.fiqmode[4]	= PLATFORM_FIQ_TRIGGER_MODE5,
++		.fiqlevel[4]	= ~PLATFORM_FIQ_TRIGGER_LEVEL5,
++
++		.irqmode[5]	= PLATFORM_IRQ_TRIGGER_MODE6,
++		.irqlevel[5]	= ~PLATFORM_IRQ_TRIGGER_LEVEL6,
++		.fiqmode[5]	= PLATFORM_FIQ_TRIGGER_MODE6,
++		.fiqlevel[5]	= ~PLATFORM_FIQ_TRIGGER_LEVEL6,
++
++		.irqmode[6]	= PLATFORM_IRQ_TRIGGER_MODE7,
++		.irqlevel[6]	= ~PLATFORM_IRQ_TRIGGER_LEVEL7,
++		.fiqmode[6]	= PLATFORM_FIQ_TRIGGER_MODE7,
++		.fiqlevel[6]	= ~PLATFORM_FIQ_TRIGGER_LEVEL7,
++
++		.irqmode[7]	= PLATFORM_IRQ_TRIGGER_MODE8,
++		.irqlevel[7]	= ~PLATFORM_IRQ_TRIGGER_LEVEL8,
++		.fiqmode[7]	= PLATFORM_FIQ_TRIGGER_MODE8,
++		.fiqlevel[7]	= ~PLATFORM_FIQ_TRIGGER_LEVEL8,
++	};
++
++	/*
++	 * initialize primary interrupt controller
++	 */
++	ftintc030_base_addr = __io(INTC_FTINTC030_VA_BASE);
++	ftintc030_base_cpu_0_irq_base = __io(INTC_FTINTC030_VA_BASE + FTINTC030_OFFSET_CPU_0_IRQ);
++
++	ftintc030_init(0, ftintc030_base_addr, 0, &trigger_type);
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 1,
++};
++
++static void __init board_sys_timer_init(void)
++{
++    unsigned int pclk = pmu_get_apb_clk();
++
++	fttmr010_0_clockevent.freq = pclk;
++	fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++	fttmr010_1_clocksource.freq = pclk;
++	fttmr010_clocksource_init(&fttmr010_1_clocksource);
++}
++
++struct sys_timer board_sys_timer = {
++	.init	= board_sys_timer_init,
++};
++
++/* board init */
++static void __init board_init_machine(void)
++{
++    int i;
++
++    platform_devices_init();
++
++    /* dump iotable information
++     */
++    for (i = 0; i < ARRAY_SIZE(board_io_desc); i ++) {
++        printk("iotable: VA: 0x%x, PA: 0x%x, Length: %d \n",
++                (u32)board_io_desc[i].virtual,
++                (u32)board_io_desc[i].pfn << PAGE_SHIFT,
++                (u32)board_io_desc[i].length);
++    }
++
++#ifdef CONFIG_CACHE_FTL2CC031
++    /* 256 KB (32KB/way), 8-way associativity, parity enabled */
++	ftl2cc031_init(__io(L2CACHE_FTL2CC031_VA_BASE), (AUX_WAYSIZE(WAYSIZE_32KB) | AUX_PAR_CHK_EN | 0x23), 0xF3777);
++#endif
++}
++
++MACHINE_START(GM, BOARD_NAME)
++	.atag_offset	= BOOT_PARAMETER_PA_OFFSET,   //boot command line, after kernel 3.2 change as relative address
++	.map_io		    = board_map_io,
++	.init_irq	    = board_init_irq,
++	.timer		    = &board_sys_timer,
++	.fixup          = board_fixup_memory,
++	.init_machine	= board_init_machine,
++	.restart	= arch_reset,
++MACHINE_END
+diff --git a/arch/arm/mach-GM/platform-GM8139/platform.c b/arch/arm/mach-GM/platform-GM8139/platform.c
+new file mode 100644
+index 00000000..c19d7586
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8139/platform.c
+@@ -0,0 +1,270 @@
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/dma-mapping.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach-types.h>
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++/* i2c:0 */
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start  = I2C_FTI2C010_0_PA_BASE,
++		.end    = I2C_FTI2C010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_0_IRQ,
++		.end	= I2C_FTI2C010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		    = 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++
++/******************************************************************************
++ * OTG devices
++ *****************************************************************************/
++#ifdef CONFIG_USB_SUPPORT
++/* OTG:0 */
++static struct resource fotg210_0_resources[] = {
++	{
++		.start  = USB_FOTG2XX_0_PA_BASE,
++		.end    = USB_FOTG2XX_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_0_IRQ,
++		.end    = USB_FOTG2XX_0_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_0_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_0_device = {
++	.name           = "fotg210",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(fotg210_0_resources),
++	.resource       = fotg210_0_resources,
++	.dev = {
++		.dma_mask = &fotg210_0_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif /* CONFIG_USB_SUPPORT */
++
++/******************************************************************************
++ * SDC devices
++ *****************************************************************************/
++/* FTSDC021 */
++static struct resource ftsdc021_resource[] = {
++	[0] = {
++	       .start = SDC_FTSDC021_PA_BASE,
++	       .end = SDC_FTSDC021_PA_LIMIT,
++	       .flags = IORESOURCE_MEM,
++	       },
++	[1] = {
++	       .start = SDC_FTSDC021_0_IRQ,
++	       .end = SDC_FTSDC021_0_IRQ,
++	       .flags = IORESOURCE_IRQ,
++	       }
++};
++static u64 ftsdc021_dmamask = 0xFFFFFFUL;
++static struct platform_device ftsdc021_device = {
++	.name = "ftsdc021",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(ftsdc021_resource),
++	.resource = ftsdc021_resource,
++	.dev = {
++		.dma_mask = &ftsdc021_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/******************************************************************************
++ * GPIO devices
++ *****************************************************************************/
++/* GPIO 0 */
++static struct resource ftgpio010_0_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_PA_BASE,
++		.end 	= GPIO_FTGPIO010_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_0_IRQ,
++		.end	= GPIO_FTGPIO010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_0_device = {
++	.name	= "ftgpio010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgpio010_0_resource),
++	.resource	= ftgpio010_0_resource
++};
++
++/* GPIO 1 */
++static struct resource ftgpio010_1_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_1_PA_BASE,
++		.end 	= GPIO_FTGPIO010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_1_IRQ,
++		.end	= GPIO_FTGPIO010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_1_device = {
++	.name	= "ftgpio010",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgpio010_1_resource),
++	.resource	= ftgpio010_1_resource
++};
++
++/******************************************************************************
++ * AHB DMA controllers
++ *****************************************************************************/
++#ifdef CONFIG_FTDMAC020
++static struct resource ftdmac020_0_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_0_PA_BASE,
++		.end	= DMAC_FTDMAC020_0_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_0_IRQ,
++		.end    = DMAC_FTDMAC020_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_0_device = {
++	.name		= "ftdmac020",
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_0_resources),
++	.resource	= ftdmac020_0_resources,
++};
++#endif /* CONFIG_FTDMAC020 */
++
++/******************************************************************************
++ * SPI020 controllers
++ *****************************************************************************/
++#ifdef CONFIG_SPI_FTSPI020
++static struct resource ftspi020_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,     /* Register Base address */
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static u64 ftspi020_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftspi020_device = {
++    .name = "ftspi020",
++    .id = 0,//must match with bus_num
++    .num_resources = ARRAY_SIZE(ftspi020_resource),
++    .resource = ftspi020_resource,
++    .dev = {
++            .dma_mask = &ftspi020_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            },
++};
++#endif /* CONFIG_SPI_FTSPI020 */
++
++#ifdef CONFIG_SPI_FTSSP010
++static struct resource ftssp010_1_resources[] = {
++	{
++		.start	= SSP_FTSSP010_1_PA_BASE,
++		.end	= SSP_FTSSP010_1_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= SSP_FTSSP010_1_IRQ,
++		.end    = SSP_FTSSP010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftssp010_1_device = {
++	.name		= "ssp_spi",
++	.id		    = 1,
++	.num_resources	= ARRAY_SIZE(ftssp010_1_resources),
++	.resource	= ftssp010_1_resources,	
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++};
++
++static struct spi_board_info spi_devs_info[] __initdata = {
++    /* SONY sensor */
++    {
++            .modalias       = "spidev",//"imx138_spi",
++            .max_speed_hz   = 6000000,
++            .bus_num        = 1,    //use controller 1
++            .chip_select    = 0,    //chip select 0
++            .mode = SPI_MODE_3,
++    },
++};
++#endif /* CONFIG_SPI_FTSSP010 */
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/
++static struct platform_device *gm_devices[] __initdata =
++{
++	/* I2C */
++	&ftiic010_0_device,
++	/* OTG */
++#ifdef CONFIG_USB_SUPPORT
++	&fotg210_0_device,
++#endif
++    &ftsdc021_device,
++	/* GPIO */
++	&ftgpio010_0_device,
++	&ftgpio010_1_device,
++#ifdef CONFIG_FTDMAC020
++    &ftdmac020_0_device,
++#endif
++#ifdef CONFIG_SPI_FTSPI020
++    &ftspi020_device,
++#endif
++#ifdef CONFIG_SPI_FTSSP010
++    &ftssp010_1_device,
++#endif
++};
++
++void __init platform_devices_init(void)
++{
++    /* add platform devices here
++     */
++
++    /* will invoke platform_device_register() to register all platform devices
++     */
++	platform_add_devices(gm_devices, ARRAY_SIZE(gm_devices));
++#ifdef CONFIG_SPI_FTSSP010
++	spi_register_board_info(spi_devs_info, ARRAY_SIZE(spi_devs_info));
++#endif	
++}
+diff --git a/arch/arm/mach-GM/platform-GM8139/pmu.c b/arch/arm/mach-GM/platform-GM8139/pmu.c
+new file mode 100644
+index 00000000..2c25beb4
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8139/pmu.c
+@@ -0,0 +1,481 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++#include <mach/fmem.h>
++
++#define SYS_CLK 30000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++#ifdef CONFIG_GPIO_FTGPIO010
++static int gpio_fd = -1;
++#endif
++static int dmac_fd = -1;
++static int gmac_fd = -1;
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0x40, (0x1 << 14), (0x1 << 14), (0x1 << 14), (0x1 << 14)}, ///< Enable Schmitt-trigger control on I2C signal
++    {0x54, (0xF << 22), (0xF << 22), (0x5 << 22), (0xF << 22)},
++    {0xB8, (0x1 << 7),  (0x1 << 7),  (0x0 << 7),  (0x1 << 7)},
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 8), (0x1 << 8), (0x0 << 8), (0x1 << 8)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++/* MAC
++ */
++static pmuReg_t regGMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 11), (0x1 << 11), (0x1 << 11), (0x1 << 11)},
++};
++
++static pmuRegInfo_t gmac_clk_info = {
++    "GMAC_CLK",
++    ARRAY_SIZE(regGMACArray),
++    ATTR_TYPE_PLL2,
++    regGMACArray
++};
++
++/* GPIO
++ */
++#ifdef CONFIG_GPIO_FTGPIO010
++static pmuReg_t regGPIOArray[] = {
++	/* reg_off, bit_masks, lock_bits, init_val, init_mask */
++	{0xB8, 1 << 16, 1 << 16, 0, 1 << 16}, // FTGPIO010_0
++	{0xB8, 1 << 17, 1 << 17, 0, 1 << 17}, // FTGPIO010_1
++};
++static pmuRegInfo_t gpio_clk_info = {
++	"gpio_clk",
++	ARRAY_SIZE(regGPIOArray),
++	ATTR_TYPE_NONE,             /* no clock source */
++	regGPIOArray
++};
++#endif
++
++static unsigned int pmu_get_chip(void)
++{
++	static unsigned int ID = 0;
++	unsigned int product = 0;
++
++  ID = (ioread32(pmu_base_addr) >> 8) & 0xF;
++
++	switch (ID) {
++	  case 0xB:case 0xE:
++	    product = 0x8139;
++	    break;
++	  case 0xA:case 0xD:case 0xF:
++      case 0xC:
++	    product = 0x8138;
++	    break;
++	  case 0x5:case 0x6:case 0x7:
++	    product = 0x8137;
++	    break;
++	  default:
++	  	printk("Not define this ID\n");
++	    break;
++	}
++
++	return product;
++}
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	pmuver_t pmuver;
++	//unsigned int product;
++
++	/*
++	 * Version ID:
++	 *     81290: 8139
++	 *     81291: 8139 MP
++	 */
++	if (!version) {
++	    //product = (ioread32(pmu_base_addr) >> 16) & 0xFFFF;
++	    version = (ioread32(pmu_base_addr) >> 12) & 0xF;
++
++	    printk("IC: GM%x, version: 0x%x \n", pmu_get_chip(), version);
++	}
++
++	switch (version) {
++      case 0x00:
++        pmuver = PMUVER_A;
++        break;
++      case 0x01:
++        pmuver = PMUVER_B;
++        break;
++      default:
++        printk("@@@@@@@@@@@@@@@@@@@@@@@@ CHIP Version: unknown! @@@@@@@@@@@@@@@@@@@@@@@@\n");
++        pmuver = PMUVER_UNKNOWN;
++        break;
++    }
++
++	return (unsigned int)pmuver;
++}
++
++/* 0 for system running NAND, -1 for SPI NOR, 1 for SPI NAND */
++int platform_check_flash_type(void)
++{
++	static unsigned int version, clk_data, jmp_data;
++	int ret = 0;
++
++	clk_data = ioread32(pmu_base_addr + 0xB4);
++	jmp_data = ioread32(pmu_base_addr + 0x4);
++	version = pmu_get_version();
++
++	if(version == PMUVER_A){
++        if (jmp_data & BIT23) {
++    		//clock off	NAND
++    		clk_data |= (1 << 16);
++    		iowrite32(clk_data, pmu_base_addr + 0xB4);
++
++            ret = -1;
++        } else {
++            ret = 1;
++        }
++    } else {
++        if (jmp_data & BIT22){
++            //clock off	NAND
++            clk_data |= (1 << 16);
++            iowrite32(clk_data, pmu_base_addr + 0xB4);
++            if (jmp_data & BIT23)
++                ret = -1;
++            else
++                ret = 1;
++        } else {
++            //clock off	SPI
++            clk_data |= (1 << 15);
++            iowrite32(clk_data, pmu_base_addr + 0xB4);
++            ret = 0;
++        }
++    }
++	return ret;
++}
++
++/* 0: 3 byte, 1: 4 byte */
++int platform_spi_four_byte_mode(void)
++{
++	static unsigned int version, jmp_data;
++	int ret = 0;
++
++	jmp_data = ioread32(pmu_base_addr + 0x4);
++	version = pmu_get_version();
++
++	if(version == PMUVER_A){
++        if (jmp_data & BIT7)
++            ret = 1;
++        else
++            ret = 0;
++    }else{
++        if (jmp_data & BIT7)
++            ret = 0;
++        else
++            ret = 1;
++    }
++	return ret;
++}
++
++//format: xxxx_yyyy. xxxx: 8139, yyyy:IC revision
++unsigned int pmu_get_chipversion(void)
++{
++    unsigned int value = (pmu_get_chip() << 16);
++
++    value |= pmu_get_version();
++
++    return value;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return ((readl(pmu_base_addr + 0x30)) >> 16) & 0xffff;
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    n = (value >> 4) & 0x7F;
++    m = (value >> 11) & 0x1F;
++    value = (SYS_CLK * n) / m;
++
++    return value;
++#endif
++}
++
++static inline u32 pmu_read_pll2out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m;
++
++    value = ioread32(pmu_base_addr + 0x34);
++    n = (value >> 4) & 0x7F;
++    m = (value >> 11) & 0x1F;
++    value = (SYS_CLK * n) / m;
++
++    return value;
++#endif
++}
++
++static inline u32 pmu_read_pll3out(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value, n, m;
++
++    value = ioread32(pmu_base_addr + 0x34);
++    n = (value >> 20) & 0x7F;
++    m = (value >> 27) & 0x1F;
++		value = (SYS_CLK * n) / m;
++
++    return value;
++#endif
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 18) & 0x1;
++
++    if(value)
++  		value = pmu_read_pll2out() / 4;
++  	else
++  		value = pmu_read_pll1out() / 4;
++
++    return value;
++#endif
++}
++
++static unsigned int pmu_get_axi_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 50000000;
++#else
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 20) & 0x1;
++
++    if(value)
++  		value = pmu_read_pll1out() / 4;
++  	else
++  		value = pmu_read_pll1out() / 3;
++
++    return value;
++#endif
++}
++
++unsigned int pmu_get_apb_clk(void)
++{
++#ifdef CONFIG_FPGA
++    return 20000000;
++#else
++    return pmu_get_ahb_clk() / 2;
++#endif
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 22) & 0x1;
++
++    if(pmu_get_chip() == 0x8137)
++        value = pmu_read_pll2out() / 2;
++    else if(value)
++  		value = pmu_read_pll2out() / 2;
++  	else
++  		value = pmu_read_pll2out();
++
++    return value;
++}
++
++static unsigned int pmu_get_ep_cnt(void)
++{
++    return 0;
++}
++
++static attr_cpu_enum_t pmu_get_cpu_enumator(void)
++{
++    fmem_pci_id_t   pci_id;
++    fmem_cpu_id_t   cpu_id;
++    attr_cpu_enum_t retval;
++
++    if (fmem_get_identifier(&pci_id, &cpu_id))
++        panic("%s, error! \n", __func__);
++
++    retval = (cpu_id == FMEM_CPU_FA726) ? CPU_RC_FA726 : CPU_RC_FA626;
++
++    return retval;
++}
++
++static unsigned int pmu_get_id_pin(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x0);
++    value = (value >> 8) & 0xF;
++
++    return value;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk",   ATTR_TYPE_AXI,    0}, pmu_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    {{"pclk",   ATTR_TYPE_APB0,   0}, pmu_get_apb_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll2",   ATTR_TYPE_PLL2,   0}, pmu_read_pll2out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++    {{"chipver", ATTR_TYPE_CHIPVER, 0}, pmu_get_chipversion},
++    {{"pci_epcnt", ATTR_TYPE_EPCNT,   0}, pmu_get_ep_cnt},
++    {{"cpu_enum",  ATTR_TYPE_CPUENUM, 0}, pmu_get_cpu_enumator},
++    {{"id_pin",  ATTR_TYPE_IDPIN, 0}, pmu_get_id_pin},
++};
++
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(clock_info); tmp ++) {
++            if (clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (clock_info[tmp].clock_fun) {
++                clock_info[tmp].clock.value = clock_info[tmp].clock_fun();
++                ftpmu010_deregister_attr(&clock_info[tmp].clock);
++                ret = ftpmu010_register_attr(&clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++#ifdef CONFIG_GPIO_FTGPIO010
++    /* register GPIO to pmu core */
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++#endif
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++    /* disable MAC clock, wait insmod MAC driver and enable it */
++    gmac_fd = ftpmu010_register_reg(&gmac_clk_info);
++    if (unlikely(gmac_fd < 0)){
++        printk("GMAC registers to PMU fail! \n");
++    }
++    ftpmu010_deregister_reg(gmac_fd);
++
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM/platform-GM8139/timer_fixup.c b/arch/arm/mach-GM/platform-GM8139/timer_fixup.c
+new file mode 100644
+index 00000000..b4bb491a
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8139/timer_fixup.c
+@@ -0,0 +1,126 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/ftpmu010.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/fiq.h>
++#include <mach/platform/board.h>
++
++#define CONFIG_MAX_TICK     0xffffffff
++static int timer_init_ready = 0;
++
++/*
++ * Get the max ms the this timer
++ */
++unsigned int video_gettime_max_ms(void)
++{
++    return (CONFIG_MAX_TICK / APB0_CLK_IN) * 1000;
++}
++
++/* calculate the max hz in max_ms
++ */
++unsigned int video_gettime_max_hz(void)
++{
++    unsigned int max_hz;
++    
++    /* calculate the max hz in max_ms */
++    max_hz = (video_gettime_max_ms() * APB0_CLK_IN) / 1000;
++    
++    return max_hz;
++}
++
++unsigned int video_gettime_ms(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++unsigned int video_gettime_us(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++/*
++ * Entry Point of this module. It may be declared by arch_initcall section
++ */
++static int __init fixup_timer_init(void)
++{
++    //use timer3, 42s will overflow in AHB clock 200HZ
++    unsigned int ft_apb_clk = APB0_CLK_IN;
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++    unsigned int max_tick;
++    
++    if (*(unsigned int *)(timer_base + 0x30) & (0x1 << 6))
++    {
++        printk("Timer3 is alredy been used!\n");
++        return 0;
++    }
++
++    max_tick = video_gettime_max_ms() * (ft_apb_clk / 1000);    //the max hz count in TmxCounter
++    
++    printk("Video Timer(timer3) Max %dms in 0x%x HZ.\n", video_gettime_max_ms(), max_tick);
++    
++    /* the following configuration is for TIMER3 */
++    *(volatile unsigned int *)(timer_base + 0x20) = CONFIG_MAX_TICK - max_tick; //keep the start count in start counter
++    *(volatile unsigned int *)(timer_base + 0x24) = CONFIG_MAX_TICK - max_tick; //reLoad counter
++    *(volatile unsigned int *)(timer_base + 0x38) |= (0x7 << 6);   //IRQ disable
++    *(volatile unsigned int *)(timer_base + 0x30) |= ((0x1 << 6) | (0x1 << 11));    //enable timer3, count up
++    timer_init_ready = 1;
++    
++    return 0;
++}
++
++static void fixup_timer_exit(void)
++{
++    if (timer_init_ready == 1)
++    {
++        unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        *(volatile unsigned int *)(timer_base + 0x30) &= ~(0x1 << 6);//disable timer2, count up
++        timer_init_ready = 0;
++    }
++	printk("%s: cleaning up\n",__func__);
++}
++
++module_init(fixup_timer_init);
++module_exit(fixup_timer_exit);
++
++EXPORT_SYMBOL(video_gettime_ms);
++EXPORT_SYMBOL(video_gettime_us);
++EXPORT_SYMBOL(video_gettime_max_ms);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("FIXUP timer driver");
+diff --git a/arch/arm/mach-GM/platform-GM8287/Kconfig b/arch/arm/mach-GM/platform-GM8287/Kconfig
+new file mode 100644
+index 00000000..1813248f
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8287/Kconfig
+@@ -0,0 +1,18 @@
++#
++# arch/arm/mach-GM/platform-GM8287/Kconfig
++
++if PLATFORM_GM8287
++
++#config SYS_CLK
++config CLOCK_TICK_RATE	
++        int "AHB System Clock"
++        default 33000000
++        help
++            Any fake value is ok. It almost obsolete.
++
++config FTINTC030
++	bool "FTINTC030 support"
++	default y
++
++endif
++
+diff --git a/arch/arm/mach-GM/platform-GM8287/Makefile b/arch/arm/mach-GM/platform-GM8287/Makefile
+new file mode 100644
+index 00000000..beb66a1b
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8287/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the GM platform dependent files
++
++# Object file lists.
++
++obj-y		:= board.o pmu.o timer_fixup.o platform.o
++
+diff --git a/arch/arm/mach-GM/platform-GM8287/board.c b/arch/arm/mach-GM/platform-GM8287/board.c
+new file mode 100644
+index 00000000..91325375
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8287/board.c
+@@ -0,0 +1,239 @@
++/*
++ *  board depdenent initialization
++ *  
++ *  Copyright (C) 2009 Faraday Corp. (http://www.faraday-tech.com)
++ *
++ * 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 <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++#include <asm/mach-types.h>
++#include <asm/sizes.h>
++#include <asm/setup.h>
++#include <mach/platform/board.h>
++#include <mach/platform/pmu.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/system.h>
++#include <mach/ftintc030.h>
++#include <mach/fttmr010.h>
++#include <mach/fmem.h>
++#include <linux/dma-mapping.h> /* NISH_20121015 add for init_consistent_dma_size() */
++
++/* External functions and variables declaration
++ */
++extern void platform_devices_init(void);
++
++/* Local variables declaration
++ */
++void __iomem *ftintc030_base_addr;
++void __iomem *ftintc030_base_cpu_0_irq_base; //entry-macro.S will reference it
++
++/******************************************************************************
++ * IPs virtual address mapping
++ *****************************************************************************/
++static struct map_desc board_io_desc[] __initdata = {
++    /* PMU */
++    {
++        .virtual	= PMU_FTPMU010_VA_BASE,
++		.pfn		= __phys_to_pfn(PMU_FTPMU010_PA_BASE),
++		.length		= PMU_FTPMU010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART0 */
++    {
++        .virtual	= UART_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_0_PA_BASE),
++		.length		= UART_FTUART010_0_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART1 */
++    {
++        .virtual	= UART_FTUART010_1_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_1_PA_BASE),
++		.length		= UART_FTUART010_1_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART2 */
++    {
++        .virtual	= UART_FTUART010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_2_PA_BASE),
++		.length		= UART_FTUART010_2_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* UART3 */
++    {
++        .virtual	= UART_FTUART010_3_VA_BASE,
++		.pfn		= __phys_to_pfn(UART_FTUART010_3_PA_BASE),
++		.length		= UART_FTUART010_3_VA_SIZE,
++		.type		= MT_DEVICE,
++    },    
++    /* TIMER */
++    {
++        .virtual	= TIMER_FTTMR010_VA_BASE,
++		.pfn		= __phys_to_pfn(TIMER_FTTMR010_PA_BASE),
++		.length		= TIMER_FTTMR010_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++    /* INTC030 */
++    {
++        .virtual	= INTC_FTINTC030_VA_BASE,
++		.pfn		= __phys_to_pfn(INTC_FTINTC030_PA_BASE),
++		.length		= INTC_FTINTC030_VA_SIZE,
++		.type		= MT_DEVICE,
++    },
++};
++
++/* fixup the memory for MACHINE_START. The parameters come from commandline of menuconfig
++ */
++static void __init board_fixup_memory(struct tag *tag, char **cmdline, struct meminfo *mi)
++{
++    fmem_fixup_memory(tag, cmdline, mi);
++}    
++
++/* 2. create the iotable for IPs in MACHINE_START
++ */
++static void __init board_map_io(void) 
++{
++    iotable_init(&board_io_desc[0], ARRAY_SIZE(board_io_desc));
++    
++    /* set the base to pmu module */
++    pmu_earlyinit((void *)PMU_FTPMU010_VA_BASE);
++
++    /* init dma coherent mapping size,      
++     * CONSISTENT_DMA_SIZE is defined in memory.h     
++     * max allowable dma consistent size is 14M (0xFFE0_0000 - 0xFF00_00000)    
++     * set as 12M to avoid unexpected data overlay, NISH_20121015      
++     */
++    #ifdef CONSISTENT_DMA_SIZE	
++    init_consistent_dma_size(CONSISTENT_DMA_SIZE);    
++    #endif
++}
++
++static void __init board_init_irq(void)
++{        
++	struct ftintc030_trigger_type trigger_type = {
++		.irqmode[0]	= PLATFORM_IRQ_TRIGGER_MODE1,
++		.irqlevel[0]	= ~PLATFORM_IRQ_TRIGGER_LEVEL1,
++		.fiqmode[0]	= PLATFORM_FIQ_TRIGGER_MODE1,
++		.fiqlevel[0]	= ~PLATFORM_FIQ_TRIGGER_LEVEL1,
++
++		.irqmode[1]	= PLATFORM_IRQ_TRIGGER_MODE2,
++		.irqlevel[1]	= ~PLATFORM_IRQ_TRIGGER_LEVEL2,
++		.fiqmode[1]	= PLATFORM_FIQ_TRIGGER_MODE2,
++		.fiqlevel[1]	= ~PLATFORM_FIQ_TRIGGER_LEVEL2,
++
++		.irqmode[2]	= PLATFORM_IRQ_TRIGGER_MODE3,
++		.irqlevel[2]	= ~PLATFORM_IRQ_TRIGGER_LEVEL3,
++		.fiqmode[2]	= PLATFORM_FIQ_TRIGGER_MODE3,
++		.fiqlevel[2]	= ~PLATFORM_FIQ_TRIGGER_LEVEL3,
++
++		.irqmode[3]	= PLATFORM_IRQ_TRIGGER_MODE4,
++		.irqlevel[3]	= ~PLATFORM_IRQ_TRIGGER_LEVEL4,
++		.fiqmode[3]	= PLATFORM_FIQ_TRIGGER_MODE4,
++		.fiqlevel[3]	= ~PLATFORM_FIQ_TRIGGER_LEVEL4,
++
++		.irqmode[4]	= PLATFORM_IRQ_TRIGGER_MODE5,
++		.irqlevel[4]	= ~PLATFORM_IRQ_TRIGGER_LEVEL5,
++		.fiqmode[4]	= PLATFORM_FIQ_TRIGGER_MODE5,
++		.fiqlevel[4]	= ~PLATFORM_FIQ_TRIGGER_LEVEL5,
++
++		.irqmode[5]	= PLATFORM_IRQ_TRIGGER_MODE6,
++		.irqlevel[5]	= ~PLATFORM_IRQ_TRIGGER_LEVEL6,
++		.fiqmode[5]	= PLATFORM_FIQ_TRIGGER_MODE6,
++		.fiqlevel[5]	= ~PLATFORM_FIQ_TRIGGER_LEVEL6,
++
++		.irqmode[6]	= PLATFORM_IRQ_TRIGGER_MODE7,
++		.irqlevel[6]	= ~PLATFORM_IRQ_TRIGGER_LEVEL7,
++		.fiqmode[6]	= PLATFORM_FIQ_TRIGGER_MODE7,
++		.fiqlevel[6]	= ~PLATFORM_FIQ_TRIGGER_LEVEL7,
++
++		.irqmode[7]	= PLATFORM_IRQ_TRIGGER_MODE8,
++		.irqlevel[7]	= ~PLATFORM_IRQ_TRIGGER_LEVEL8,
++		.fiqmode[7]	= PLATFORM_FIQ_TRIGGER_MODE8,
++		.fiqlevel[7]	= ~PLATFORM_FIQ_TRIGGER_LEVEL8,
++	};
++    
++	/*
++	 * initialize primary interrupt controller
++	 */
++	ftintc030_base_addr = __io(INTC_FTINTC030_VA_BASE);
++	ftintc030_base_cpu_0_irq_base = __io(INTC_FTINTC030_VA_BASE + FTINTC030_OFFSET_CPU_0_IRQ);
++	
++	ftintc030_init(0, ftintc030_base_addr, 0, &trigger_type);
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= TIMER_FTTMR010_IRQ0,
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {	
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)TIMER_FTTMR010_VA_BASE,
++	.id	= 1,
++};
++
++static void __init board_sys_timer_init(void)
++{
++    unsigned int pclk = pmu_get_apb0_clk();
++	printk("Timer use APB0 clock\n");
++
++	fttmr010_0_clockevent.freq = pclk;
++	fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++	fttmr010_1_clocksource.freq = pclk;
++	fttmr010_clocksource_init(&fttmr010_1_clocksource);
++}
++
++struct sys_timer board_sys_timer = {
++	.init	= board_sys_timer_init,
++};
++
++/* board init */
++static void __init board_init_machine(void)
++{
++    int i;
++    
++    platform_devices_init();
++    
++    /* dump iotable information 
++     */
++    for (i = 0; i < ARRAY_SIZE(board_io_desc); i ++) {
++        printk("iotable: VA: 0x%x, PA: 0x%x, Length: %d \n", 
++                (u32)board_io_desc[i].virtual, 
++                (u32)board_io_desc[i].pfn << PAGE_SHIFT,
++                (u32)board_io_desc[i].length);
++    }
++}
++
++MACHINE_START(GM, BOARD_NAME)
++	.atag_offset	= BOOT_PARAMETER_PA_OFFSET,   //boot command line, after kernel 3.2 change as relative address
++	.map_io		    = board_map_io,
++	.init_irq	    = board_init_irq,
++	.timer		    = &board_sys_timer,
++	.fixup          = board_fixup_memory,
++	.init_machine	= board_init_machine,
++	.restart	= arch_reset,
++MACHINE_END
+diff --git a/arch/arm/mach-GM/platform-GM8287/platform.c b/arch/arm/mach-GM/platform-GM8287/platform.c
+new file mode 100644
+index 00000000..27286343
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8287/platform.c
+@@ -0,0 +1,372 @@
++#include <linux/platform_device.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/dma-mapping.h>
++#include <asm/setup.h>
++#include <asm/sizes.h>
++#include <linux/module.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach-types.h>
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++/* i2c:0 */
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start  = I2C_FTI2C010_0_PA_BASE,
++		.end    = I2C_FTI2C010_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_0_IRQ,
++		.end	= I2C_FTI2C010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		    = 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++
++#ifdef CONFIG_I2C1_IP
++/* i2c:1 */
++static struct resource ftiic010_1_resources[] = {
++	{
++		.start  = I2C_FTI2C010_1_PA_BASE,
++		.end    = I2C_FTI2C010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_1_IRQ,
++		.end	= I2C_FTI2C010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_1_device = {
++	.name		= "ftiic010",
++	.id		    = 1,
++	.num_resources	= ARRAY_SIZE(ftiic010_1_resources),
++	.resource	= ftiic010_1_resources,
++};
++#endif
++
++#ifdef CONFIG_I2C2_IP
++/* i2c:2 */
++static struct resource ftiic010_2_resources[] = {
++	{
++		.start  = I2C_FTI2C010_2_PA_BASE,
++		.end    = I2C_FTI2C010_2_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start	= I2C_FTI2C010_2_IRQ,
++		.end	= I2C_FTI2C010_2_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_2_device = {
++	.name		= "ftiic010",
++	.id		    = 2,
++	.num_resources	= ARRAY_SIZE(ftiic010_2_resources),
++	.resource	= ftiic010_2_resources,
++};
++#endif
++
++/******************************************************************************
++ * OTG devices
++ *****************************************************************************/
++#ifdef CONFIG_USB_SUPPORT
++/* OTG:0 */
++static struct resource fotg210_0_resources[] = {
++	{
++		.start  = USB_FOTG2XX_0_PA_BASE,
++		.end    = USB_FOTG2XX_0_PA_LIMIT,
++		.flags  = IORESOURCE_MEM,
++	},
++	{
++		.start  = USB_FOTG2XX_0_IRQ,
++		.end    = USB_FOTG2XX_0_IRQ,
++		.flags  = IORESOURCE_IRQ,
++	},
++};
++static u64 fotg210_0_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_0_device = {
++	.name           = "fotg210",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(fotg210_0_resources),
++	.resource       = fotg210_0_resources,
++	.dev = {
++		.dma_mask = &fotg210_0_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++/* OTG:1 */
++struct resource fotg210_1_resources[] = {
++    {
++        .start  = USB_FOTG2XX_1_PA_BASE,
++        .end    = USB_FOTG2XX_1_PA_LIMIT,
++        .flags  = IORESOURCE_MEM,
++    },
++    {
++        .start  = USB_FOTG2XX_1_IRQ,
++        .end    = USB_FOTG2XX_1_IRQ,
++        .flags  = IORESOURCE_IRQ,
++    },
++};
++static u64 fotg210_1_dmamask = 0xFFFFFFUL;
++static struct platform_device fotg210_1_device = {
++    .name           = "fotg210",
++    .id             = 1,
++    .num_resources  = ARRAY_SIZE(fotg210_1_resources),
++    .resource       = fotg210_1_resources,
++    .dev = {
++        .dma_mask = &fotg210_1_dmamask,
++        .coherent_dma_mask = 0xFFFFFFFF,
++    },
++};
++#endif /* CONFIG_USB_SUPPORT */
++
++/******************************************************************************
++ * SDC devices
++ *****************************************************************************/
++#if defined(CONFIG_MMC_FTSDC021)
++/* FTSDC021 */
++static struct resource ftsdc021_resource[] = {
++	[0] = {
++	       .start = SDC_FTSDC021_PA_BASE,
++	       .end = SDC_FTSDC021_PA_LIMIT,
++	       .flags = IORESOURCE_MEM,
++	       },
++	[1] = {
++	       .start = SDC_FTSDC021_0_IRQ,
++	       .end = SDC_FTSDC021_0_IRQ,
++	       .flags = IORESOURCE_IRQ,
++	       }
++};
++static u64 ftsdc021_dmamask = 0xFFFFFFUL;
++static struct platform_device ftsdc021_device = {
++	.name = "ftsdc021",
++	.id = 0,
++	.num_resources = ARRAY_SIZE(ftsdc021_resource),
++	.resource = ftsdc021_resource,
++	.dev = {
++		.dma_mask = &ftsdc021_dmamask,
++		.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif
++/******************************************************************************
++ * GPIO devices
++ *****************************************************************************/
++/* GPIO 0 */
++static struct resource ftgpio010_0_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_PA_BASE,
++		.end 	= GPIO_FTGPIO010_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_0_IRQ,
++		.end	= GPIO_FTGPIO010_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_0_device = {
++	.name	= "ftgpio010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgpio010_0_resource),
++	.resource	= ftgpio010_0_resource
++};
++
++/* GPIO 1 */
++static struct resource ftgpio010_1_resource[] = {
++	{
++		.start	= GPIO_FTGPIO010_1_PA_BASE,
++		.end 	= GPIO_FTGPIO010_1_PA_LIMIT,
++		.flags  = IORESOURCE_MEM
++	},
++	{
++		.start	= GPIO_FTGPIO010_1_IRQ,
++		.end	= GPIO_FTGPIO010_1_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgpio010_1_device = {
++	.name	= "ftgpio010",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgpio010_1_resource),
++	.resource	= ftgpio010_1_resource
++};
++
++/******************************************************************************
++ * SATA devices
++ *****************************************************************************/
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++/* SATA0 */
++static struct resource ftsata100_0_resource[] = {
++    {
++        .start = SATA_FTSATA100_0_PA_BASE,
++        .end   = SATA_FTSATA100_0_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_0_IRQ,
++        .end   = SATA_FTSATA100_0_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_0_dmamask = ~(u32)0;
++static struct platform_device ftsata100_0_device = {
++	.name           = "ftsata100",
++	.id             = 0,
++	.num_resources  = ARRAY_SIZE(ftsata100_0_resource),
++	.resource       = ftsata100_0_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_0_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++
++/* SATA1 */
++static struct resource ftsata100_1_resource[] = {
++    {
++        .start = SATA_FTSATA100_1_PA_BASE,
++        .end   = SATA_FTSATA100_1_PA_LIMIT,
++        .flags = IORESOURCE_MEM,
++    },
++    {
++        .start = SATA_FTSATA100_1_IRQ,
++        .end   = SATA_FTSATA100_1_IRQ,
++        .flags = IORESOURCE_IRQ,
++    }
++};
++
++static u64 ftsata100_1_dmamask = ~(u32)0;
++static struct platform_device ftsata100_1_device = {
++	.name           = "ftsata100",
++	.id             = 1,
++	.num_resources  = ARRAY_SIZE(ftsata100_1_resource),
++	.resource       = ftsata100_1_resource,
++	.dev            = {
++				.dma_mask = &ftsata100_1_dmamask,
++				.coherent_dma_mask = 0xFFFFFFFF,
++	},
++};
++#endif // #ifdef CONFIG_SATA_AHCI_PLATFORM
++
++/******************************************************************************
++ * AHB DMA controllers
++ *****************************************************************************/
++#ifdef CONFIG_FTDMAC020
++static struct resource ftdmac020_0_resources[] = {
++	{
++		.start	= DMAC_FTDMAC020_0_PA_BASE,
++		.end	= DMAC_FTDMAC020_0_PA_LIMIT,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= DMAC_FTDMAC020_0_IRQ,
++		.end    = DMAC_FTDMAC020_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftdmac020_0_device = {
++	.name		= "ftdmac020",
++	.id		    = 0,
++	.dev		= {
++		.coherent_dma_mask	= ((1ULL<<(32))-1),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_0_resources),
++	.resource	= ftdmac020_0_resources,
++};
++#endif /* CONFIG_FTDMAC020 */
++
++/******************************************************************************
++ * SPI020 controllers
++ *****************************************************************************/
++#ifdef CONFIG_SPI_FTSPI020
++static struct resource ftspi020_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,     /* Register Base address */
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static u64 ftspi020_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftspi020_device = {
++    .name = "ftspi020",
++    .id = 0,//must match with bus_num
++    .num_resources = ARRAY_SIZE(ftspi020_resource),
++    .resource = ftspi020_resource,
++    .dev = {
++            .dma_mask = &ftspi020_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            },
++};
++#endif /* CONFIG_SPI_FTSPI020 */
++
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/
++static struct platform_device *gm_devices[] __initdata =
++{
++	/* I2C */
++	&ftiic010_0_device,
++#ifdef CONFIG_I2C1_IP
++	&ftiic010_1_device,
++#endif
++#ifdef CONFIG_I2C2_IP
++	&ftiic010_2_device,
++#endif
++	/* OTG */
++#ifdef CONFIG_USB_SUPPORT
++	&fotg210_0_device,
++	&fotg210_1_device,
++#endif
++	/* SDC */
++#if defined(CONFIG_MMC_FTSDC021)
++    &ftsdc021_device,
++#endif
++	/* GPIO */
++	&ftgpio010_0_device,
++	&ftgpio010_1_device,
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++    &ftsata100_0_device,
++    &ftsata100_1_device,
++#endif
++#ifdef CONFIG_FTDMAC020
++    &ftdmac020_0_device,
++#endif
++#ifdef CONFIG_SPI_FTSPI020
++    &ftspi020_device,
++#endif
++};
++
++void __init platform_devices_init(void)
++{
++    /* add platform devices here
++     */
++
++    /* will invoke platform_device_register() to register all platform devices
++     */
++	platform_add_devices(gm_devices, ARRAY_SIZE(gm_devices));
++}
+diff --git a/arch/arm/mach-GM/platform-GM8287/pmu.c b/arch/arm/mach-GM/platform-GM8287/pmu.c
+new file mode 100644
+index 00000000..48b8a53c
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8287/pmu.c
+@@ -0,0 +1,409 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <linux/synclink.h>
++#include <mach/fmem.h>
++
++#define SYS_CLK 12000000
++
++static void __iomem    *pmu_base_addr = (void __iomem *)NULL;
++
++/* PMU register data */
++static int i2c_fd = -1;
++//static int gpio_fd = -1;
++static int dmac_fd = -1;
++/* -----------------------------------------------------------------------
++ * Clock GATE table. Note: this table is necessary
++ * -----------------------------------------------------------------------
++ */
++ftpmu010_gate_clk_t gate_tbl[] = {
++    /* moduleID,    count,  register (ofs, val, mask) */
++    {FTPMU_NONE,    0,      {{0x0,   0x0,        0x0}}} /* END, this row is necessary */
++};
++
++/* I2C
++ */
++static pmuReg_t  regI2cArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++#ifdef CONFIG_I2C0_IP
++    {0xB8, (0x1 << 14), (0x1 << 14), (0x0 << 14), (0x1 << 14)}, /* Disable i2c0 gating clock off */
++    {0x44, (0x1 << 12), (0x1 << 12), (0x1 << 12), (0x1 << 12)}, /* Enable i2c0 schmitt trigger */
++#endif
++#ifdef CONFIG_I2C1_IP
++    {0x50, (0x1 << 22), (0x1 << 22), (0x0 << 22), (0x1 << 22)},
++    {0xBC, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)}, // i2c2 gating clock off
++#endif
++#ifdef CONFIG_I2C2_IP
++    {0xBC, (0x1 << 13), (0x1 << 13), (0x0 << 13), (0x1 << 13)}, // i2c2 gating clock off
++    {0x44, (0x1 << 17), (0x1 << 17), (0x1 << 17), (0x1 << 17)}, // i2c2 schmitt trigger
++    {0x58, (0x3 << 12), (0x3 << 12), (0x1 << 12), (0x3 << 12)}, // i2c2 pin mux, 00b:I2C1, 01b:GPIO[48:49], 10b:I2S5_SCLK/I2S5_FS
++#endif
++
++};
++
++static pmuRegInfo_t i2c_clk_info = {
++    "i2c_clk",
++    ARRAY_SIZE(regI2cArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regI2cArray
++};
++
++/* GPIO
++ */
++#if 0 //useless now
++static pmuReg_t regGPIOArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++};
++
++static pmuRegInfo_t gpio_clk_info = {
++    "gpio_clk",
++    ARRAY_SIZE(regGPIOArray),
++    ATTR_TYPE_NONE, /* no clock source */
++    regGPIOArray
++};
++#endif
++
++/* DMAC
++ */
++static pmuReg_t regDMACArray[] = {
++ /* reg_off  bit_masks  lock_bits     init_val    init_mask */
++    {0xB4, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)},
++};
++
++static pmuRegInfo_t dmac_clk_info = {
++    "AHB_DMAC_CLK",
++    ARRAY_SIZE(regDMACArray),
++    ATTR_TYPE_AHB,
++    regDMACArray
++};
++
++/* 0 for system running NAND, -1 for spi, 1 for SMC */
++int platform_check_flash_type(void)
++{
++	static unsigned int data = 0;
++	int ret = 0;
++
++	data = ioread32(pmu_base_addr + 0x4);
++
++    if (data & BIT23)
++        ret = -1;
++    else
++        ret = 0;
++
++	return ret;
++}
++
++static unsigned int pmu_get_chip(void)
++{
++	static unsigned int ID = 0;
++	unsigned int product;
++
++  ID = ioread32(pmu_base_addr + 0x100) & 0xF;
++
++	if((ID >> 2) == 0x2)
++			product = 0x8287;
++	else{
++			switch (ID & 0x3) {
++		      case 0:
++		        product = 0x8282;
++		        break;
++		      case 1:
++		        product = 0x8283;
++		        break;
++		      case 2:
++		        product = 0x8286;
++		        break;
++		      case 3:
++		        product = 0x8287;
++		        break;
++		      default:
++		        break;
++		    }
++	}
++	return product;
++}
++
++static unsigned int pmu_get_version(void)
++{
++	static unsigned int version = 0;
++	pmuver_t pmuver;
++
++    /*
++	 * Version ID:
++	 *     887610: A version
++	 *     821011: B version
++	 */
++	if (!version) {
++	    version = (ioread32(pmu_base_addr + 0x100) >> 8) & 0x3;
++
++	    printk("IC: GM%x, version: 0x%x \n", pmu_get_chip(), version);
++	}
++
++	switch (version) {
++      case 0:
++        pmuver = PMUVER_B;
++        break;
++      case 2:
++        pmuver = PMUVER_C;
++        break;
++      case 3:
++        pmuver = 3;//PMUVER_E;
++        break;        
++      default:
++        printk("@@@@@@@@@@@@@@@@@@@@@@@@ CHIP Version: unknown! @@@@@@@@@@@@@@@@@@@@@@@@\n");
++        pmuver = PMUVER_UNKNOWN;
++        break;
++    }
++
++	return (unsigned int)pmuver;
++}
++
++//format: xxxx_yyyy. xxxx: 8287, yyyy:IC revision
++unsigned int pmu_get_chipversion(void)
++{
++    unsigned int value;
++
++    value = (pmu_get_chip() << 16) | pmu_get_version();
++
++    if(((ioread32(pmu_base_addr + 0x100) >> 2) & 0x3) == 0x2)
++        value |= 0x20;
++
++    return value;
++}
++
++/*
++ * Local functions
++ */
++static inline u32 pmu_read_cpumode(void)
++{
++    return ((readl(pmu_base_addr + 0x30)) >> 16) & 0xffff;
++}
++
++static inline u32 pmu_read_pll1out(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 3) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static inline u32 pmu_read_pll2out(void)
++{
++	printk("pll2 not support\n");
++
++	return 0;
++}
++
++static inline u32 pmu_read_pll3out(void)
++{
++    u32 mul, value = 0;
++
++    if (ioread32(pmu_base_addr + 0x28) & (1 << 15)) {   /* no pll3 */
++        printk("PLL3 not support this mode\n");
++    } else {
++  	    mul = (ioread32(pmu_base_addr + 0x34) >> 4) & 0x7F;
++  	    value = (SYS_CLK * mul) / 2;
++    }
++
++    return value;
++}
++
++static unsigned int pmu_read_pll4out(void)
++{
++	u32 value;
++
++    value = (ioread32(pmu_base_addr + 0x38) >> 4 ) & 0x7F;
++
++    return (SYS_CLK * value);
++}
++
++static unsigned int pmu_read_pll5out(void)
++{
++    return 750000000;
++}
++
++static unsigned int pmu_get_ahb_clk(void)
++{
++    u32 value = 0;
++
++    value = ioread32(pmu_base_addr + 0x30);
++    value = (value >> 17) & 0x3;
++
++    switch(value){
++    case 0:
++  	    value = (pmu_read_pll1out() * 2) / 5;
++  	    break;
++    case 1:
++  		value = pmu_read_pll1out() / 3;
++  		break;
++    case 2:
++  		value = pmu_read_pll1out() / 4;
++  		break;
++    case 3:
++  	    value = pmu_read_pll1out() / 5;
++    default:
++  		printk("AHB not support this mode\n");
++  		break;
++	}
++
++    return value;
++}
++
++static unsigned int pmu_get_cpu_clk(void)
++{
++    u32 fclk = 0;
++
++  	fclk = (pmu_read_pll1out() * 2) / 3;
++
++	return fclk;
++}
++
++static unsigned int pmu_get_ep_cnt(void)
++{
++    return 0;
++}
++
++static attr_cpu_enum_t pmu_get_cpu_enumator(void)
++{
++    fmem_pci_id_t   pci_id;
++    fmem_cpu_id_t   cpu_id;
++    attr_cpu_enum_t retval;
++
++    if (fmem_get_identifier(&pci_id, &cpu_id))
++        panic("%s, error! \n", __func__);
++
++    retval = (cpu_id == FMEM_CPU_FA726) ? CPU_RC_FA726 : CPU_RC_FA626;
++
++    return retval;
++}
++
++static unsigned int pmu_get_axi_clk(void)
++{
++    return pmu_get_cpu_clk() / 2;
++}
++
++unsigned int pmu_get_apb0_clk(void)
++{
++    return pmu_get_axi_clk() / 8;
++}
++
++unsigned int pmu_get_apb1_clk(void)
++{
++    return pmu_get_axi_clk() / 2;
++}
++
++unsigned int pmu_get_apb2_clk(void)
++{
++    return pmu_get_ahb_clk() / 4;
++}
++
++struct clock_s
++{
++    attrInfo_t   clock;
++    u32         (*clock_fun)(void);
++} clock_info[] = {
++    {{"aclk",   ATTR_TYPE_AXI,    0}, pmu_get_axi_clk},
++    {{"hclk",   ATTR_TYPE_AHB,    0}, pmu_get_ahb_clk},
++    {{"pclk0",  ATTR_TYPE_APB0,   0}, pmu_get_apb0_clk},
++    {{"pclk1",  ATTR_TYPE_APB1,   0}, pmu_get_apb1_clk},
++    {{"pclk2",  ATTR_TYPE_APB2,   0}, pmu_get_apb2_clk},
++    {{"pll1",   ATTR_TYPE_PLL1,   0}, pmu_read_pll1out},
++    {{"pll3",   ATTR_TYPE_PLL3,   0}, pmu_read_pll3out},
++    {{"pll4",   ATTR_TYPE_PLL4,   0}, pmu_read_pll4out},
++    {{"pll5",   ATTR_TYPE_PLL5,   0}, pmu_read_pll5out},
++    {{"cpuclk", ATTR_TYPE_CPU,    0}, pmu_get_cpu_clk},
++    {{"pmuver", ATTR_TYPE_PMUVER, 0}, pmu_get_version},
++    {{"chipver", ATTR_TYPE_CHIPVER, 0}, pmu_get_chipversion},
++    {{"pci_epcnt", ATTR_TYPE_EPCNT,   0}, pmu_get_ep_cnt},
++    {{"cpu_enum",  ATTR_TYPE_CPUENUM, 0}, pmu_get_cpu_enumator},
++};
++
++static int pmu_ctrl_handler(u32 cmd, u32 data1, u32 data2)
++{
++    ATTR_TYPE_T attr = (ATTR_TYPE_T)data1;
++    u32 tmp;
++    int ret = -1;
++
++    switch (cmd) {
++      case FUNC_TYPE_RELOAD_ATTR:
++        /* this attribute exists */
++        ret = -1;
++        if (ftpmu010_get_attr(attr) == 0)
++            break;
++        for (tmp = 0; tmp < ARRAY_SIZE(clock_info); tmp ++) {
++            if (clock_info[tmp].clock.attr_type != attr)
++                continue;
++
++            ret = 0;
++            if (clock_info[tmp].clock_fun) {
++                clock_info[tmp].clock.value = clock_info[tmp].clock_fun();
++                ftpmu010_deregister_attr(&clock_info[tmp].clock);
++                ret = ftpmu010_register_attr(&clock_info[tmp].clock);
++                break;
++            }
++        }
++        break;
++
++      default:
++        panic("%s, command 0x%x is unrecognized! \n", __func__, cmd);
++        break;
++    }
++
++    return ret;
++}
++static int __init pmu_postinit(void)
++{
++    int i;
++
++    printk("PMU: Mapped at 0x%x \n", (unsigned int)pmu_base_addr);
++
++    /* calls init function */
++    ftpmu010_init(pmu_base_addr, &gate_tbl[0], pmu_ctrl_handler);
++
++    /* register clock */
++    for (i = 0; i < ARRAY_SIZE(clock_info); i ++)
++    {
++        if (clock_info[i].clock_fun)
++            clock_info[i].clock.value = clock_info[i].clock_fun();
++
++        ftpmu010_register_attr(&clock_info[i].clock);
++    }
++
++    /* register I2C to pmu core */
++    i2c_fd = ftpmu010_register_reg(&i2c_clk_info);
++    if (unlikely(i2c_fd < 0)){
++        printk("I2C registers to PMU fail! \n");
++    }
++    /* register GPIO to pmu core */
++#if 0//please check define
++    gpio_fd = ftpmu010_register_reg(&gpio_clk_info);
++    if (unlikely(gpio_fd < 0)){
++        printk("GPIO registers to PMU fail! \n");
++    }
++#endif
++    /* register DMAC to pmu core */
++    dmac_fd = ftpmu010_register_reg(&dmac_clk_info);
++    if (unlikely(dmac_fd < 0)){
++        printk("AHB DMAC registers to PMU fail! \n");
++    }
++
++    return 0;
++}
++
++arch_initcall(pmu_postinit);
++
++/* this function should be earlier than any function in this file
++ */
++void __init pmu_earlyinit(void __iomem *base)
++{
++    pmu_base_addr = base;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("PMU driver");
+diff --git a/arch/arm/mach-GM/platform-GM8287/timer_fixup.c b/arch/arm/mach-GM/platform-GM8287/timer_fixup.c
+new file mode 100644
+index 00000000..b4bb491a
+--- /dev/null
++++ b/arch/arm/mach-GM/platform-GM8287/timer_fixup.c
+@@ -0,0 +1,126 @@
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <mach/ftpmu010.h>
++#include <linux/interrupt.h>
++#include <asm/irq.h>
++#include <asm/fiq.h>
++#include <mach/platform/board.h>
++
++#define CONFIG_MAX_TICK     0xffffffff
++static int timer_init_ready = 0;
++
++/*
++ * Get the max ms the this timer
++ */
++unsigned int video_gettime_max_ms(void)
++{
++    return (CONFIG_MAX_TICK / APB0_CLK_IN) * 1000;
++}
++
++/* calculate the max hz in max_ms
++ */
++unsigned int video_gettime_max_hz(void)
++{
++    unsigned int max_hz;
++    
++    /* calculate the max hz in max_ms */
++    max_hz = (video_gettime_max_ms() * APB0_CLK_IN) / 1000;
++    
++    return max_hz;
++}
++
++unsigned int video_gettime_ms(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++unsigned int video_gettime_us(void)
++{
++    //0~35 sec round
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        
++    if (timer_init_ready == 1)
++    {
++        unsigned int ft_apb_clk = APB0_CLK_IN;
++        unsigned int value = *(volatile unsigned int *)(timer_base + 0x20);
++        unsigned int tick_diff;
++                        
++        tick_diff = CONFIG_MAX_TICK - video_gettime_max_hz();   //counter shift
++        return (value - tick_diff) / (ft_apb_clk / 1000000);
++    }
++    else
++    {
++        //printk("TIMER not ready\n");
++        return 0;
++    }
++}
++
++/*
++ * Entry Point of this module. It may be declared by arch_initcall section
++ */
++static int __init fixup_timer_init(void)
++{
++    //use timer3, 42s will overflow in AHB clock 200HZ
++    unsigned int ft_apb_clk = APB0_CLK_IN;
++    unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++    unsigned int max_tick;
++    
++    if (*(unsigned int *)(timer_base + 0x30) & (0x1 << 6))
++    {
++        printk("Timer3 is alredy been used!\n");
++        return 0;
++    }
++
++    max_tick = video_gettime_max_ms() * (ft_apb_clk / 1000);    //the max hz count in TmxCounter
++    
++    printk("Video Timer(timer3) Max %dms in 0x%x HZ.\n", video_gettime_max_ms(), max_tick);
++    
++    /* the following configuration is for TIMER3 */
++    *(volatile unsigned int *)(timer_base + 0x20) = CONFIG_MAX_TICK - max_tick; //keep the start count in start counter
++    *(volatile unsigned int *)(timer_base + 0x24) = CONFIG_MAX_TICK - max_tick; //reLoad counter
++    *(volatile unsigned int *)(timer_base + 0x38) |= (0x7 << 6);   //IRQ disable
++    *(volatile unsigned int *)(timer_base + 0x30) |= ((0x1 << 6) | (0x1 << 11));    //enable timer3, count up
++    timer_init_ready = 1;
++    
++    return 0;
++}
++
++static void fixup_timer_exit(void)
++{
++    if (timer_init_ready == 1)
++    {
++        unsigned int timer_base = TIMER_FTTMR010_VA_BASE;
++        *(volatile unsigned int *)(timer_base + 0x30) &= ~(0x1 << 6);//disable timer2, count up
++        timer_init_ready = 0;
++    }
++	printk("%s: cleaning up\n",__func__);
++}
++
++module_init(fixup_timer_init);
++module_exit(fixup_timer_exit);
++
++EXPORT_SYMBOL(video_gettime_ms);
++EXPORT_SYMBOL(video_gettime_us);
++EXPORT_SYMBOL(video_gettime_max_ms);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("GM Technology Corp.");
++MODULE_DESCRIPTION("FIXUP timer driver");
+diff --git a/arch/arm/mach-faraday/Kconfig b/arch/arm/mach-faraday/Kconfig
+new file mode 100644
+index 00000000..c1e30f78
+--- /dev/null
++++ b/arch/arm/mach-faraday/Kconfig
+@@ -0,0 +1,111 @@
++#
++# arch/arm/mach-faraday/Kconfig
++#
++
++#
++# Faraday Platform Types Selection
++#
++choice
++	prompt "Platform Selection"
++	default PLATFORM_A320
++	depends on ARCH_FARADAY
++
++config PLATFORM_A320
++	bool "A320 evaluation board"
++	select ARM_GIC if CPU_FMP626
++	select DMADEVICES
++	select FTINTC010
++	select FTPMU010
++	select FTTMR010
++
++config PLATFORM_A369
++	bool "A369 evaluation board"
++	select ARM_GIC if CPU_FMP626
++	select DMADEVICES
++	select FTINTC010EX
++	select FTPWMTMR010
++	select FTSCU010
++	select FTAHBB020
++
++config PLATFORM_AXI
++	bool "AXI development board"
++	select ARM_GIC if CPU_FMP626
++	select DMADEVICES
++	select FTINTC010
++	select FTTMR010
++
++endchoice
++
++config FARADAY_HIGH_PHYS_OFFSET
++	bool "High physical base address for the Faraday platforms"
++	default y if CPU_FMP626
++	default n
++	help
++	  Faraday AHB bus controllers have a bit to swap ROM and RAM banks.
++	  Usually, we do the remap to map RAM to 0x0, but if we are using
++	  Multi-core processor e.g. FMP626, remapping will cause problem.
++
++config PLATFORM_FIA321
++	bool "A321 daughter board support"
++	depends on PLATFORM_A320
++
++config FTAHBB020
++	bool
++	help
++	   FTAHBB020 as external interrupt controller
++
++config FTAPBB020
++	tristate "FTAPBB020 DMA Engine"
++	select DMA_ENGINE
++	select ASYNC_TX_DISABLE_CHANNEL_SWITCH
++
++config FTDMAC020
++	tristate "FTDMAC020 DMA Engine"
++	select DMA_ENGINE
++	select ASYNC_TX_DISABLE_CHANNEL_SWITCH
++
++config FTDMAC030
++	tristate "FTDMAC030 DMA Engine"
++	select DMA_ENGINE
++	select ASYNC_TX_DISABLE_CHANNEL_SWITCH
++
++config FTINTC010
++	bool
++	help
++	   FTINTC010 interrupt controller
++
++config FTINTC010EX
++	bool
++	select FTINTC010
++	help
++	   newer version of FTINTC010 interrupt controller which supports up to 64 IRQ
++
++config FTPCI100
++	bool "Faraday PCI100 Support"
++	depends on PCI
++	help
++	  FTPCI100 bus driver
++
++config FTPMU010
++	bool
++	help
++	  Power Management Unit
++
++config FTPWMTMR010
++	bool
++	help
++	  FTPWMTMR010 timer
++
++config FTSCU010
++	bool
++	help
++	  System Controller
++
++config FTTMR010
++	bool
++	help
++	  FTTMR010 timer
++
++config ACP
++	bool "Use Accelerator Coherency Port"
++	depends on SMP
+diff --git a/arch/arm/mach-faraday/Makefile b/arch/arm/mach-faraday/Makefile
+new file mode 100644
+index 00000000..d28f7fa8
+--- /dev/null
++++ b/arch/arm/mach-faraday/Makefile
+@@ -0,0 +1,23 @@
++#
++# Makefile for the linux kernel.
++
++obj-y				+= clock.o
++
++obj-$(CONFIG_PLATFORM_A320)	+= board-a320.o
++obj-$(CONFIG_PLATFORM_A369)	+= board-a369.o
++obj-$(CONFIG_PLATFORM_AXI)	+= board-axi.o
++
++obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
++obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
++obj-$(CONFIG_LOCAL_TIMERS)	+= localtimer.o
++
++obj-$(CONFIG_FTAHBB020)		+= ftahbb020.o
++obj-$(CONFIG_FTAPBB020)		+= ftapbb020.o
++obj-$(CONFIG_FTDMAC020)		+= ftdmac020.o
++obj-$(CONFIG_FTDMAC030)		+= ftdmac030.o
++obj-$(CONFIG_FTINTC010)		+= ftintc010.o
++obj-$(CONFIG_FTPCI100) 		+= ftpci100.o
++obj-$(CONFIG_FTPMU010)		+= ftpmu010.o
++obj-$(CONFIG_FTPWMTMR010)	+= ftpwmtmr010.o
++obj-$(CONFIG_FTSCU010)		+= ftscu010.o
++obj-$(CONFIG_FTTMR010)		+= fttmr010.o
+diff --git a/arch/arm/mach-faraday/Makefile.boot b/arch/arm/mach-faraday/Makefile.boot
+new file mode 100644
+index 00000000..b9da0284
+--- /dev/null
++++ b/arch/arm/mach-faraday/Makefile.boot
+@@ -0,0 +1,10 @@
++ifeq ($(CONFIG_FARADAY_HIGH_PHYS_OFFSET),y)
++# memory not remapped
++   zreladdr-y	+= 0x10008000
++params_phys-y	:= 0x10000100
++initrd_phys-y	:= 0x10800000
++else
++   zreladdr-y	+= 0x00008000
++params_phys-y	:= 0x00000100
++initrd_phys-y	:= 0x00800000
++endif
+diff --git a/arch/arm/mach-faraday/board-a320.c b/arch/arm/mach-faraday/board-a320.c
+new file mode 100644
+index 00000000..061218d6
+--- /dev/null
++++ b/arch/arm/mach-faraday/board-a320.c
+@@ -0,0 +1,438 @@
++/*
++ *  linux/arch/arm/mach-faraday/board-a320.c
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/clk.h>
++#include <linux/clkdev.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-types.h>
++#ifdef CONFIG_CPU_FMP626
++#include <asm/localtimer.h>
++#include <asm/hardware/gic.h>
++#include <asm/pmu.h>
++#endif
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++
++#include <mach/board-a320.h>
++#include <mach/ftintc010.h>
++#include <mach/fttmr010.h>
++#include <mach/ftpci100.h>
++#include <mach/ftpmu010.h>
++
++#include "clock.h"
++#ifdef CONFIG_CPU_FMP626
++#include "core.h"
++#endif
++
++/******************************************************************************
++ * platform devices
++ *****************************************************************************/
++
++#ifdef CONFIG_CPU_FMP626
++static struct resource pmu_resources[] = {
++	[0] = {
++		.start		= IRQ_FMP626_PMU_CPU0,
++		.flags		= IORESOURCE_IRQ,
++	},
++	[1] = {
++		.start		= IRQ_FMP626_PMU_CPU1,
++		.flags		= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device pmu_device = {
++	.name			= "arm-pmu",
++	.id			= ARM_PMU_DEVICE_CPU,
++	.num_resources		= ARRAY_SIZE(pmu_resources),
++	.resource		= pmu_resources,
++};
++#endif
++
++/*
++ * FTAPBB020
++ */
++static struct resource ftapbb020_0_resources[] = {
++	{
++		.start	= A320_FTAPBB020_0_PA_BASE,
++		.end	= A320_FTAPBB020_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A320_FTAPBB020_0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftapbb020_0_device = {
++	.name		= "ftapbb020",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftapbb020_0_resources),
++	.resource	= ftapbb020_0_resources,
++};
++
++
++/*
++ * FTLCDC100
++ */
++static struct resource ftlcdc100_0_resources[] = {
++	{
++		.start	= A320_FTLCDC100_0_PA_BASE,
++		.end	= A320_FTLCDC100_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A320_FTLCDC100_0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftlcdc100_0_device = {
++	.name		= "ftlcdc100",
++	.num_resources	= ARRAY_SIZE(ftlcdc100_0_resources),
++	.resource	= ftlcdc100_0_resources,
++};
++
++/*
++ * FTMAC100
++ */
++static struct resource ftmac100_0_resources[] = {
++	{
++		.start	= A320_FTMAC100_0_PA_BASE,
++		.end	= A320_FTMAC100_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A320_FTMAC100_0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftmac100_0_device = {
++	.name		= "ftmac100",
++	.id		= 0,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftmac100_0_resources),
++	.resource	= ftmac100_0_resources,
++};
++
++#ifdef CONFIG_PLATFORM_FIA321
++static struct resource ftmac100_1_resources[] = {
++	{
++		.start	= A321_FTMAC100_0_PA_BASE,
++		.end	= A321_FTMAC100_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A321_FTMAC100_0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftmac100_1_device = {
++	.name		= "ftmac100",
++	.id		= 1,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftmac100_1_resources),
++	.resource	= ftmac100_1_resources,
++};
++#endif
++
++/*
++ * FTRTC010
++ */
++static struct resource ftrtc010_0_resources[] = {
++	{
++		.start	= A320_FTRTC010_0_PA_BASE,
++		.end	= A320_FTRTC010_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {		/* alarm interrupt */
++		.start	= IRQ_A320_FTRTC010_0_ALRM,
++		.flags	= IORESOURCE_IRQ,
++	}, {		/* periodic interrupt */
++		.start	= IRQ_A320_FTRTC010_0_SEC,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftrtc010_0_device = {
++	.name		= "ftrtc010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftrtc010_0_resources),
++	.resource	= ftrtc010_0_resources,
++};
++
++static struct platform_device *a320_devices[] __initdata = {
++#ifdef CONFIG_CPU_FMP626
++	&pmu_device,
++#endif
++	&ftapbb020_0_device,
++	&ftlcdc100_0_device,
++	&ftmac100_0_device,
++#ifdef CONFIG_PLATFORM_FIA321
++	&ftmac100_1_device,
++#endif
++	&ftrtc010_0_device,
++};
++
++/******************************************************************************
++ * clock functions
++ *****************************************************************************/
++static struct clk_lookup a320_clk_lookups[] = {
++	{
++		.con_id = "cpuclk",
++		.clk	= &ftpmu010_cpuclk,
++	}, {
++		.con_id	= "hclk",
++		.clk	= &ftpmu010_hclk,
++	}, {
++		.con_id	= "pclk",
++		.clk	= &ftpmu010_pclk,
++	}, {
++		.con_id	= "irda",
++		.clk	= &ftpmu010_irda_clk,
++	}, {
++		.con_id	= "ssp",
++		.clk	= &ftpmu010_ssp_clk,
++	}, {
++		.con_id	= "i2s",
++		.clk	= &ftpmu010_i2s_clk,
++	}, {
++		.con_id	= "ac97:1",
++		.clk	= &ftpmu010_ac97_clk1,
++	}, {
++		.con_id	= "ac97:2",
++		.clk	= &ftpmu010_ac97_clk2,
++	}, {
++		.con_id	= "uart",
++		.clk	= &ftpmu010_uart_clk,
++	}, {
++		.con_id	= "32768hz",
++		.clk	= &ftpmu010_32768hz_clk,
++	}
++};
++
++static int __init a320_clk_init(void)
++{
++	void __iomem *base = (void __iomem *)A320_FTPMU010_0_VA_BASE;
++
++	ftpmu010_main_clk.rate = MAIN_CLK;
++	ftpmu010_init(base);
++	clkdev_add_table(a320_clk_lookups, ARRAY_SIZE(a320_clk_lookups));
++	return 0;
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= IRQ_A320_FTTMR010_0_T0,
++	},
++	.base	= (void __iomem *)A320_FTTMR010_0_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)A320_FTTMR010_0_VA_BASE,
++	.id	= 1,
++};
++
++static void __init a320_sys_timer_init(void)
++{
++	struct clk *clk;
++	unsigned long cpuclk;
++	unsigned long hclk;
++	unsigned long pclk;
++
++	clk = clk_get(NULL, "cpuclk");
++	clk_enable(clk);
++	cpuclk = clk_get_rate(clk);
++
++	clk = clk_get(NULL, "hclk");
++	clk_enable(clk);
++	hclk = clk_get_rate(clk);
++
++	clk = clk_get(NULL, "pclk");
++	clk_enable(clk);
++	pclk = clk_get_rate(clk);
++
++	printk(KERN_INFO "CPU: %ld Hz, HCLK: %ld Hz, PCLK: %ld Hz\n", cpuclk, hclk, pclk);
++
++#ifdef CONFIG_LOCAL_TIMERS
++	twd_base = __io(PLATFORM_TWD_VA_BASE);
++#endif
++
++	fttmr010_0_clockevent.freq = pclk;
++	fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++	fttmr010_1_clocksource.freq = pclk;
++	fttmr010_clocksource_init(&fttmr010_1_clocksource);
++}
++
++static struct sys_timer a320_sys_timer = {
++	.init	= a320_sys_timer_init,
++};
++
++/******************************************************************************
++ * platform dependent functions
++ *****************************************************************************/
++static struct map_desc a320_io_desc[] __initdata = {
++	{
++#ifdef CONFIG_CPU_FMP626
++		/* SCU, GIC CPU and TWD */
++		.virtual	= PLATFORM_SCU_VA_BASE,
++		.pfn		= __phys_to_pfn(PLATFORM_SCU_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {	/* GIC DIST */
++		.virtual	= PLATFORM_GIC_DIST_VA_BASE,
++		.pfn		= __phys_to_pfn(PLATFORM_GIC_DIST_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++#endif
++		.virtual	= A320_FTINTC010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A320_FTINTC010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A320_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A320_FTUART010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A320_FTUART010_1_VA_BASE,
++		.pfn		= __phys_to_pfn(A320_FTUART010_1_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A320_FTUART010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(A320_FTUART010_2_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A320_FTTMR010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A320_FTTMR010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A320_FTPMU010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A320_FTPMU010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++#ifdef CONFIG_PLATFORM_FIA321
++	}, {
++		.virtual	= A321_FTINTC010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A321_FTINTC010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A321_FTPCI100_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A321_FTPCI100_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++#endif
++	},
++};
++
++static void __init a320_map_io(void)
++{
++	iotable_init((struct map_desc*)a320_io_desc, ARRAY_SIZE(a320_io_desc));
++	init_consistent_dma_size(SZ_8M);
++	a320_clk_init();
++
++#ifdef CONFIG_FTPCI100
++	ftpci100_init(0, __io(A321_FTPCI100_0_VA_BASE));
++#endif
++}
++
++static void __init a320_init_irq(void)
++{
++	/*
++	 * initialize primary interrupt controller
++	 */
++#ifndef CONFIG_CPU_FMP626
++	ftintc010_init(0, __io(A320_FTINTC010_0_VA_BASE), IRQ_A320_START);
++#else
++	gic_init(0, IRQ_LOCALTIMER, __io(PLATFORM_GIC_DIST_VA_BASE),__io(PLATFORM_GIC_CPU_VA_BASE));
++
++	/*
++	 * initialize second tier interrupt controller
++	 */
++	ftintc010_init(0, __io(A320_FTINTC010_0_VA_BASE), IRQ_A320_START);
++
++	ftintc010_cascade_irq(0, PLATFORM_LEGACY_IRQ);
++#endif
++
++	ftintc010_set_irq_type(IRQ_A320_FTGPIO010_0, IRQ_TYPE_EDGE_RISING);
++	ftintc010_set_irq_type(IRQ_A320_FTTMR010_0_T1, IRQ_TYPE_EDGE_RISING);
++	ftintc010_set_irq_type(IRQ_A320_FTTMR010_0_T2, IRQ_TYPE_EDGE_RISING);
++	ftintc010_set_irq_type(IRQ_A320_FTRTC010_0_ALRM, IRQ_TYPE_EDGE_RISING);
++	ftintc010_set_irq_type(IRQ_A320_FTRTC010_0_SEC, IRQ_TYPE_EDGE_RISING);
++	ftintc010_set_irq_type(IRQ_A320_FTTMR010_0_T0, IRQ_TYPE_EDGE_RISING);
++
++#ifdef CONFIG_PLATFORM_FIA321
++	/*
++	 * initialize second tier interrupt controller
++	 */
++	ftintc010_init(1, __io(A321_FTINTC010_0_VA_BASE), IRQ_A321_START);
++
++	ftintc010_cascade_irq(1, IRQ_A320_A321);
++
++	ftintc010_set_irq_type(IRQ_A321_FTKBC010_0, IRQ_TYPE_EDGE_RISING);
++	ftintc010_set_irq_type(IRQ_A321_FTKBC010_1, IRQ_TYPE_EDGE_RISING);
++
++#ifdef CONFIG_FTPCI100
++	/*
++	 * initialize third tier interrupt controller
++	 * because all 4 irqs of FTPCI100 are connected to the same pin of A321
++	 * we are compelled to make FTPCI100 be a third tier interrupt controller
++	 */
++	ftpci100_int_init(0, IRQ_FTPCI100_0_START);
++
++	ftpci100_int_cascade_irq(0, IRQ_A321_FTPCI100_0);
++#endif
++#endif
++}
++
++static void __init a320_board_init(void)
++{
++	platform_add_devices(a320_devices, ARRAY_SIZE(a320_devices));
++}
++
++MACHINE_START(FARADAY, "A320")
++	.atag_offset	= 0x100,
++	.map_io		= a320_map_io,
++	.init_irq	= a320_init_irq,
++	.timer		= &a320_sys_timer,
++	.init_machine	= a320_board_init,
++#ifdef CONFIG_CPU_FMP626
++	.handle_irq	= gic_handle_irq,
++#endif
++MACHINE_END
+diff --git a/arch/arm/mach-faraday/board-a369.c b/arch/arm/mach-faraday/board-a369.c
+new file mode 100644
+index 00000000..240e0caf
+--- /dev/null
++++ b/arch/arm/mach-faraday/board-a369.c
+@@ -0,0 +1,672 @@
++/*
++ *  linux/arch/arm/mach-faraday/board-a369.c
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/clk.h>
++#include <linux/clkdev.h>
++#include <linux/dma-mapping.h>
++#include <linux/i2c.h>
++#include <linux/platform_device.h>
++#include <linux/input/matrix_keypad.h>
++#include <linux/export.h>
++
++#include <asm/mach-types.h>
++#ifdef CONFIG_CPU_FMP626
++#include <asm/localtimer.h>
++#include <asm/hardware/gic.h>
++#include <asm/pmu.h>
++#endif
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++
++#include <mach/board-a369.h>
++#include <mach/dma-a369.h>
++#include <mach/ftahbb020.h>
++#include <mach/ftintc010.h>
++#include <mach/ftpwmtmr010.h>
++#include <mach/ftscu010.h>
++
++#include "clock.h"
++#ifdef CONFIG_CPU_FMP626
++#include "core.h"
++#endif
++
++/******************************************************************************
++ * platform keypad config
++ *****************************************************************************/
++static const unsigned int default_keymap[] = {
++	/* KEY(row, col, keycode) */
++	KEY(0, 0, KEY_BACK),	KEY(0, 1, KEY_UP),	KEY(0, 2, KEY_HOME),	/* PB1 - PB3 */
++	KEY(1, 0, KEY_LEFT),	KEY(1, 1, KEY_MENU),	KEY(1, 2, KEY_RIGHT),	/* PB4 - PB6 */
++	KEY(2, 0, KEY_SLEEP),	KEY(2, 1, KEY_DOWN),	KEY(2, 2, KEY_WAKEUP),	/* PB7 - PB9 */
++};
++
++static const struct matrix_keymap_data default_keymap_data = {
++	.keymap = default_keymap,
++	.keymap_size = ARRAY_SIZE(default_keymap),
++};
++
++static struct matrix_keypad_platform_data a369_keypad_config = {
++	.keymap_data = &default_keymap_data,
++	.num_row_gpios = 3,
++	.num_col_gpios = 3,
++};
++
++
++/******************************************************************************
++ * platform devices
++ *****************************************************************************/
++
++#ifdef CONFIG_CPU_FMP626
++static struct resource pmu_resources[] = {
++	[0] = {
++		.start		= IRQ_FMP626_PMU_CPU0,
++		.flags		= IORESOURCE_IRQ,
++	},
++	[1] = {
++		.start		= IRQ_FMP626_PMU_CPU1,
++		.flags		= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device pmu_device = {
++	.name			= "arm-pmu",
++	.id			= ARM_PMU_DEVICE_CPU,
++	.num_resources		= ARRAY_SIZE(pmu_resources),
++	.resource		= pmu_resources,
++};
++#endif
++
++/*
++ * FTAPBB020
++ */
++static struct resource ftapbb020_0_resources[] = {
++	{
++		.start	= A369_FTAPBB020_0_PA_BASE,
++		.end	= A369_FTAPBB020_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTAPBB020_0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftapbb020_0_device = {
++	.name		= "ftapbb020",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftapbb020_0_resources),
++	.resource	= ftapbb020_0_resources,
++};
++
++/*
++ * FTDMAC020
++ */
++static struct resource ftdmac020_0_resources[] = {
++	{
++		.start	= A369_FTDMAC020_0_PA_BASE,
++		.end	= A369_FTDMAC020_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTDMAC020_0_TC,
++		.flags	= IORESOURCE_IRQ,
++	}, {
++		.start	= IRQ_A369_FTDMAC020_0_ERR,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftdmac020_0_device = {
++	.name		= "ftdmac020",
++	.id		= 0,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_0_resources),
++	.resource	= ftdmac020_0_resources,
++};
++
++static struct resource ftdmac020_1_resources[] = {
++	{
++		.start	= A369_FTDMAC020_1_PA_BASE,
++		.end	= A369_FTDMAC020_1_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTDMAC020_1_TC,
++		.flags	= IORESOURCE_IRQ,
++	}, {
++		.start	= IRQ_A369_FTDMAC020_1_ERR,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftdmac020_1_device = {
++	.name		= "ftdmac020",
++	.id		= 1,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftdmac020_1_resources),
++	.resource	= ftdmac020_1_resources,
++};
++
++/*
++ * FTGMAC100
++ */
++static struct resource ftgmac100_0_resources[] = {
++	{
++		.start	= A369_FTGMAC100_0_PA_BASE,
++		.end	= A369_FTGMAC100_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTGMAC100_0_IRQ,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftgmac100_0_device = {
++	.name		= "ftgmac100",
++	.id		= 0,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftgmac100_0_resources),
++	.resource	= ftgmac100_0_resources,
++};
++
++/*
++ * FTIIC010
++ */
++static struct resource ftiic010_0_resources[] = {
++	{
++		.start	= A369_FTIIC010_0_PA_BASE,
++		.end	= A369_FTIIC010_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTIIC010_0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_0_device = {
++	.name		= "ftiic010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftiic010_0_resources),
++	.resource	= ftiic010_0_resources,
++};
++
++static struct resource ftiic010_1_resources[] = {
++	{
++		.start	= A369_FTIIC010_1_PA_BASE,
++		.end	= A369_FTIIC010_1_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTIIC010_1,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftiic010_1_device = {
++	.name		= "ftiic010",
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftiic010_1_resources),
++	.resource	= ftiic010_1_resources,
++};
++
++/*
++ * FTKBC010
++ */
++static struct resource ftkbc010_0_resources[] = {
++	{
++		.start	= A369_FTKBC010_0_PA_BASE,
++		.end	= A369_FTKBC010_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTKBC010_0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftkbc010_0_device = {
++	.name		= "ftkbc010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftkbc010_0_resources),
++	.resource	= ftkbc010_0_resources,
++	.dev		= {
++		.platform_data = &a369_keypad_config,
++	}
++};
++
++/*
++ * FTLCDC200
++ */
++static struct resource ftlcdc200_0_resources[] = {
++	{
++		.start	= A369_FTLCDC200_0_PA_BASE,
++		.end	= A369_FTLCDC200_0_PA_BASE + SZ_64K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {	/* bus error */
++		.start	= IRQ_A369_FTLCDC200_0_MERR,
++		.flags	= IORESOURCE_IRQ,
++	}, {	/* FIFO underrun */
++		.start	= IRQ_A369_FTLCDC200_0_FUR,
++		.flags	= IORESOURCE_IRQ,
++	}, {	/* base address update */
++		.start	= IRQ_A369_FTLCDC200_0_BAUPD,
++		.flags	= IORESOURCE_IRQ,
++	}, {	/* vertical status */
++		.start	= IRQ_A369_FTLCDC200_0_VSTATUS,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftlcdc200_0_device = {
++	.name		= "ftlcdc200",
++	.id		= 0,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftlcdc200_0_resources),
++	.resource	= ftlcdc200_0_resources,
++};
++
++/*
++ * FTRTC011
++ */
++static struct resource ftrtc011_0_resources[] = {
++	{
++		.start	= A369_FTRTC011_0_PA_BASE,
++		.end	= A369_FTRTC011_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {	/* alarm interrupt */
++		.start	= IRQ_A369_FTRTC011_0_ALRM,
++		.flags	= IORESOURCE_IRQ,
++	}, {	/* periodic interrupt */
++		.start	= IRQ_A369_FTRTC011_0_SEC,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftrtc011_0_device = {
++	.name		= "ftrtc011",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftrtc011_0_resources),
++	.resource	= ftrtc011_0_resources,
++};
++
++/*
++ * FTSDC010
++ */
++static struct resource ftsdc010_0_resources[] = {
++	{
++		.start	= A369_FTSDC010_0_PA_BASE,
++		.end	= A369_FTSDC010_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTSDC010_0,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftsdc010_0_device = {
++	.name		= "ftsdc010",
++	.id		= 0,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftsdc010_0_resources),
++	.resource	= ftsdc010_0_resources,
++};
++
++static struct resource ftsdc010_1_resources[] = {
++	{
++		.start	= A369_FTSDC010_1_PA_BASE,
++		.end	= A369_FTSDC010_1_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTSDC010_1,
++		.flags	= IORESOURCE_IRQ,
++	}
++};
++
++static struct platform_device ftsdc010_1_device = {
++	.name		= "ftsdc010",
++	.id		= 1,
++	.dev		= {
++		.coherent_dma_mask	= DMA_BIT_MASK(32),
++	},
++	.num_resources	= ARRAY_SIZE(ftsdc010_1_resources),
++	.resource	= ftsdc010_1_resources,
++};
++
++/*
++ * FTSSP010
++ */
++static struct resource ftssp010_0_i2s_resources[] = {
++	{
++		.start	= A369_FTSSP010_0_PA_BASE,
++		.end	= A369_FTSSP010_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {
++		.start	= IRQ_A369_FTSSP010_0,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device ftssp010_0_i2s_device = {
++	.name		= "ftssp010-i2s",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftssp010_0_i2s_resources),
++	.resource	= ftssp010_0_i2s_resources,
++};
++
++/*
++ * FTTSC010
++ *
++ * Note: Sytlus interrupt of FTTSC010 on A369 is broken.
++ */
++static struct resource fttsc010_0_resources[] = {
++	{
++		.start	= A369_FTTSC010_0_PA_BASE,
++		.end	= A369_FTTSC010_0_PA_BASE + SZ_4K - 1,
++		.flags	= IORESOURCE_MEM,
++	}, {	/* ADC interrupt */
++		.start	= IRQ_A369_FTTSC010_0_ADC,
++		.flags	= IORESOURCE_IRQ,
++	}, {	/* stylus interrupt */
++		.start	= IRQ_A369_FTTSC010_0_PANEL,
++		.flags	= IORESOURCE_IRQ,
++	},
++};
++
++static struct platform_device fttsc010_0_device = {
++	.name		= "fttsc010",
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(fttsc010_0_resources),
++	.resource	= fttsc010_0_resources,
++};
++
++static struct platform_device *a369_devices[] __initdata = {
++#ifdef CONFIG_CPU_FMP626
++	&pmu_device,
++#endif
++	&ftapbb020_0_device,
++	&ftdmac020_0_device,
++	&ftdmac020_1_device,
++	&ftgmac100_0_device,
++	&ftkbc010_0_device,
++	&ftiic010_0_device,
++	&ftiic010_1_device,
++	&ftlcdc200_0_device,
++	&ftrtc011_0_device,
++	&ftsdc010_0_device,
++	&ftsdc010_1_device,
++	&ftssp010_0_i2s_device,
++	&fttsc010_0_device,
++};
++
++/******************************************************************************
++ * I2C devices
++ *****************************************************************************/
++static struct i2c_board_info __initdata a369_i2c_devices[] = {
++	{ I2C_BOARD_INFO("wm8731", 0x1b), },
++};
++
++/******************************************************************************
++ * clock functions
++ *****************************************************************************/
++static struct clk_lookup a369_clk_lookups[] = {
++	{
++		.con_id	= "dclk",
++		.clk	= &ftscu010_dclk,
++	}, {
++		.con_id	= "mclk",
++		.clk	= &ftscu010_mclk,
++	}, {
++		.con_id	= "hclk",
++		.clk	= &ftscu010_hclk,
++	}, {
++		.con_id	= "pclk",
++		.clk	= &ftscu010_pclk,
++	}, {
++		.con_id = "extahb",
++		.clk	= &ftscu010_extahb_clk,
++	}, {
++		.con_id	= "mcpu_clk",
++		.clk	= &ftscu010_mcpu_clk,
++	}, {
++		.con_id = "ssp0-extclk",
++		.clk	= &ftscu010_ssp0_extclk,
++	}, {
++		.con_id = "tsc",
++		.clk	= &ftscu010_tsc_clk,
++	},
++};
++
++static int __init a369_clk_init(void)
++{
++	void __iomem *base = (void __iomem *)A369_FTSCU010_0_VA_BASE;
++
++	ftscu010_main_clk.rate = MAIN_CLK;
++	ftscu010_init(base);
++	clkdev_add_table(a369_clk_lookups, ARRAY_SIZE(a369_clk_lookups));
++	return 0;
++}
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct ftpwmtmr010_clockevent ftpwmtmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "ftpwmtmr010:0",
++		.irq	= IRQ_A369_FTPWMTMR010_0_T0,
++	},
++	.base	= (void __iomem *)A369_FTPWMTMR010_0_VA_BASE,
++	.id	= 0,
++};
++
++static struct ftpwmtmr010_clocksource ftpwmtmr010_1_clocksource = {
++	.clocksource = {
++		.name	= "ftpwmtmr010:1",
++	},
++	.base	= (void __iomem *)A369_FTPWMTMR010_0_VA_BASE,
++	.id	= 1,
++};
++
++static void __init a369_sys_timer_init(void)
++{
++	struct clk *clk;
++	unsigned long cpuclk;
++	unsigned long hclk;
++	unsigned long pclk;
++	unsigned long extahbclk;
++
++	clk = clk_get(NULL, "mcpu_clk");
++	clk_enable(clk);
++	cpuclk = clk_get_rate(clk);
++
++	clk = clk_get(NULL, "hclk");
++	clk_enable(clk);
++	hclk = clk_get_rate(clk);
++
++	clk = clk_get(NULL, "pclk");
++	clk_enable(clk);
++	pclk = clk_get_rate(clk);
++
++	clk = clk_get(NULL, "extahb");
++	clk_enable(clk);
++	extahbclk = clk_get_rate(clk);
++
++	printk(KERN_INFO "CPU: %ld Hz, HCLK: %ld Hz, PCLK: %ld Hz, ExtAHB: %ld\n", cpuclk, hclk, pclk, extahbclk);
++
++#ifdef CONFIG_LOCAL_TIMERS
++	twd_base = __io(PLATFORM_TWD_VA_BASE);
++#endif
++
++	ftpwmtmr010_0_clockevent.freq = pclk;
++	ftpwmtmr010_clockevent_init(&ftpwmtmr010_0_clockevent);
++
++	ftpwmtmr010_1_clocksource.freq = pclk;
++	ftpwmtmr010_clocksource_init(&ftpwmtmr010_1_clocksource);
++}
++
++static struct sys_timer a369_sys_timer = {
++	.init	= a369_sys_timer_init,
++};
++
++/******************************************************************************
++ * DMA function
++ *****************************************************************************/
++
++int a369_dmac_handshake_alloc(const char *name)
++{
++	return ftscu010_handshake_alloc(name);
++}
++EXPORT_SYMBOL(a369_dmac_handshake_alloc);
++
++int a369_dmac_handshake_setup(unsigned int handshake, int which)
++{
++	return ftscu010_handshake_setup(handshake, which);
++}
++EXPORT_SYMBOL(a369_dmac_handshake_setup);
++
++int a369_dmac_handshake_free(unsigned int handshake)
++{
++	return ftscu010_handshake_free(handshake);
++}
++EXPORT_SYMBOL(a369_dmac_handshake_free);
++
++/******************************************************************************
++ * platform dependent functions
++ *****************************************************************************/
++
++static struct map_desc a369_io_desc[] __initdata = {
++	{
++#ifdef CONFIG_CPU_FMP626
++		/* SCU, GIC CPU and TWD */
++		.virtual	= PLATFORM_SCU_VA_BASE,
++		.pfn		= __phys_to_pfn(PLATFORM_SCU_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {	/* GIC DIST */
++		.virtual	= PLATFORM_GIC_DIST_VA_BASE,
++		.pfn		= __phys_to_pfn(PLATFORM_GIC_DIST_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++#endif
++		.virtual	= A369_FTINTC020_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A369_FTINTC020_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A369_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A369_FTUART010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A369_FTUART010_1_VA_BASE,
++		.pfn		= __phys_to_pfn(A369_FTUART010_1_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A369_FTUART010_2_VA_BASE,
++		.pfn		= __phys_to_pfn(A369_FTUART010_2_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A369_FTUART010_3_VA_BASE,
++		.pfn		= __phys_to_pfn(A369_FTUART010_3_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A369_FTPWMTMR010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A369_FTPWMTMR010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A369_FTSCU010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(A369_FTSCU010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= A369_FTAHBB020_3_VA_BASE,
++		.pfn		= __phys_to_pfn(A369_FTAHBB020_3_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	},
++};
++
++static void __init a369_map_io(void)
++{
++	iotable_init((struct map_desc*)a369_io_desc, ARRAY_SIZE(a369_io_desc));
++	init_consistent_dma_size(SZ_8M);
++	a369_clk_init();
++}
++
++static void __init a369_init_irq(void)
++{
++	/*
++	 * initialize primary interrupt controller
++	 */
++#ifndef CONFIG_CPU_FMP626
++	ftintc010_init(0, __io(A369_FTINTC020_0_VA_BASE), IRQ_A369_START);
++#else
++	gic_init(0, IRQ_LOCALTIMER, __io(PLATFORM_GIC_DIST_VA_BASE),__io(PLATFORM_GIC_CPU_VA_BASE));
++
++	/*
++	 * initialize second tier interrupt controller
++	 */
++	ftintc010_init(0, __io(A369_FTINTC020_0_VA_BASE), IRQ_A369_START);
++
++	ftintc010_cascade_irq(0, PLATFORM_LEGACY_IRQ);
++#endif
++
++	/*
++	 * initialize second tier interrupt controller
++	 */
++	ftahbb020_init(0, __io(A369_FTAHBB020_3_VA_BASE), IRQ_FTAHBB020_3_START);
++
++	ftahbb020_cascade_irq(0, IRQ_A369_FTAHBB020_3);
++
++	ftahbb020_set_irq_type(IRQ_FTAHBB020_3_EXINT(0), IRQ_TYPE_LEVEL_LOW);
++	ftahbb020_set_irq_type(IRQ_FTAHBB020_3_EXINT(1), IRQ_TYPE_LEVEL_LOW);
++}
++
++static void __init a369_board_init(void)
++{
++	/* default pin mux setting */
++	ftscu010_pinmux_setup("lcd", "lcd_mice");
++
++	i2c_register_board_info(0, a369_i2c_devices, ARRAY_SIZE(a369_i2c_devices));
++	platform_add_devices(a369_devices, ARRAY_SIZE(a369_devices));
++}
++
++MACHINE_START(FARADAY, "A369")
++	.atag_offset	= 0x100,
++	.map_io		= a369_map_io,
++	.init_irq	= a369_init_irq,
++	.timer		= &a369_sys_timer,
++	.init_machine	= a369_board_init,
++#ifdef CONFIG_CPU_FMP626
++	.handle_irq     = gic_handle_irq,
++#endif
++MACHINE_END
+diff --git a/arch/arm/mach-faraday/board-axi.c b/arch/arm/mach-faraday/board-axi.c
+new file mode 100644
+index 00000000..759627c0
+--- /dev/null
++++ b/arch/arm/mach-faraday/board-axi.c
+@@ -0,0 +1,116 @@
++/*
++ *  linux/arch/arm/mach-faraday/board-axi.c
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/platform_device.h>
++
++#include <asm/mach-types.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/time.h>
++
++#include <mach/board-axi.h>
++#include <mach/fttmr010.h>
++#include <mach/ftintc010.h>
++
++/******************************************************************************
++ * timer - clockevent and clocksource
++ *****************************************************************************/
++static struct fttmr010_clockevent fttmr010_0_clockevent = {
++	.clockevent = {
++		.name	= "fttmr010:0",
++		.irq	= IRQ_AXI_FTTMR010_0_T0,
++	},
++	.base	= (void __iomem *)AXI_FTTMR010_0_VA_BASE,
++	.id	= 0,
++};
++
++static struct fttmr010_clocksource fttmr010_1_clocksource = {
++	.clocksource = {
++		.name	= "fttmr010:1",
++	},
++	.base	= (void __iomem *)AXI_FTTMR010_0_VA_BASE,
++	.id	= 1,
++};
++
++static void __init axi_sys_timer_init(void)
++{
++	fttmr010_0_clockevent.freq = CLOCK_TICK_RATE;
++	fttmr010_clockevent_init(&fttmr010_0_clockevent);
++
++	fttmr010_1_clocksource.freq = CLOCK_TICK_RATE;
++	fttmr010_clocksource_init(&fttmr010_1_clocksource);
++}
++
++static struct sys_timer axi_sys_timer = {
++	.init	= axi_sys_timer_init,
++};
++
++/******************************************************************************
++ * platform dependent functions
++ *****************************************************************************/
++static struct map_desc axi_io_desc[] __initdata = {
++	{
++		.virtual	= AXI_FTINTC010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(AXI_FTINTC010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= AXI_FTUART010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(AXI_FTUART010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= AXI_FTUART010_1_VA_BASE,
++		.pfn		= __phys_to_pfn(AXI_FTUART010_1_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	}, {
++		.virtual	= AXI_FTTMR010_0_VA_BASE,
++		.pfn		= __phys_to_pfn(AXI_FTTMR010_0_PA_BASE),
++		.length		= SZ_4K,
++		.type		= MT_DEVICE,
++	},
++};
++
++static void __init axi_map_io(void)
++{
++	iotable_init((struct map_desc*)axi_io_desc, ARRAY_SIZE(axi_io_desc));
++}
++
++static void __init axi_init_irq(void)
++{
++	/*
++	 * initialize primary interrupt controller
++	 */
++	ftintc010_init(0, __io(AXI_FTINTC010_0_VA_BASE), IRQ_AXI_START);
++
++	ftintc010_set_irq_type(IRQ_AXI_FTTMR010_0_T0, IRQ_TYPE_EDGE_RISING);
++	ftintc010_set_irq_type(IRQ_AXI_FTTMR010_0_T1, IRQ_TYPE_EDGE_RISING);
++	ftintc010_set_irq_type(IRQ_AXI_FTTMR010_0_T2, IRQ_TYPE_EDGE_RISING);
++}
++
++MACHINE_START(FARADAY, "AXI")
++	.boot_params	= PHYS_OFFSET + 0x00000100,
++	.map_io		= axi_map_io,
++	.init_irq	= axi_init_irq,
++	.timer		= &axi_sys_timer,
++MACHINE_END
+diff --git a/arch/arm/mach-faraday/clock.c b/arch/arm/mach-faraday/clock.c
+new file mode 100644
+index 00000000..e207d2c5
+--- /dev/null
++++ b/arch/arm/mach-faraday/clock.c
+@@ -0,0 +1,111 @@
++/*
++ *  linux/arch/arm/mach-faraday/clock.c
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/clk.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++
++#include <linux/clkdev.h>
++
++#include "clock.h"
++
++static DEFINE_SPINLOCK(clk_lock);
++
++void __clk_enable(struct clk *clk)
++{
++	if (clk->parent)
++		__clk_enable(clk->parent);
++	if (clk->users++ == 0 && clk->mode)
++		clk->mode(clk, 1);
++}
++
++int clk_enable(struct clk *clk)
++{
++	unsigned long	flags;
++
++	spin_lock_irqsave(&clk_lock, flags);
++	__clk_enable(clk);
++	spin_unlock_irqrestore(&clk_lock, flags);
++	return 0;
++}
++EXPORT_SYMBOL(clk_enable);
++
++void __clk_disable(struct clk *clk)
++{
++	BUG_ON(clk->users == 0);
++	if (--clk->users == 0 && clk->mode)
++		clk->mode(clk, 0);
++	if (clk->parent)
++		__clk_disable(clk->parent);
++}
++
++void clk_disable(struct clk *clk)
++{
++	unsigned long	flags;
++
++	spin_lock_irqsave(&clk_lock, flags);
++	__clk_disable(clk);
++	spin_unlock_irqrestore(&clk_lock, flags);
++}
++EXPORT_SYMBOL(clk_disable);
++
++unsigned long __clk_get_rate(struct clk *clk)
++{
++	unsigned long rate;
++
++	rate = clk->rate;
++	if (rate == 0) {
++		if (clk->get_rate)
++			rate = clk->get_rate(clk);
++		else if (clk->parent)
++			rate = __clk_get_rate(clk->parent);
++	}
++
++	return rate;
++}
++
++unsigned long clk_get_rate(struct clk *clk)
++{
++	unsigned long flags;
++	unsigned long rate;
++
++	spin_lock_irqsave(&clk_lock, flags);
++	rate = __clk_get_rate(clk);
++	spin_unlock_irqrestore(&clk_lock, flags);
++	return rate;
++}
++EXPORT_SYMBOL(clk_get_rate);
++
++int clk_set_rate(struct clk *clk, unsigned long rate)
++{
++	unsigned long flags;
++	int ret = -EINVAL;
++
++	if (clk == NULL || clk->set_rate == NULL || rate == 0)
++		return ret;
++
++	spin_lock_irqsave(&clk_lock, flags);
++	ret = clk->set_rate(clk, rate);
++	spin_unlock_irqrestore(&clk_lock, flags);
++
++	return ret;
++}
++EXPORT_SYMBOL(clk_set_rate);
+diff --git a/arch/arm/mach-faraday/clock.h b/arch/arm/mach-faraday/clock.h
+new file mode 100644
+index 00000000..1a132480
+--- /dev/null
++++ b/arch/arm/mach-faraday/clock.h
+@@ -0,0 +1,41 @@
++/*
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __ARCH_ARM_FARADAY_CLOCK_H
++#define __ARCH_ARM_FARADAY_CLOCK_H
++
++struct clk {
++	struct clk	*parent;
++	int		users;
++	unsigned long	rate;
++	void __iomem	*base;	/* base address of controller if any */
++	unsigned long	(*get_rate)(struct clk *clk);
++	int		(*set_rate)(struct clk *clk, unsigned long rate);
++	int		(*mode)(struct clk *, int on);
++	void		*params;
++};
++
++/*
++ * These functions assume that lock is already held.
++ */
++void __clk_enable(struct clk *clk);
++void __clk_disable(struct clk *clk);
++unsigned long __clk_get_rate(struct clk *clk);
++
++#endif
+diff --git a/arch/arm/mach-faraday/core.h b/arch/arm/mach-faraday/core.h
+new file mode 100644
+index 00000000..c8b44230
+--- /dev/null
++++ b/arch/arm/mach-faraday/core.h
+@@ -0,0 +1,27 @@
++/*
++ *  linux/arch/arm/mach-realview/core.h
++ *
++ *  Copyright (C) 2004 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_REALVIEW_H
++#define __ASM_ARCH_REALVIEW_H
++
++#include <linux/io.h>
++
++#endif
+diff --git a/arch/arm/mach-faraday/ftahbb020.c b/arch/arm/mach-faraday/ftahbb020.c
+new file mode 100644
+index 00000000..4fa3696e
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftahbb020.c
+@@ -0,0 +1,348 @@
++/*
++ *  linux/arch/arm/mach-faraday/ftahbb020.c
++ *
++ *  Faraday FTAHBB020 Interrupt Controller
++ *
++ *  Copyright (C) 2020 Faraday Technology
++ *  Copyright (C) 2020 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++
++#include <asm/mach/irq.h>
++#include <mach/ftahbb020.h>
++
++struct ftahbb020_chip_data {
++	unsigned int irq_offset;
++	void __iomem *base;
++};
++
++#ifndef MAX_FTAHBB020_NR
++#define MAX_FTAHBB020_NR	1
++#endif
++
++static struct ftahbb020_chip_data ftahbb020_data[MAX_FTAHBB020_NR];
++static DEFINE_SPINLOCK(ftahbb020_lock);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline void __iomem *ftahbb020_base(struct irq_data *d)
++{
++	struct ftahbb020_chip_data *chip_data = irq_data_get_irq_chip_data(d);
++	return chip_data->base;
++}
++
++/*
++ * return hardware irq number
++ */
++static inline unsigned int ftahbb020_irq(struct irq_data *d)
++{
++	struct ftahbb020_chip_data *chip_data = irq_data_get_irq_chip_data(d);
++	return d->irq - chip_data->irq_offset;
++}
++
++static inline void ftahbb020_clear_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask = 1 << hw_irq;
++
++	writel(mask, base + FTAHBB020_OFFSET_S2P_XIRQCLEAR);
++}
++
++static inline void ftahbb020_mask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	mask = readl(base + FTAHBB020_OFFSET_S2P_XIRQMASK);
++	mask |= 1 << hw_irq;
++	writel(mask, base + FTAHBB020_OFFSET_S2P_XIRQMASK);
++}
++
++static inline void ftahbb020_unmask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	mask = readl(base + FTAHBB020_OFFSET_S2P_XIRQMASK);
++	mask &= ~(1 << hw_irq);
++	writel(mask, base + FTAHBB020_OFFSET_S2P_XIRQMASK);
++}
++
++static inline void ftahbb020_set_trig_mode(void __iomem *base, unsigned int hw_irq,
++	int mode)
++{
++	unsigned int irqmode;
++
++	irqmode = readl(base + FTAHBB020_OFFSET_S2P_XIRQMODE);
++
++	/*
++	 * 0: edge trigger
++	 * 1: level trigger
++	 */
++	if (mode)
++		irqmode |= 1 << hw_irq;
++	else
++		irqmode &= ~(1 << hw_irq);
++
++	writel(irqmode, base + FTAHBB020_OFFSET_S2P_XIRQMODE);
++}
++
++static inline void ftahbb020_set_trig_level(void __iomem *base, unsigned int hw_irq,
++	int level)
++{
++	unsigned int irqlevel;
++
++	irqlevel = readl(base + FTAHBB020_OFFSET_S2P_XIRQLEVEL);
++
++	/*
++	 * 0: active-high level trigger / rising edge trigger
++	 * 1: active-low level trigger / falling edge trigger
++	 */
++	if (level)
++		irqlevel |= 1 << hw_irq;
++	else
++		irqlevel &= ~(1 << hw_irq);
++
++	writel(irqlevel, base + FTAHBB020_OFFSET_S2P_XIRQLEVEL);
++}
++
++static inline void ftahbb020_set_trig_both(void __iomem *base, unsigned int hw_irq,
++	int both)
++{
++	unsigned int irqboth;
++
++	irqboth = readl(base + FTAHBB020_OFFSET_S2P_XIRQBOTH);
++
++	if (both)
++		irqboth |= 1 << hw_irq;
++	else
++		irqboth &= ~(1 << hw_irq);
++
++	writel(irqboth, base + FTAHBB020_OFFSET_S2P_XIRQBOTH);
++}
++
++/******************************************************************************
++ * struct irq_chip functions
++ *****************************************************************************/
++static int ftahbb020_set_type(struct irq_data *d, unsigned int type)
++{
++	unsigned int hw_irq = ftahbb020_irq(d);
++	void __iomem *base = ftahbb020_base(d);
++	int mode = 0;
++	int both = 0;
++	int level = 0;
++
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_LEVEL_HIGH:
++		mode = 1;
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_EDGE_RISING:
++		break;
++
++	case IRQ_TYPE_EDGE_BOTH:
++		both = 1;
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	spin_lock(&ftahbb020_lock);
++	ftahbb020_set_trig_mode(base, hw_irq, mode);
++	ftahbb020_set_trig_both(base, hw_irq, both);
++	ftahbb020_set_trig_level(base, hw_irq, level);
++	spin_unlock(&ftahbb020_lock);
++	return 0;
++}
++
++/*
++ * Edge trigger IRQ chip methods
++ */
++static void ftahbb020_edge_ack(struct irq_data *d)
++{
++	unsigned int hw_irq = ftahbb020_irq(d);
++	void __iomem *base = ftahbb020_base(d);
++
++	spin_lock(&ftahbb020_lock);
++	ftahbb020_clear_irq(base, hw_irq);
++	spin_unlock(&ftahbb020_lock);
++}
++
++static void ftahbb020_mask(struct irq_data *d)
++{
++	unsigned int hw_irq = ftahbb020_irq(d);
++	void __iomem *base = ftahbb020_base(d);
++
++	spin_lock(&ftahbb020_lock);
++	ftahbb020_mask_irq(base, hw_irq);
++	spin_unlock(&ftahbb020_lock);
++}
++
++static void ftahbb020_unmask(struct irq_data *d)
++{
++	unsigned int hw_irq = ftahbb020_irq(d);
++	void __iomem *base = ftahbb020_base(d);
++
++	spin_lock(&ftahbb020_lock);
++	ftahbb020_unmask_irq(base, hw_irq);
++	spin_unlock(&ftahbb020_lock);
++}
++
++static struct irq_chip ftahbb020_edge_chip = {
++	.irq_ack	= ftahbb020_edge_ack,
++	.irq_mask	= ftahbb020_mask,
++	.irq_unmask	= ftahbb020_unmask,
++	.irq_set_type	= ftahbb020_set_type,
++};
++
++/*
++ * Level trigger IRQ chip methods
++ */
++static void ftahbb020_level_ack(struct irq_data *d)
++{
++	/* do nothing */
++}
++
++static struct irq_chip ftahbb020_level_chip = {
++	.irq_ack	= ftahbb020_level_ack,
++	.irq_mask	= ftahbb020_mask,
++	.irq_unmask	= ftahbb020_unmask,
++	.irq_set_type	= ftahbb020_set_type,
++};
++
++/******************************************************************************
++ * initialization functions
++ *****************************************************************************/
++static void ftahbb020_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
++{
++	struct ftahbb020_chip_data *chip_data = irq_get_handler_data(irq);
++	struct irq_chip *chip = irq_get_chip(irq);
++	unsigned int cascade_irq, hw_irq;
++	unsigned long status;
++	unsigned long mask;
++
++	/* primary controller ack'ing */
++	chip->irq_mask(&desc->irq_data);
++	chip->irq_ack(&desc->irq_data);
++
++	spin_lock(&ftahbb020_lock);
++	status = readl(chip_data->base + FTAHBB020_OFFSET_S2P_XIRQSRC);
++	mask = readl(chip_data->base + FTAHBB020_OFFSET_S2P_XIRQMASK);
++	spin_unlock(&ftahbb020_lock);
++
++	status &= ~mask;
++	if (!status)
++		goto out;
++
++	hw_irq = ffs(status) - 1;
++
++	cascade_irq = hw_irq + chip_data->irq_offset;
++	generic_handle_irq(cascade_irq);
++
++out:
++	/* primary controller unmasking */
++	chip->irq_unmask(&desc->irq_data);
++}
++
++void __init ftahbb020_cascade_irq(unsigned int ftahbb020_nr, unsigned int irq)
++{
++	if (ftahbb020_nr >= MAX_FTAHBB020_NR)
++		BUG();
++	if (irq_set_handler_data(irq, &ftahbb020_data[ftahbb020_nr]) != 0)
++		BUG();
++
++	irq_set_chained_handler(irq, ftahbb020_handle_cascade_irq);
++}
++
++int ftahbb020_set_irq_type(unsigned int irq, unsigned int type)
++{
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++	case IRQ_TYPE_LEVEL_HIGH:
++		irq_set_chip(irq, &ftahbb020_level_chip);
++		irq_set_handler(irq, handle_level_irq);
++		break;
++
++	case IRQ_TYPE_EDGE_BOTH:
++	case IRQ_TYPE_EDGE_FALLING:
++	case IRQ_TYPE_EDGE_RISING:
++		irq_set_chip(irq, &ftahbb020_edge_chip);
++		irq_set_handler(irq, handle_edge_irq);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	return irq_set_irq_type(irq, type);
++}
++
++/*
++ * Initialization of external interrupt controller.
++ */
++void __init ftahbb020_init(unsigned int ftahbb020_nr, void __iomem *base,
++			   unsigned int irq_start)
++{
++	unsigned int irq;
++	unsigned int irq_end;
++
++	if (ftahbb020_nr >= MAX_FTAHBB020_NR)
++		BUG();
++
++	ftahbb020_data[ftahbb020_nr].base = base;
++	ftahbb020_data[ftahbb020_nr].irq_offset = irq_start;
++
++	/*
++	 * mask all external interrupts
++	 */
++	writel(~0, base + FTAHBB020_OFFSET_S2P_XIRQMASK);
++	writel(~0, base + FTAHBB020_OFFSET_S2P_XIRQCLEAR);
++
++	/*
++	 * initial trigger mode and level
++	 */
++	writel(0, base + FTAHBB020_OFFSET_S2P_XIRQMODE);
++	writel(0, base + FTAHBB020_OFFSET_S2P_XIRQBOTH);
++	writel(0, base + FTAHBB020_OFFSET_S2P_XIRQLEVEL);
++
++	/*
++	 * enable all external interrupts
++	 */
++	writel(~0, base + FTAHBB020_OFFSET_S2P_XIRQENABLE);
++
++	/*
++	 * setup the linux irq subsystem
++	 */
++	irq_end = irq_start + 32;
++	for (irq = irq_start; irq < irq_end; irq++) {
++		irq_set_chip_data(irq, &ftahbb020_data[ftahbb020_nr]);
++		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++		irq_set_chip(irq, &ftahbb020_level_chip);
++		irq_set_handler(irq, handle_level_irq);
++		irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
++	}
++}
+diff --git a/arch/arm/mach-faraday/ftapbb020.c b/arch/arm/mach-faraday/ftapbb020.c
+new file mode 100644
+index 00000000..b1897f2c
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftapbb020.c
+@@ -0,0 +1,1228 @@
++/*
++ * Faraday FTAPBB020 DMA engine driver
++ *
++ * (C) Copyright 2010 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <asm/io.h>
++
++#include <mach/ftapbb020.h>
++
++#define DRV_NAME	"ftapbb020"
++#define CHANNEL_NR	4
++
++/*
++ * This value must be multiple of 32-bits to prevent from changing the
++ * alignment of child descriptors.
++ */
++#define MAX_CYCLE_PER_BLOCK		0x00800000
++#if (MAX_CYCLE_PER_BLOCK > FTAPBB020_CYC_MASK) || (MAX_CYCLE_PER_BLOCK & 0x3)
++#error invalid MAX_CYCLE_PER_BLOCK
++#endif
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 64;
++module_param(init_nr_desc_per_channel, uint, 0644);
++MODULE_PARM_DESC(init_nr_desc_per_channel,
++		 "initial descriptors per channel (default: 64)");
++
++/**
++ * struct ftapbb020_desc - async transaction descriptor.
++ * @txd: support for the async_tx api
++ * @node: node on the descriptors list
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @cmd: command register content
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @len: length in bytes
++ */
++struct ftapbb020_desc {
++	struct dma_async_tx_descriptor txd;
++	struct list_head node;
++	struct list_head child_list;
++	struct ftapbb020_chan *ftchan;
++	unsigned int cmd;
++	dma_addr_t src;
++	dma_addr_t dst;
++	unsigned int cycle;
++	size_t len;
++};
++
++/**
++ * struct ftapbb020_chan - internal representation of an ftapbb020 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @pending_list: list of descriptors dmaengine which is wating to run
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftapbb020: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftapbb020_chan {
++	struct dma_chan	common;
++	struct list_head active_list;
++	struct list_head pending_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftapbb020 *ftapbb020;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++};
++
++/**
++ * struct ftapbb020 - internal representation of an ftapbb020 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @irq: irq number
++ * @channel: channel table
++ */
++struct ftapbb020 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	unsigned int irq;
++	struct ftapbb020_chan channel[CHANNEL_NR];
++};
++
++static dma_cookie_t ftapbb020_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftapbb020_stop_channel(struct ftapbb020_chan *ftchan)
++{
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	iowrite32(0, base + FTAPBB020_OFFSET_CMD(chan_id));
++}
++
++static void ftapbb020_stop_all_channels(struct ftapbb020 *ftapbb020)
++{
++	void __iomem *base = ftapbb020->base;
++	int i;
++
++	for (i = 0; i < CHANNEL_NR; i++)
++		iowrite32(0, base + FTAPBB020_OFFSET_CMD(i));
++}
++
++static int ftapbb020_chan_is_enabled(struct ftapbb020_chan *ftchan)
++{
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++	unsigned int cmd;
++
++	cmd = ioread32(base + FTAPBB020_OFFSET_CMD(chan_id));
++	return cmd & FTAPBB020_CMD_ENABLE;
++}
++
++/**
++ * ftapbb020_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftapbb020_desc *ftapbb020_alloc_desc(
++		struct ftapbb020_chan *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = kzalloc(sizeof(*desc), gfp_flags);
++	if (desc) {
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftapbb020_tx_submit;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftapbb020_free_desc(struct ftapbb020_desc *desc)
++{
++	struct dma_chan *chan = &desc->ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	kfree(desc);
++}
++
++/**
++ * ftapbb020_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftapbb020_desc *ftapbb020_desc_get(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc = NULL;
++
++	spin_lock_bh(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++			struct ftapbb020_desc, node);
++
++		list_del(&desc->node);
++	}
++	spin_unlock_bh(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftapbb020_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			spin_lock_bh(&ftchan->lock);
++			ftchan->descs_allocated++;
++			spin_unlock_bh(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftapbb020_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftapbb020_desc_put(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *child;
++
++	spin_lock_bh(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++static void ftapbb020_unmap_desc(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->dst, desc->len,
++				DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->dst, desc->len,
++				DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->src, desc->len,
++				DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->src, desc->len,
++				DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftapbb020_remove_chain(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *child;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->node, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftapbb020_unmap_desc(child);
++		ftapbb020_desc_put(child);
++	}
++
++	ftapbb020_unmap_desc(desc);
++	ftapbb020_desc_put(desc);
++}
++
++/**
++ * ftapbb020_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ * @cmd: command register content
++ */
++static struct ftapbb020_desc *ftapbb020_create_chain(
++		struct ftapbb020_chan *ftchan,
++		struct ftapbb020_desc *first,
++		dma_addr_t src, dma_addr_t dest, size_t len,
++		unsigned int shift, int fixed_src, int fixed_dest,
++		unsigned int cmd)
++{
++	struct dma_chan *chan = &ftchan->common;
++	size_t offset;
++	unsigned int cycle;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, shift %d)\n",
++		__func__, src, dest, len, shift);
++	if ((shift == 2 && ((src | dest | len) & 3)) ||
++	    (shift == 1 && ((src | dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	for (offset = 0; offset < len; offset += cycle << shift) {
++		struct ftapbb020_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> shift,
++				MAX_CYCLE_PER_BLOCK);
++
++		cycle &= FTAPBB020_CYC_MASK;
++
++		desc = ftapbb020_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		if (fixed_src)
++			desc->src = src;
++		else
++			desc->src = src + offset;
++
++		if (fixed_dest)
++			desc->dst = dest;
++		else
++			desc->dst = dest + offset;
++
++		desc->cmd = cmd;
++		desc->len = cycle << shift;
++		desc->cycle = cycle;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++	}
++
++	return first;
++err:
++	if (first)
++		ftapbb020_remove_chain(first);
++	return NULL;
++}
++
++static void ftapbb020_start_desc(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	unsigned int cmd = desc->cmd;
++	void __iomem *base = ftchan->ftapbb020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	cmd |= FTAPBB020_CMD_ENABLE
++	    |  FTAPBB020_CMD_FININT_E
++	    |  FTAPBB020_CMD_ERRINT_E;
++
++	dev_dbg(chan2dev(chan), "\t[SAR %d] = %x\n", chan_id, desc->src);
++	iowrite32(desc->src, base + FTAPBB020_OFFSET_SAR(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DAR %d] = %x\n", chan_id, desc->dst);
++	iowrite32(desc->dst, base + FTAPBB020_OFFSET_DAR(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	iowrite32(desc->cycle, base + FTAPBB020_OFFSET_CYC(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CMD %d] = %x\n", chan_id, cmd);
++	iowrite32(cmd, base + FTAPBB020_OFFSET_CMD(chan_id));
++}
++
++static void ftapbb020_activate_chain(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	/* move new transfer chain to active list */
++	list_add_tail(&desc->node, &ftchan->active_list);
++	list_splice_tail_init(&desc->child_list, &ftchan->active_list);
++
++	/* start first descriptor */
++	ftapbb020_start_desc(desc);
++}
++
++static void ftapbb020_start_next_chain(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *new;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->pending_list))
++		return;
++
++	new = list_first_entry(&ftchan->pending_list, struct ftapbb020_desc,
++		node);
++	list_del(&new->node);
++
++	ftapbb020_activate_chain(new);
++}
++
++static void ftapbb020_invoke_callback(struct ftapbb020_desc *desc)
++{
++	struct ftapbb020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	ftchan->completed_cookie = desc->txd.cookie;
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback)
++		desc->txd.callback(desc->txd.callback_param);
++}
++
++static void ftapbb020_finish_all_pending_chains(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->pending_list, node) {
++		list_del(&desc->node);
++		ftapbb020_invoke_callback(desc);
++		ftapbb020_remove_chain(desc);
++	}
++}
++
++static void ftapbb020_finish_active_chain(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftapbb020_desc,
++		node);
++	/* first descriptor in the active list has callback fields */
++	ftapbb020_invoke_callback(desc);
++
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftapbb020_unmap_desc(desc);
++		ftapbb020_desc_put(desc);
++	}
++}
++
++static void ftapbb020_finish_all_chains(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftapbb020_finish_active_chain(ftchan);
++	ftapbb020_finish_all_pending_chains(ftchan);
++}
++
++static dma_cookie_t ftapbb020_new_cookie(struct ftapbb020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftapbb020_chan_filter(struct dma_chan *chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftapbb020_dma_slave *slave = data;
++
++	if (strncmp(DRV_NAME, drv_name, sizeof(DRV_NAME)))
++		return false;
++
++	if ((slave->channels & (1 << chan->chan_id)) == 0)
++		return false;
++
++	chan->private = slave;
++	return true;
++}
++EXPORT_SYMBOL_GPL(ftapbb020_chan_filter);
++
++/******************************************************************************
++ * tasklet - called after we finished one chunk
++ *****************************************************************************/
++static void ftapbb020_tasklet(unsigned long data)
++{
++	struct ftapbb020_chan *ftchan = (struct ftapbb020_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftapbb020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	BUG_ON(list_empty(&ftchan->active_list));
++
++	spin_lock_bh(&ftchan->lock);
++
++	/* remove already finished descriptor */
++	desc = list_first_entry(&ftchan->active_list, struct ftapbb020_desc,
++		node);
++	list_del(&desc->node);
++
++	if (list_empty(&ftchan->active_list)) {
++		ftapbb020_invoke_callback(desc);
++		ftapbb020_start_next_chain(ftchan);
++	} else {
++		struct ftapbb020_desc *next;
++
++		/* Do next descriptor in the trasnfer chain */
++		next = list_first_entry(&ftchan->active_list,
++			struct ftapbb020_desc, node);
++
++		/*
++		 * Always keep the txd fields in the first descriptor in the
++		 * active list.
++		 */
++		next->txd.cookie = desc->txd.cookie;
++		next->txd.flags = desc->txd.flags;
++		next->txd.callback = desc->txd.callback;
++		next->txd.callback_param = desc->txd.callback_param;
++
++		ftapbb020_start_desc(next);
++	}
++
++	ftapbb020_unmap_desc(desc);
++	spin_unlock_bh(&ftchan->lock);
++	ftapbb020_desc_put(desc);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftapbb020_interrupt(int irq, void *dev_id)
++{
++	struct ftapbb020 *ftapbb020 = dev_id;
++	struct device *dev = ftapbb020->dma.dev;
++	irqreturn_t ret = IRQ_NONE;
++	unsigned int sr;
++	int i;
++
++	sr = ioread32(ftapbb020->base + FTAPBB020_OFFSET_SR);
++	if (sr & FTAPBB020_SR_BWERRINT) {
++		dev_info(dev, "bufferable write error\n");
++		ret = IRQ_HANDLED;
++	}
++
++	/* clear SR */
++	iowrite32(sr, ftapbb020->base + FTAPBB020_OFFSET_SR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++		void __iomem *base = ftchan->ftapbb020->base;
++		int chan_id = ftchan->common.chan_id;
++		unsigned int cmd;
++
++		/*
++		 * status bits in command register?
++		 * what a brain-damaged design.
++		 */
++		cmd = ioread32(base + FTAPBB020_OFFSET_CMD(chan_id));
++
++		if (cmd & FTAPBB020_CMD_FININT_S) {
++			tasklet_schedule(&ftchan->tasklet);
++			ret = IRQ_HANDLED;
++		} else if (cmd & FTAPBB020_CMD_ERRINT_S) {
++			dev_err(chan2dev(chan), "error happened\n");
++			ret = IRQ_HANDLED;
++		}
++
++		if (cmd & (FTAPBB020_CMD_FININT_S | FTAPBB020_CMD_ERRINT_S)) {
++			/* clear interrupt status */
++			cmd &= ~(FTAPBB020_CMD_FININT_S | FTAPBB020_CMD_ERRINT_S);
++			iowrite32(cmd, base + FTAPBB020_OFFSET_CMD(chan_id));
++		}
++	}
++
++	return ret;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftapbb020_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftapbb020_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++
++	desc = container_of(txd, struct ftapbb020_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	spin_lock_bh(&ftchan->lock);
++
++	cookie = ftapbb020_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list)) {
++		ftapbb020_activate_chain(desc);
++	} else {
++		list_add_tail(&desc->node, &ftchan->pending_list);
++	}
++
++	spin_unlock_bh(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftapbb020_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftapbb020_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftapbb020_desc *desc;
++
++		desc = ftapbb020_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	spin_lock_bh(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list);
++	ftchan->completed_cookie = chan->cookie = 1;
++	spin_unlock_bh(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftapbb020_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftapbb020_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	struct ftapbb020_desc *tmp;
++	struct ftapbb020 *ftapbb020;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++	ftapbb020 = ftchan->ftapbb020;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(!list_empty(&ftchan->pending_list));
++	BUG_ON(ftapbb020_chan_is_enabled(ftchan));
++
++	spin_lock_bh(&ftchan->lock);
++	ftapbb020_stop_channel(ftchan);
++	ftapbb020_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftapbb020_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/**
++ * ftapbb020_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++		dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc;
++	unsigned int shift;
++	unsigned int cmd;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	/* Assume RAM is on AHB bus. */
++	cmd = FTAPBB020_CMD_DST_TYPE_AHB | FTAPBB020_CMD_SRC_TYPE_AHB;
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++		cmd |= FTAPBB020_CMD_WIDTH_WORD
++		    |  FTAPBB020_CMD_DST_MODE_WORD_INC
++		    |  FTAPBB020_CMD_SRC_MODE_WORD_INC;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++		cmd |= FTAPBB020_CMD_WIDTH_HALF
++		    |  FTAPBB020_CMD_DST_MODE_HALF_INC
++		    |  FTAPBB020_CMD_SRC_MODE_HALF_INC;
++	} else {
++		shift = 0;
++		cmd |= FTAPBB020_CMD_WIDTH_BYTE
++		    |  FTAPBB020_CMD_DST_MODE_BYTE_INC
++		    |  FTAPBB020_CMD_SRC_MODE_BYTE_INC;
++	}
++
++	desc = ftapbb020_create_chain(ftchan, NULL, src, dest, len, shift, 0, 0, cmd);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++	desc->cmd = cmd;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftapbb020_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftapbb020_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++		unsigned int sg_len, enum dma_data_direction direction,
++		unsigned long flags)
++{
++	struct ftapbb020_dma_slave *slave = chan->private;
++	struct ftapbb020_chan *ftchan;
++	struct ftapbb020_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int cmd;
++	unsigned int shift;
++	unsigned int i;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (direction) {
++	case DMA_TO_DEVICE:
++		cmd = FTAPBB020_CMD_DST_MODE_FIXED
++		    | FTAPBB020_CMD_DST_HANDSHAKE(slave->handshake);
++
++		/* Assume RAM is on AHB bus. */
++		cmd |= FTAPBB020_CMD_SRC_TYPE_AHB;
++
++		switch (slave->type) {
++		case FTAPBB020_BUS_TYPE_AHB:
++			cmd |= FTAPBB020_CMD_DST_TYPE_AHB;
++			break;
++		case FTAPBB020_BUS_TYPE_APB:
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect bus type\n",
++				__func__);
++			BUG();
++		}
++
++		switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			shift = 0;
++			cmd |= FTAPBB020_CMD_WIDTH_BYTE
++			    |  FTAPBB020_CMD_SRC_MODE_BYTE_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			shift = 1;
++			cmd |= FTAPBB020_CMD_WIDTH_HALF
++			    |  FTAPBB020_CMD_SRC_MODE_HALF_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			shift = 2;
++			cmd |= FTAPBB020_CMD_WIDTH_WORD
++			    |  FTAPBB020_CMD_SRC_MODE_WORD_INC;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++				__func__);
++			BUG();
++		}
++
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftapbb020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftapbb020_create_chain(ftchan, desc,
++				mem, slave->common.dst_addr, len,
++				shift, 0, 1, cmd);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++		break;
++	case DMA_FROM_DEVICE:
++		cmd = FTAPBB020_CMD_SRC_MODE_FIXED
++		    | FTAPBB020_CMD_SRC_HANDSHAKE(slave->handshake);
++
++		/* Assume RAM is on AHB bus. */
++		cmd |= FTAPBB020_CMD_DST_TYPE_AHB;
++
++		switch (slave->type) {
++		case FTAPBB020_BUS_TYPE_AHB:
++			cmd |= FTAPBB020_CMD_SRC_TYPE_AHB;
++			break;
++		case FTAPBB020_BUS_TYPE_APB:
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect bus type\n",
++				__func__);
++			BUG();
++		}
++
++		switch (slave->common.src_addr_width) {
++		case DMA_SLAVE_BUSWIDTH_1_BYTE:
++			shift = 0;
++			cmd |= FTAPBB020_CMD_WIDTH_BYTE
++			    |  FTAPBB020_CMD_DST_MODE_BYTE_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_2_BYTES:
++			shift = 1;
++			cmd |= FTAPBB020_CMD_WIDTH_HALF
++			    |  FTAPBB020_CMD_DST_MODE_HALF_INC;
++			break;
++		case DMA_SLAVE_BUSWIDTH_4_BYTES:
++			shift = 2;
++			cmd |= FTAPBB020_CMD_WIDTH_WORD
++			    |  FTAPBB020_CMD_DST_MODE_WORD_INC;
++			break;
++		default:
++			dev_err(chan2dev(chan), "%s: incorrect data width\n",
++				__func__);
++			BUG();
++		}
++
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftapbb020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftapbb020_create_chain(ftchan, desc,
++				slave->common.src_addr, mem, len,
++				shift, 1, 0, cmd);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n",
++			__func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftapbb020_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++		unsigned long arg)
++{
++	struct ftapbb020_chan *ftchan;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	/* Only supports DMA_TERMINATE_ALL */
++	if (cmd != DMA_TERMINATE_ALL)
++		return -ENXIO;
++
++	/*
++	 * This is only called when something went wrong elsewhere, so
++	 * we don't really care about the data. Just disable the channel.
++	 */
++	spin_lock_bh(&ftchan->lock);
++	ftapbb020_stop_channel(ftchan);
++	ftapbb020_finish_all_chains(ftchan);
++	spin_unlock_bh(&ftchan->lock);
++	return 0;
++}
++
++/**
++ * ftapbb020_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftapbb020_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		struct dma_tx_state *txstate)
++{
++	struct ftapbb020_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftapbb020_issue_pending - try to finish work
++ * @chan: target DMA channel
++ */
++static void ftapbb020_issue_pending(struct dma_chan *chan)
++{
++	struct ftapbb020_chan *ftchan;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftapbb020_chan, common);
++
++	if (list_empty(&ftchan->active_list)) {
++		spin_lock_bh(&ftchan->lock);
++		ftapbb020_start_next_chain(ftchan);
++		spin_unlock_bh(&ftchan->lock);
++	}
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftapbb020_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftapbb020 *ftapbb020;
++	struct dma_device *dma;
++	int irq;
++	int i;
++	int err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftapbb020 = kzalloc(sizeof(*ftapbb020), GFP_KERNEL);
++	if (!ftapbb020) {
++		return -ENOMEM;
++	}
++
++	dma = &ftapbb020->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftapbb020);
++
++	/* map io memory */
++
++	ftapbb020->res = request_mem_region(res->start, res->end - res->start + 1,
++			dev_name(&pdev->dev));
++	if (ftapbb020->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftapbb020->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftapbb020->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* force dma off, just in case */
++	ftapbb020_stop_all_channels(ftapbb020);
++
++	/* initialize channels */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->pending_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device	= dma;
++		ftchan->common.cookie	= DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftapbb020		= ftapbb020;
++		ftchan->completed_cookie	= DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftapbb020_tasklet,
++				(unsigned long)ftchan);
++
++		list_add_tail(&ftchan->common.device_node, &dma->channels);
++	}
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources	= ftapbb020_alloc_chan_resources;
++	dma->device_free_chan_resources	= ftapbb020_free_chan_resources;
++	dma->device_prep_dma_memcpy	= ftapbb020_prep_dma_memcpy;
++	dma->device_prep_slave_sg	= ftapbb020_prep_slave_sg;
++	dma->device_control		= ftapbb020_control;
++	dma->device_tx_status		= ftapbb020_tx_status;
++	dma->device_issue_pending	= ftapbb020_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);
++
++	err = request_irq(irq, ftapbb020_interrupt, IRQF_SHARED, pdev->name,
++		ftapbb020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_irq;
++	}
++
++	ftapbb020->irq = irq;
++
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	dev_info(&pdev->dev, "DMA engine driver: irq %d, mapped at %p\n",
++		irq, ftapbb020->base);
++
++	return 0;
++
++err_register:
++	free_irq(irq, ftapbb020);
++err_irq:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftapbb020->base);
++err_ioremap:
++	release_resource(ftapbb020->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftapbb020);
++	return err;
++}
++
++static int __exit ftapbb020_remove(struct platform_device *pdev)
++{
++	struct ftapbb020 *ftapbb020;
++	int i;
++
++	ftapbb020 = platform_get_drvdata(pdev);
++
++	dma_async_device_unregister(&ftapbb020->dma);
++
++	free_irq(ftapbb020->irq, ftapbb020);
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftapbb020_chan *ftchan = &ftapbb020->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftapbb020->base);
++	release_resource(ftapbb020->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftapbb020);
++	return 0;
++}
++
++static struct platform_driver ftapbb020_driver = {
++	.probe		= ftapbb020_probe,
++	.remove		= __exit_p(ftapbb020_remove),
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftapbb020_init(void)
++{
++	return platform_driver_register(&ftapbb020_driver);
++}
++
++static void __exit ftapbb020_exit(void)
++{
++	platform_driver_unregister(&ftapbb020_driver);
++}
++
++module_init(ftapbb020_init);
++module_exit(ftapbb020_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTAPBB020 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-faraday/ftdmac020.c b/arch/arm/mach-faraday/ftdmac020.c
+new file mode 100644
+index 00000000..c4fc1bc5
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftdmac020.c
+@@ -0,0 +1,1303 @@
++/*
++ * Faraday FTDMAC020 DMA engine driver
++ *
++ * (C) Copyright 2010 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/dmapool.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <asm/io.h>
++
++#include <mach/ftdmac020.h>
++
++#define DRV_NAME	"ftdmac020"
++#define CHANNEL_NR	8
++
++/*
++ * This value must be multiple of 32-bits to prevent from changing the
++ * alignment of child descriptors.
++ */
++#define MAX_CYCLE_PER_BLOCK	0x200000
++#if (MAX_CYCLE_PER_BLOCK > FTDMAC020_CYC_MASK) || \
++	(MAX_CYCLE_PER_BLOCK > FTDMAC020_LLD_CYCLE_MASK) || \
++	(MAX_CYCLE_PER_BLOCK & 0x3)
++#error invalid MAX_CYCLE_PER_BLOCK
++#endif
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 64;
++module_param(init_nr_desc_per_channel, uint, 0644);
++MODULE_PARM_DESC(init_nr_desc_per_channel,
++		 "initial descriptors per channel (default: 64)");
++
++/**
++ * struct ftdmac020_desc - async transaction descriptor.
++ * @lld: hardware descriptor, MUST be the first member
++ * @ccr: value for channel control register
++ * @cfg: value for channel configuration register
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the first link list descriptor (2nd block)
++ * @cycle: transfer size
++ * @txd: support for the async_tx api
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @node: node on the descriptors list
++ * @len: length in bytes
++ *
++ * For a chained transfer, software has to set channel-specific hardware
++ * registers to describe the first block and link list descriptors to describe
++ * other blocks. Because of this unbelievable brain-damaged design, the
++ * software descriptor and driver became unnecessarily complex.
++ *
++ * Sure, we can reuse src, dst, next and cycle in lld to save some space.
++ * The reason I do not do that is not to make you confused.
++ */
++struct ftdmac020_desc {
++	/* not used by the first block */
++	struct ftdmac020_lld lld;
++
++	/* used only by the first block */
++	unsigned int ccr;
++	unsigned int cfg;
++	dma_addr_t src;
++	dma_addr_t dst;
++	dma_addr_t next;
++	unsigned int cycle;
++
++	struct dma_async_tx_descriptor txd;
++	struct list_head child_list;
++
++	/* used by all blocks */
++	struct ftdmac020_chan *ftchan;
++	struct list_head node;
++	size_t len;
++};
++
++/**
++ * struct ftdmac020_chan - internal representation of an ftdmac020 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftdmac020: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftdmac020_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftdmac020 *ftdmac020;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++};
++
++/**
++ * struct ftdmac020 - internal representation of an ftdmac020 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @id: id for each device
++ * @tc_irq: terminal count irq number
++ * @ea_irq: error and abort irq number
++ * @channel: channel table
++ */
++struct ftdmac020 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	int id;
++	unsigned int tc_irq;
++	unsigned int ea_irq;
++	struct dma_pool *dma_desc_pool;
++	struct ftdmac020_chan channel[CHANNEL_NR];
++};
++
++static dma_cookie_t ftdmac020_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftdmac020_stop_channel(struct ftdmac020_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++
++	iowrite32(0, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++}
++
++static void ftdmac020_enable(struct ftdmac020 *ftdmac020)
++{
++	void __iomem *base = ftdmac020->base;
++
++	iowrite32(FTDMAC020_CR_ENABLE, base + FTDMAC020_OFFSET_CR);
++}
++
++static void ftdmac020_disable(struct ftdmac020 *ftdmac020)
++{
++	void __iomem *base = ftdmac020->base;
++
++	iowrite32(0, base + FTDMAC020_OFFSET_CR);
++}
++
++
++static int ftdmac020_chan_is_enabled(struct ftdmac020_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac020->base;
++	unsigned int enabled;
++
++	enabled = ioread32(base + FTDMAC020_OFFSET_CH_ENABLED);
++	return enabled & (1 << chan_id);
++}
++
++/**
++ * ftdmac020_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftdmac020_desc *ftdmac020_alloc_desc(
++		struct ftdmac020_chan *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020 *ftdmac020 = ftchan->ftdmac020;
++	struct ftdmac020_desc *desc;
++	dma_addr_t phys;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = dma_pool_alloc(ftdmac020->dma_desc_pool, gfp_flags, &phys);
++	if (desc) {
++		memset(desc, 0, sizeof(*desc));
++
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftdmac020_tx_submit;
++		desc->txd.phys = phys;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftdmac020_free_desc(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &desc->ftchan->common;
++	struct ftdmac020 *ftdmac020 = ftchan->ftdmac020;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	dma_pool_free(ftdmac020->dma_desc_pool, desc, desc->txd.phys);
++}
++
++/**
++ * ftdmac020_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftdmac020_desc *ftdmac020_desc_get(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc = NULL;
++
++	spin_lock_bh(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++			struct ftdmac020_desc, node);
++
++		list_del(&desc->node);
++	}
++	spin_unlock_bh(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftdmac020_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			spin_lock_bh(&ftchan->lock);
++			ftchan->descs_allocated++;
++			spin_unlock_bh(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftdmac020_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftdmac020_desc_put(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *child;
++
++	spin_lock_bh(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++static void ftdmac020_unmap_desc(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftdmac020_remove_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *child;
++	struct ftdmac020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->child_list, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftdmac020_unmap_desc(child);
++		ftdmac020_desc_put(child);
++	}
++
++	ftdmac020_unmap_desc(desc);
++	ftdmac020_desc_put(desc);
++}
++
++/**
++ * ftdmac020_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @maxburst: the maximum number of words (note: words, as in units of the
++ * data width, not bytes) that can be sent in one burst to the device.
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ */
++static struct ftdmac020_desc *ftdmac020_create_chain(
++		struct ftdmac020_chan *ftchan,
++		struct ftdmac020_desc *first,
++		dma_addr_t src, dma_addr_t dest, size_t len,
++		unsigned int shift, int maxburst, int fixed_src, int fixed_dest)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_dma_slave *slave = chan->private;
++	struct ftdmac020_desc *prev = NULL;
++	unsigned int ccr;
++	unsigned int lld_ctrl;
++	size_t offset;
++	unsigned int cycle;
++
++	dev_dbg(chan2dev(chan),
++		"%s(src %x, dest %x, len %x, shift %d, maxburst %d)\n",
++		__func__, src, dest, len, shift, maxburst);
++
++	if ((shift == 2 && ((src | dest | len) & 3)) ||
++	    (shift == 1 && ((src | dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	if (first) {
++		if (list_empty(&first->child_list))
++			prev = first;
++		else
++			prev = list_entry(first->child_list.prev,
++				struct ftdmac020_desc, node);
++	}
++
++	ccr = FTDMAC020_CCR_ENABLE
++	    | FTDMAC020_CCR_PRIO_0
++	    | FTDMAC020_CCR_FIFOTH_1;
++
++	lld_ctrl = FTDMAC020_LLD_CTRL_FIFOTH_1;
++
++	switch (maxburst) {
++	case 1:
++		ccr |= FTDMAC020_CCR_BURST_1;
++		break;
++	case 4:
++		ccr |= FTDMAC020_CCR_BURST_4;
++		break;
++	case 8:
++		ccr |= FTDMAC020_CCR_BURST_8;
++		break;
++	case 16:
++		ccr |= FTDMAC020_CCR_BURST_16;
++		break;
++	case 32:
++		ccr |= FTDMAC020_CCR_BURST_32;
++		break;
++	case 64:
++		ccr |= FTDMAC020_CCR_BURST_64;
++		break;
++	case 128:
++		ccr |= FTDMAC020_CCR_BURST_128;
++		break;
++	case 256:
++		ccr |= FTDMAC020_CCR_BURST_256;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect burst size\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	switch (shift) {
++	case 2:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_32
++		    |  FTDMAC020_CCR_SRC_WIDTH_32;
++
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_32
++			 |  FTDMAC020_LLD_CTRL_SRC_WIDTH_32;
++		break;
++	case 1:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_16
++		    |  FTDMAC020_CCR_SRC_WIDTH_16;
++
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_16
++			 |  FTDMAC020_LLD_CTRL_SRC_WIDTH_16;
++		break;
++	case 0:
++		ccr |= FTDMAC020_CCR_DST_WIDTH_8
++		    |  FTDMAC020_CCR_SRC_WIDTH_8;
++
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_WIDTH_8
++			 |  FTDMAC020_LLD_CTRL_SRC_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	if (slave && slave->handshake >= 0)
++		ccr |= FTDMAC020_CCR_HANDSHAKE;
++
++	if (fixed_src) {
++		ccr |= FTDMAC020_CCR_SRC_FIXED;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_FIXED;
++	} else {
++		ccr |= FTDMAC020_CCR_SRC_INC;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_SRC_INC;
++	}
++
++	if (fixed_dest) {
++		ccr |= FTDMAC020_CCR_DST_FIXED;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_FIXED;
++	} else {
++		ccr |= FTDMAC020_CCR_DST_INC;
++		lld_ctrl |= FTDMAC020_LLD_CTRL_DST_INC;
++	}
++
++	for (offset = 0; offset < len; offset += cycle << shift) {
++		struct ftdmac020_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> shift,
++				MAX_CYCLE_PER_BLOCK);
++
++		desc = ftdmac020_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		if (fixed_src) {
++			desc->src = desc->lld.src = src;
++		} else {
++			desc->src = desc->lld.src = src + offset;
++		}
++
++		if (fixed_dest) {
++			desc->dst = desc->lld.dst = dest;
++		} else {
++			desc->dst = desc->lld.dst = dest + offset;
++		}
++
++		desc->next	= 0;
++		desc->cycle	= cycle & FTDMAC020_CYC_MASK;
++		desc->ccr	= ccr;
++		desc->cfg	= 0;
++		desc->len	= cycle << shift;
++
++		desc->lld.next	= 0;
++		desc->lld.cycle	= cycle & FTDMAC020_LLD_CYCLE_MASK;
++		desc->lld.ctrl	= lld_ctrl;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/*
++			 * Mask terminal count interrupt for this descriptor.
++			 * What an inconvenient stupid design.
++			 */
++			prev->ccr	|= FTDMAC020_CCR_MASK_TC;
++			prev->lld.ctrl	|= FTDMAC020_LLD_CTRL_MASK_TC;
++
++			/* hardware link list pointer */
++			prev->next	= FTDMAC020_LLP_ADDR(desc->txd.phys);
++			prev->lld.next	= desc->txd.phys;
++
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++
++		prev = desc;
++	}
++
++	return first;
++err:
++	if (first)
++		ftdmac020_remove_chain(first);
++	return NULL;
++}
++
++static void ftdmac020_start_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	void __iomem *base = ftchan->ftdmac020->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++
++	/*
++	 * The first transfer block is not described by hardware lld.
++	 * Instead, we should fill some hardware registers.
++	 * What a stupid weird design.
++	 */
++	dev_dbg(chan2dev(chan), "\t[SRC %d] = %x\n", chan_id, desc->src);
++	iowrite32(desc->src, base + FTDMAC020_OFFSET_SRC_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DST %d] = %x\n", chan_id, desc->dst);
++	iowrite32(desc->dst, base + FTDMAC020_OFFSET_DST_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[LLP %d] = %x\n", chan_id, desc->next);
++	iowrite32(desc->next, base + FTDMAC020_OFFSET_LLP_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->cycle);
++	iowrite32(desc->cycle, base + FTDMAC020_OFFSET_CYC_CH(chan_id));
++
++	/* go */
++	dev_dbg(chan2dev(chan), "\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	iowrite32(desc->cfg, base + FTDMAC020_OFFSET_CFG_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CCR %d] = %x\n", chan_id, desc->ccr);
++	iowrite32(desc->ccr, base + FTDMAC020_OFFSET_CCR_CH(chan_id));
++}
++
++static void ftdmac020_start_new_chain(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac020_desc, node);
++	ftdmac020_start_chain(desc);
++}
++
++static void ftdmac020_finish_chain(struct ftdmac020_desc *desc)
++{
++	struct ftdmac020_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	spin_lock_bh(&ftchan->lock);
++	ftchan->completed_cookie = desc->txd.cookie;
++	spin_unlock_bh(&ftchan->lock);
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback)
++		desc->txd.callback(desc->txd.callback_param);
++
++	ftdmac020_remove_chain(desc);
++}
++
++static void ftdmac020_finish_all_chains(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftdmac020_finish_chain(desc);
++	}
++}
++
++static dma_cookie_t ftdmac020_new_cookie(struct ftdmac020_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftdmac020_chan_filter(struct dma_chan *chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftdmac020_dma_slave *slave = data;
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020 *ftdmac020;
++
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++	ftdmac020 = ftchan->ftdmac020;
++
++	if (strncmp(DRV_NAME, drv_name, sizeof(DRV_NAME)))
++		return false;
++
++	if (slave->id >= 0 && slave->id != ftdmac020->id)
++		return false;
++
++	if ((slave->channels & (1 << chan->chan_id)) == 0)
++		return false;
++
++	chan->private = slave;
++	return true;
++}
++EXPORT_SYMBOL_GPL(ftdmac020_chan_filter);
++
++/******************************************************************************
++ * tasklet - called after we finished one chain
++ *****************************************************************************/
++static void ftdmac020_tasklet(unsigned long data)
++{
++	struct ftdmac020_chan *ftchan = (struct ftdmac020_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac020_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	BUG_ON(list_empty(&ftchan->active_list));
++
++	spin_lock_bh(&ftchan->lock);
++
++	/* remove already finished descriptor */
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac020_desc,
++		node);
++	list_del(&desc->node);
++
++	/* check if there were another transfer to do */
++	ftdmac020_start_new_chain(ftchan);
++
++	spin_unlock_bh(&ftchan->lock);
++	ftdmac020_finish_chain(desc);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftdmac020_tc_interrupt(int irq, void *dev_id)
++{
++	struct ftdmac020 *ftdmac020 = dev_id;
++	unsigned int status;
++	int i;
++
++	status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_TCISR);
++	if (!status)
++		return IRQ_NONE;
++
++	/* clear status */
++	iowrite32(status, ftdmac020->base + FTDMAC020_OFFSET_TCICR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (status & (1 << i)) {
++			dev_dbg(chan2dev(chan), "terminal count\n");
++			tasklet_schedule(&ftchan->tasklet);
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++static irqreturn_t ftdmac020_ea_interrupt(int irq, void *dev_id)
++{
++	struct ftdmac020 *ftdmac020 = dev_id;
++	unsigned int status;
++	int i;
++
++	status = ioread32(ftdmac020->base + FTDMAC020_OFFSET_EAISR);
++	if (!status)
++		return IRQ_NONE;
++
++	/* clear status */
++	iowrite32(status, ftdmac020->base + FTDMAC020_OFFSET_EAICR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (status & FTDMAC020_EA_ERR_CH(i))
++			dev_info(chan2dev(chan), "error happened\n");
++
++		if (status & FTDMAC020_EA_ABT_CH(i))
++			dev_info(chan2dev(chan), "transfer aborted\n");
++	}
++
++	return IRQ_HANDLED;
++}
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftdmac020_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftdmac020_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++	bool busy;
++
++	desc = container_of(txd, struct ftdmac020_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	spin_lock_bh(&ftchan->lock);
++
++	cookie = ftdmac020_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list))
++		busy = false;
++	else
++		busy = true;
++
++	list_add_tail(&desc->node, &ftchan->active_list);
++
++	/* start ASAP */
++	if (!busy)
++		ftdmac020_start_chain(desc);
++
++	spin_unlock_bh(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftdmac020_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftdmac020_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftdmac020_desc *desc;
++
++		desc = ftdmac020_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	spin_lock_bh(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list);
++	ftchan->completed_cookie = chan->cookie = 1;
++	spin_unlock_bh(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftdmac020_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftdmac020_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	struct ftdmac020_desc *tmp;
++	struct ftdmac020 *ftdmac020;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++	ftdmac020 = ftchan->ftdmac020;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(ftdmac020_chan_is_enabled(ftchan));
++
++	spin_lock_bh(&ftchan->lock);
++	ftdmac020_stop_channel(ftchan);
++	ftdmac020_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftdmac020_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/**
++ * ftdmac020_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++		dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++	} else {
++		shift = 0;
++	}
++
++	desc = ftdmac020_create_chain(ftchan, NULL, src, dest, len,
++		shift, 1, 0, 0);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac020_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac020_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++		unsigned int sg_len, enum dma_transfer_direction direction,
++		unsigned long flags)
++{
++	struct ftdmac020_dma_slave *slave = chan->private;
++	struct ftdmac020_chan *ftchan;
++	struct ftdmac020_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int shift;
++	unsigned int i;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		shift = 2;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++	switch (direction) {
++	case DMA_TO_DEVICE:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftdmac020_create_chain(ftchan, desc,
++				mem, slave->common.dst_addr, len,
++				shift, slave->common.dst_maxburst, 0, 1);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC020_CFG_DST_HANDSHAKE_EN
++				| FTDMAC020_CFG_DST_HANDSHAKE(slave->handshake);
++		break;
++	case DMA_FROM_DEVICE:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac020_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftdmac020_create_chain(ftchan, desc,
++				slave->common.src_addr, mem, len,
++				shift, slave->common.src_maxburst, 1, 0);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC020_CFG_SRC_HANDSHAKE_EN
++				| FTDMAC020_CFG_SRC_HANDSHAKE(slave->handshake);
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n",
++			__func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftdmac020_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++		unsigned long arg)
++{
++	struct ftdmac020_chan *ftchan;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	/* Only supports DMA_TERMINATE_ALL */
++	if (cmd != DMA_TERMINATE_ALL)
++		return -ENXIO;
++
++	/*
++	 * This is only called when something went wrong elsewhere, so
++	 * we don't really care about the data. Just disable the channel.
++	 */
++	spin_lock_bh(&ftchan->lock);
++	ftdmac020_stop_channel(ftchan);
++	ftdmac020_finish_all_chains(ftchan);
++	spin_unlock_bh(&ftchan->lock);
++	return 0;
++}
++
++/**
++ * ftdmac020_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftdmac020_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		struct dma_tx_state *txstate)
++{
++	struct ftdmac020_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac020_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftdmac020_issue_pending - try to finish work
++ * @chan: target DMA channel
++ */
++static void ftdmac020_issue_pending(struct dma_chan *chan)
++{
++	/*
++	 * We are posting descriptors to the hardware as soon as
++	 * they are ready, so this function does nothing.
++	 */
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftdmac020_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftdmac020 *ftdmac020;
++	struct dma_device *dma;
++	int tc_irq;
++	int ea_irq;
++	int i;
++	int err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((tc_irq = platform_get_irq(pdev, 0)) < 0) {
++		return tc_irq;
++	}
++
++	if ((ea_irq = platform_get_irq(pdev, 1)) < 0) {
++		return ea_irq;
++	}
++
++	ftdmac020 = kzalloc(sizeof(*ftdmac020), GFP_KERNEL);
++	if (!ftdmac020) {
++		return -ENOMEM;
++	}
++
++	dma = &ftdmac020->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftdmac020);
++	ftdmac020->id = pdev->id;
++
++	/* map io memory */
++
++	ftdmac020->res = request_mem_region(res->start, res->end - res->start + 1,
++			dev_name(&pdev->dev));
++	if (ftdmac020->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftdmac020->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftdmac020->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* create a pool of consistent memory blocks for hardware descriptors */
++	ftdmac020->dma_desc_pool = dma_pool_create("ftdmac020_desc_pool",
++			&pdev->dev, sizeof(struct ftdmac020_desc),
++			4 /* word alignment */, 0);
++	if (!ftdmac020->dma_desc_pool) {
++		dev_err(&pdev->dev, "No memory for descriptor pool\n");
++		err = -ENOMEM;
++		goto err_pool_create;
++	}
++
++	/* force dma off, just in case */
++	ftdmac020_disable(ftdmac020);
++
++	/* initialize channels */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device	= dma;
++		ftchan->common.cookie	= DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftdmac020		= ftdmac020;
++		ftchan->completed_cookie	= DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftdmac020_tasklet,
++				(unsigned long)ftchan);
++		list_add_tail(&ftchan->common.device_node, &dma->channels);
++	}
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftdmac020_alloc_chan_resources;
++	dma->device_free_chan_resources	= ftdmac020_free_chan_resources;
++	dma->device_prep_dma_memcpy	= ftdmac020_prep_dma_memcpy;
++	dma->device_prep_slave_sg	= ftdmac020_prep_slave_sg;
++	dma->device_control		= ftdmac020_control;
++	dma->device_tx_status		= ftdmac020_tx_status;
++	dma->device_issue_pending	= ftdmac020_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);
++
++	err = request_irq(tc_irq, ftdmac020_tc_interrupt, IRQF_SHARED, pdev->name,
++		ftdmac020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", tc_irq);
++		goto err_tc_irq;
++	}
++
++	ftdmac020->tc_irq = tc_irq;
++
++	err = request_irq(ea_irq, ftdmac020_ea_interrupt, IRQF_SHARED, pdev->name,
++		ftdmac020);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", ea_irq);
++		goto err_ea_irq;
++	}
++
++	ftdmac020->ea_irq = ea_irq;
++
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	ftdmac020_enable(ftdmac020);
++	dev_info(&pdev->dev,
++		"DMA engine driver: tc irq %d, ea irq %d, mapped at %p\n",
++		tc_irq, ea_irq, ftdmac020->base);
++
++	return 0;
++
++err_register:
++	free_irq(ea_irq, ftdmac020);
++err_ea_irq:
++	free_irq(tc_irq, ftdmac020);
++err_tc_irq:
++	dma_pool_destroy(ftdmac020->dma_desc_pool);
++err_pool_create:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftdmac020->base);
++err_ioremap:
++	release_resource(ftdmac020->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac020);
++	return err;
++}
++
++static int __exit ftdmac020_remove(struct platform_device *pdev)
++{
++	struct ftdmac020 *ftdmac020;
++	int i;
++
++	ftdmac020 = platform_get_drvdata(pdev);
++
++	ftdmac020_disable(ftdmac020);
++	dma_async_device_unregister(&ftdmac020->dma);
++
++	free_irq(ftdmac020->tc_irq, ftdmac020);
++	free_irq(ftdmac020->ea_irq, ftdmac020);
++	dma_pool_destroy(ftdmac020->dma_desc_pool);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac020_chan *ftchan = &ftdmac020->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftdmac020->base);
++	release_resource(ftdmac020->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac020);
++	return 0;
++}
++
++static struct platform_driver ftdmac020_driver = {
++	.probe		= ftdmac020_probe,
++	.remove		= __exit_p(ftdmac020_remove),
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftdmac020_init(void)
++{
++	return platform_driver_register(&ftdmac020_driver);
++}
++
++static void __exit ftdmac020_exit(void)
++{
++	platform_driver_unregister(&ftdmac020_driver);
++}
++
++module_init(ftdmac020_init);
++module_exit(ftdmac020_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTDMAC020 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-faraday/ftdmac030.c b/arch/arm/mach-faraday/ftdmac030.c
+new file mode 100644
+index 00000000..dc015ff3
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftdmac030.c
+@@ -0,0 +1,1170 @@
++/*
++ * Faraday FTDMAC030 DMA engine driver
++ *
++ * (C) Copyright 2011 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++#include <linux/dmapool.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <asm/io.h>
++
++#include <mach/ftdmac030.h>
++
++#define DRV_NAME	"ftdmac030"
++#define CHANNEL_NR	8
++
++/*
++ * This value must be multiple of 32-bits to prevent from changing the
++ * alignment of child descriptors.
++ */
++#define MAX_CYCLE_PER_BLOCK	0x200000
++#if (MAX_CYCLE_PER_BLOCK > FTDMAC030_CYC_MASK) || \
++	(MAX_CYCLE_PER_BLOCK & 0x3)
++#error invalid MAX_CYCLE_PER_BLOCK
++#endif
++
++#define GRANT_WINDOW	64
++
++/*
++ * Initial number of descriptors to allocate for each channel. This could
++ * be increased during dma usage.
++ */
++static unsigned int init_nr_desc_per_channel = 64;
++module_param(init_nr_desc_per_channel, uint, 0644);
++MODULE_PARM_DESC(init_nr_desc_per_channel,
++		 "initial descriptors per channel (default: 64)");
++
++/**
++ * struct ftdmac030_desc - async transaction descriptor.
++ * @lld: hardware descriptor, MUST be the first member
++ * @ctrl: value for channel control register
++ * @cfg: value for channel configuration register
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the first link list descriptor (2nd block)
++ * @cycle: transfer size
++ * @txd: support for the async_tx api
++ * @child_list: list for transfer chain
++ * @ftchan: the channel which this descriptor belongs to
++ * @node: node on the descriptors list
++ * @len: length in bytes
++ */
++struct ftdmac030_desc {
++	struct ftdmac030_lld lld;
++
++	/* used only by the first block */
++	unsigned int cfg;
++
++	struct dma_async_tx_descriptor txd;
++	struct list_head child_list;
++
++	/* used by all blocks */
++	struct ftdmac030_chan *ftchan;
++	struct list_head node;
++	size_t len;
++};
++
++/**
++ * struct ftdmac030_chan - internal representation of an ftdmac030 channel.
++ * @common: common dmaengine channel object
++ * @active_list: list of descriptors dmaengine is being running on
++ * @free_list: list of descriptors usable by the channel
++ * @tasklet: bottom half to finish transaction work
++ * @lock: serializes enqueue/dequeue operations to descriptors lists
++ * @ftdmac030: parent device
++ * @completed_cookie: identifier for the most recently completed operation
++ * @descs_allocated: number of allocated descriptors
++ */
++struct ftdmac030_chan {
++	struct dma_chan common;
++	struct list_head active_list;
++	struct list_head free_list;
++	struct tasklet_struct tasklet;
++	spinlock_t lock;
++	struct ftdmac030 *ftdmac030;
++	dma_cookie_t completed_cookie;
++	int descs_allocated;
++};
++
++/**
++ * struct ftdmac030 - internal representation of an ftdmac030 device
++ * @dma: common dmaengine dma_device object
++ * @res: io memory resource of hardware registers
++ * @base: virtual address of hardware register base
++ * @id: id for each device
++ * @irq: irq number
++ * @channel: channel table
++ */
++struct ftdmac030 {
++	struct dma_device dma;
++	struct resource *res;
++	void __iomem *base;
++	int id;
++	unsigned int irq;
++	struct dma_pool *dma_desc_pool;
++	struct ftdmac030_chan channel[CHANNEL_NR];
++};
++
++static dma_cookie_t ftdmac030_tx_submit(struct dma_async_tx_descriptor *);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline struct device *chan2dev(struct dma_chan *chan)
++{
++	return &chan->dev->device;
++}
++
++static void ftdmac030_stop_channel(struct ftdmac030_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac030->base;
++
++	iowrite32(0, base + FTDMAC030_OFFSET_CTRL_CH(chan_id));
++}
++
++static int ftdmac030_chan_is_enabled(struct ftdmac030_chan *ftchan)
++{
++	int chan_id = ftchan->common.chan_id;
++	void __iomem *base = ftchan->ftdmac030->base;
++	unsigned int enabled;
++
++	enabled = ioread32(base + FTDMAC030_OFFSET_CH_ENABLED);
++	return enabled & (1 << chan_id);
++}
++
++/**
++ * ftdmac030_alloc_desc - allocate and initialize descriptor
++ * @ftchan: the channel to allocate descriptor for
++ * @gfp_flags: GFP allocation flags
++ */
++static struct ftdmac030_desc *ftdmac030_alloc_desc(
++		struct ftdmac030_chan *ftchan, gfp_t gfp_flags)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030 *ftdmac030 = ftchan->ftdmac030;
++	struct ftdmac030_desc *desc;
++	dma_addr_t phys;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	desc = dma_pool_alloc(ftdmac030->dma_desc_pool, gfp_flags, &phys);
++	if (desc) {
++		memset(desc, 0, sizeof(*desc));
++
++		/* initialize dma_async_tx_descriptor fields */
++		dma_async_tx_descriptor_init(&desc->txd, &ftchan->common);
++		desc->txd.tx_submit = ftdmac030_tx_submit;
++		desc->txd.phys = phys;
++
++		INIT_LIST_HEAD(&desc->child_list);
++		desc->ftchan = ftchan;
++	}
++
++	return desc;
++}
++
++static void ftdmac030_free_desc(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &desc->ftchan->common;
++	struct ftdmac030 *ftdmac030 = ftchan->ftdmac030;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	dma_pool_free(ftdmac030->dma_desc_pool, desc, desc->txd.phys);
++}
++
++/**
++ * ftdmac030_desc_get - get an unused descriptor from free list
++ * @ftchan: channel we want a new descriptor for
++ */
++static struct ftdmac030_desc *ftdmac030_desc_get(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc = NULL;
++
++	spin_lock_bh(&ftchan->lock);
++	if (!list_empty(&ftchan->free_list)) {
++		desc = list_first_entry(&ftchan->free_list,
++			struct ftdmac030_desc, node);
++
++		list_del(&desc->node);
++	}
++	spin_unlock_bh(&ftchan->lock);
++
++	/* no more descriptor available in initial pool: create one more */
++	if (!desc) {
++		desc = ftdmac030_alloc_desc(ftchan, GFP_ATOMIC);
++		if (desc) {
++			spin_lock_bh(&ftchan->lock);
++			ftchan->descs_allocated++;
++			spin_unlock_bh(&ftchan->lock);
++		} else {
++			dev_err(chan2dev(chan),
++				"not enough descriptors available\n");
++		}
++	} else {
++		dev_dbg(chan2dev(chan), "%s got desc %p\n", __func__, desc);
++	}
++
++	return desc;
++}
++
++/**
++ * ftdmac030_desc_put - move a descriptor, including any children, to the free list
++ * @ftchan: channel we work on
++ * @desc: descriptor, at the head of a chain, to move to free list
++ */
++static void ftdmac030_desc_put(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *child;
++
++	spin_lock_bh(&ftchan->lock);
++
++	if (!list_empty(&desc->child_list)) {
++		list_for_each_entry(child, &desc->child_list, node) {
++			dev_dbg(chan2dev(chan),
++				"moving child desc %p to freelist\n", child);
++		}
++
++		list_splice_init(&desc->child_list, &ftchan->free_list);
++	}
++
++	dev_dbg(chan2dev(chan), "moving desc %p to freelist\n", desc);
++	list_add(&desc->node, &ftchan->free_list);
++	spin_unlock_bh(&ftchan->lock);
++}
++
++static void ftdmac030_unmap_desc(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	enum dma_ctrl_flags flags = desc->txd.flags;
++	struct device *parent = ftchan->common.dev->device.parent;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	if (ftchan->common.private)
++		return;
++
++	if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
++		if (flags & DMA_COMPL_DEST_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.dst, desc->len,
++				DMA_FROM_DEVICE);
++		}
++	}
++
++	if (!(flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
++		if (flags & DMA_COMPL_SRC_UNMAP_SINGLE) {
++			dma_unmap_single(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		} else {
++			dma_unmap_page(parent, desc->lld.src, desc->len,
++				DMA_TO_DEVICE);
++		}
++	}
++}
++
++static void ftdmac030_remove_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *child;
++	struct ftdmac030_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	list_for_each_entry_safe(child, tmp, &desc->child_list, node) {
++		dev_dbg(chan2dev(chan), "removing child desc %p\n", child);
++		list_del(&child->node);
++		ftdmac030_unmap_desc(child);
++		ftdmac030_desc_put(child);
++	}
++
++	ftdmac030_unmap_desc(desc);
++	ftdmac030_desc_put(desc);
++}
++
++/**
++ * ftdmac030_create_chain - create a DMA transfer chain
++ * @ftchan: the channel to allocate descriptor for
++ * @first: first descriptor of a transfer chain if any
++ * @src: physical source address
++ * @dest: phyical destination address
++ * @len: length in bytes
++ * @shift: shift value for width (0: byte, 1: halfword, 2: word)
++ * @fixed_src: source address is fixed (device register)
++ * @fixed_dest: destination address is fixed (device register)
++ */
++static struct ftdmac030_desc *ftdmac030_create_chain(
++		struct ftdmac030_chan *ftchan,
++		struct ftdmac030_desc *first,
++		dma_addr_t src, dma_addr_t dest, size_t len,
++		unsigned int shift, int fixed_src, int fixed_dest)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *prev = NULL;
++	unsigned int ctrl;
++	size_t offset;
++	unsigned int cycle;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x, shift %d)\n",
++		__func__, src, dest, len, shift);
++	if ((shift == 2 && ((src | dest | len) & 3)) ||
++	    (shift == 1 && ((src | dest | len) & 1))) {
++		dev_err(chan2dev(chan), "%s: register or data misaligned\n",
++			__func__);
++		return NULL;
++	}
++
++	if (first) {
++		if (list_empty(&first->child_list))
++			prev = first;
++		else
++			prev = list_entry(first->child_list.prev,
++				struct ftdmac030_desc, node);
++	}
++
++	ctrl = FTDMAC030_CTRL_ENABLE | FTDMAC030_CTRL_1BEAT;
++
++	switch (shift) {
++	case 2:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_32
++		     |  FTDMAC030_CTRL_SRC_WIDTH_32;
++		break;
++	case 1:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_16
++		     |  FTDMAC030_CTRL_SRC_WIDTH_16;
++		break;
++	case 0:
++		ctrl |= FTDMAC030_CTRL_DST_WIDTH_8
++		     |  FTDMAC030_CTRL_SRC_WIDTH_8;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++		break;
++	}
++
++	if (fixed_src)
++		ctrl |= FTDMAC030_CTRL_SRC_FIXED;
++	else
++		ctrl |= FTDMAC030_CTRL_SRC_INC;
++
++	if (fixed_dest)
++		ctrl |= FTDMAC030_CTRL_DST_FIXED;
++	else
++		ctrl |= FTDMAC030_CTRL_DST_INC;
++
++	for (offset = 0; offset < len; offset += cycle << shift) {
++		struct ftdmac030_desc *desc;
++
++		cycle = min_t(size_t, (len - offset) >> shift,
++				MAX_CYCLE_PER_BLOCK);
++
++		desc = ftdmac030_desc_get(ftchan);
++		if (!desc)
++			goto err;
++
++		if (fixed_src)
++			desc->lld.src = src;
++		else
++			desc->lld.src = src + offset;
++
++		if (fixed_dest)
++			desc->lld.dst = dest;
++		else
++			desc->lld.dst = dest + offset;
++
++		desc->cfg = FTDMAC030_CFG_GW(GRANT_WINDOW)
++			  | FTDMAC030_CFG_HIGH_PRIO;
++		desc->len = cycle << shift;
++
++		desc->lld.next	= 0;
++		desc->lld.cycle	= FTDMAC030_CYC_TOTAL(cycle);
++		desc->lld.ctrl	= ctrl;
++
++		if (!first) {
++			first = desc;
++		} else {
++			/*
++			 * Mask terminal count interrupt for this descriptor.
++			 * What an inconvenient stupid design.
++			 */
++			prev->lld.ctrl |= FTDMAC030_CTRL_MASK_TC;
++
++			/* hardware link list pointer */
++			prev->lld.next = desc->txd.phys;
++
++			/* insert the link descriptor to the transfer chain */
++			list_add_tail(&desc->node, &first->child_list);
++		}
++
++		prev = desc;
++	}
++
++	return first;
++err:
++	if (first)
++		ftdmac030_remove_chain(first);
++	return NULL;
++}
++
++static void ftdmac030_start_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++	void __iomem *base = ftchan->ftdmac030->base;
++	int chan_id = ftchan->common.chan_id;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++
++	/*
++	 * The first transfer block is not described by hardware lld.
++	 * Instead, we should fill some hardware registers.
++	 * What a stupid weird design.
++	 */
++	dev_dbg(chan2dev(chan), "\t[SRC %d] = %x\n", chan_id, desc->lld.src);
++	iowrite32(desc->lld.src, base + FTDMAC030_OFFSET_SRC_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[DST %d] = %x\n", chan_id, desc->lld.dst);
++	iowrite32(desc->lld.dst, base + FTDMAC030_OFFSET_DST_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[LLP %d] = %x\n", chan_id, desc->lld.next);
++	iowrite32(desc->lld.next, base + FTDMAC030_OFFSET_LLP_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CYC %d] = %x\n", chan_id, desc->lld.cycle);
++	iowrite32(desc->lld.cycle, base + FTDMAC030_OFFSET_CYC_CH(chan_id));
++
++	/* go */
++	dev_dbg(chan2dev(chan), "\t[CFG %d] = %x\n", chan_id, desc->cfg);
++	iowrite32(desc->cfg, base + FTDMAC030_OFFSET_CFG_CH(chan_id));
++	dev_dbg(chan2dev(chan), "\t[CTRL %d] = %x\n", chan_id, desc->lld.ctrl);
++	iowrite32(desc->lld.ctrl, base + FTDMAC030_OFFSET_CTRL_CH(chan_id));
++}
++
++static void ftdmac030_start_new_chain(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (list_empty(&ftchan->active_list))
++		return;
++
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac030_desc, node);
++	ftdmac030_start_chain(desc);
++}
++
++static void ftdmac030_finish_chain(struct ftdmac030_desc *desc)
++{
++	struct ftdmac030_chan *ftchan = desc->ftchan;
++	struct dma_chan *chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s(%p)\n", __func__, desc);
++	spin_lock_bh(&ftchan->lock);
++	ftchan->completed_cookie = desc->txd.cookie;
++	spin_unlock_bh(&ftchan->lock);
++
++	/*
++	 * The API requires that no submissions are done from a
++	 * callback, so we don't need to drop the lock here
++	 */
++	if (desc->txd.callback)
++		desc->txd.callback(desc->txd.callback_param);
++
++	ftdmac030_remove_chain(desc);
++}
++
++static void ftdmac030_finish_all_chains(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_desc *tmp;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	list_for_each_entry_safe(desc, tmp, &ftchan->active_list, node) {
++		list_del(&desc->node);
++		ftdmac030_finish_chain(desc);
++	}
++}
++
++static dma_cookie_t ftdmac030_new_cookie(struct ftdmac030_chan *ftchan)
++{
++	struct dma_chan *chan = &ftchan->common;
++	dma_cookie_t cookie = ftchan->common.cookie;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	if (++cookie < 0)
++		cookie = DMA_MIN_COOKIE;
++
++	return cookie;
++}
++
++/******************************************************************************
++ * filter function for dma_request_channel()
++ *****************************************************************************/
++bool ftdmac030_chan_filter(struct dma_chan *chan, void *data)
++{
++	const char *drv_name = dev_driver_string(chan->device->dev);
++	struct ftdmac030_dma_slave *slave = data;
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030 *ftdmac030;
++
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++	ftdmac030 = ftchan->ftdmac030;
++
++	if (strncmp(DRV_NAME, drv_name, sizeof(DRV_NAME)))
++		return false;
++
++	if (slave->id >= 0 && slave->id != ftdmac030->id)
++		return false;
++
++	if ((slave->channels & (1 << chan->chan_id)) == 0)
++		return false;
++
++	chan->private = slave;
++	return true;
++}
++EXPORT_SYMBOL_GPL(ftdmac030_chan_filter);
++
++/******************************************************************************
++ * tasklet - called after we finished one chain
++ *****************************************************************************/
++static void ftdmac030_tasklet(unsigned long data)
++{
++	struct ftdmac030_chan *ftchan = (struct ftdmac030_chan *)data;
++	struct dma_chan *chan = &ftchan->common;
++	struct ftdmac030_desc *desc;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	BUG_ON(list_empty(&ftchan->active_list));
++
++	spin_lock_bh(&ftchan->lock);
++
++	/* remove already finished descriptor */
++	desc = list_first_entry(&ftchan->active_list, struct ftdmac030_desc,
++		node);
++	list_del(&desc->node);
++
++	/* check if there were another transfer to do */
++	ftdmac030_start_new_chain(ftchan);
++
++	spin_unlock_bh(&ftchan->lock);
++	ftdmac030_finish_chain(desc);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftdmac030_interrupt(int irq, void *dev_id)
++{
++	struct ftdmac030 *ftdmac030 = dev_id;
++	unsigned int tcs;
++	unsigned int eas;
++	int i;
++
++	tcs = ioread32(ftdmac030->base + FTDMAC030_OFFSET_TCISR);
++	eas = ioread32(ftdmac030->base + FTDMAC030_OFFSET_EAISR);
++	if (!tcs && !eas)
++		return IRQ_NONE;
++
++	/* clear status */
++	if (tcs)
++		iowrite32(tcs, ftdmac030->base + FTDMAC030_OFFSET_TCICR);
++	if (eas)
++		iowrite32(eas, ftdmac030->base + FTDMAC030_OFFSET_EAICR);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++		struct dma_chan *chan = &ftchan->common;
++
++		if (eas & FTDMAC030_EA_ERR_CH(i))
++			dev_info(chan2dev(chan), "error happened\n");
++
++		if (eas & FTDMAC030_EA_ABT_CH(i))
++			dev_info(chan2dev(chan), "transfer aborted\n");
++
++		if (tcs & (1 << i)) {
++			dev_dbg(chan2dev(chan), "terminal count\n");
++			tasklet_schedule(&ftchan->tasklet);
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/******************************************************************************
++ * struct dma_async_tx_descriptor function
++ *****************************************************************************/
++
++/**
++ * ftdmac030_tx_submit - set the prepared descriptor(s) to be executed by the engine
++ * @txd: async transaction descriptor
++ */
++static dma_cookie_t ftdmac030_tx_submit(struct dma_async_tx_descriptor *txd)
++{
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_chan *ftchan;
++	struct dma_chan *chan;
++	dma_cookie_t cookie;
++	bool busy;
++
++	desc = container_of(txd, struct ftdmac030_desc, txd);
++	ftchan = desc->ftchan;
++	chan = &ftchan->common;
++
++	dev_dbg(chan2dev(chan), "%s: submit desc %p\n", __func__, desc);
++	/* we support simple situation only */
++	BUG_ON(!async_tx_test_ack(txd));
++
++	spin_lock_bh(&ftchan->lock);
++
++	cookie = ftdmac030_new_cookie(ftchan);
++	ftchan->common.cookie = cookie;
++	txd->cookie = cookie;
++
++	if (list_empty(&ftchan->active_list))
++		busy = false;
++	else
++		busy = true;
++
++	list_add_tail(&desc->node, &ftchan->active_list);
++
++	/* start ASAP */
++	if (!busy)
++		ftdmac030_start_chain(desc);
++
++	spin_unlock_bh(&ftchan->lock);
++
++	return cookie;
++}
++
++/******************************************************************************
++ * struct dma_device functions
++ *****************************************************************************/
++
++/**
++ * ftdmac030_alloc_chan_resources - allocate resources for DMA channel
++ * @chan: DMA channel
++ */
++static int ftdmac030_alloc_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac030_chan *ftchan;
++	LIST_HEAD(tmp_list);
++	int i;
++
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	/* have we already been set up?
++	 * reconfigure channel but no need to reallocate descriptors */
++	if (!list_empty(&ftchan->free_list))
++		return ftchan->descs_allocated;
++
++	/* Allocate initial pool of descriptors */
++	for (i = 0; i < init_nr_desc_per_channel; i++) {
++		struct ftdmac030_desc *desc;
++
++		desc = ftdmac030_alloc_desc(ftchan, GFP_KERNEL);
++		if (!desc) {
++			dev_err(chan2dev(chan),
++				"Only %d initial descriptors\n", i);
++			break;
++		}
++		list_add_tail(&desc->node, &tmp_list);
++	}
++
++	spin_lock_bh(&ftchan->lock);
++	ftchan->descs_allocated = i;
++	list_splice(&tmp_list, &ftchan->free_list);
++	ftchan->completed_cookie = chan->cookie = 1;
++	spin_unlock_bh(&ftchan->lock);
++
++	dev_dbg(chan2dev(chan), "%s: allocated %d descriptors\n",
++		__func__, ftchan->descs_allocated);
++
++	return ftchan->descs_allocated;
++}
++
++/**
++ * ftdmac030_free_chan_resources - free all channel resources
++ * @chan: DMA channel
++ */
++static void ftdmac030_free_chan_resources(struct dma_chan *chan)
++{
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc;
++	struct ftdmac030_desc *tmp;
++	struct ftdmac030 *ftdmac030;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++	ftdmac030 = ftchan->ftdmac030;
++
++	/* channel must be idle */
++	BUG_ON(!list_empty(&ftchan->active_list));
++	BUG_ON(ftdmac030_chan_is_enabled(ftchan));
++
++	spin_lock_bh(&ftchan->lock);
++	ftdmac030_stop_channel(ftchan);
++	ftdmac030_finish_all_chains(ftchan);
++	list_for_each_entry_safe(desc, tmp, &ftchan->free_list, node) {
++		dev_dbg(chan2dev(chan), "  freeing descriptor %p\n", desc);
++		list_del(&desc->node);
++		/* free link descriptor */
++		ftdmac030_free_desc(desc);
++	}
++
++	ftchan->descs_allocated = 0;
++	spin_unlock_bh(&ftchan->lock);
++}
++
++/**
++ * ftdmac030_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac030_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
++		dma_addr_t src, size_t len, unsigned long flags)
++{
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc;
++	unsigned int shift;
++
++	dev_dbg(chan2dev(chan), "%s(src %x, dest %x, len %x)\n",
++		__func__, src, dest, len);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	if (unlikely(!len)) {
++		dev_info(chan2dev(chan), "%s: length is zero!\n", __func__);
++		return NULL;
++	}
++
++	/*
++	 * We can be a lot more clever here, but this should take care
++	 * of the most common optimization.
++	 */
++	if (!((src | dest | len) & 3)) {
++		shift = 2;
++	} else if (!((src | dest | len) & 1)) {
++		shift = 1;
++	} else {
++		shift = 0;
++	}
++
++	desc = ftdmac030_create_chain(ftchan, NULL, src, dest, len,
++		shift, 0, 0);
++	if (!desc)
++		goto err;
++
++	desc->txd.flags = flags;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++/**
++ * ftdmac030_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
++ * @chan: DMA channel
++ * @sgl: scatterlist to transfer to/from
++ * @sg_len: number of entries in @scatterlist
++ * @direction: DMA direction
++ * @flags: tx descriptor status flags
++ */
++static struct dma_async_tx_descriptor *
++ftdmac030_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
++		unsigned int sg_len, enum dma_data_direction direction,
++		unsigned long flags)
++{
++	struct ftdmac030_dma_slave *slave = chan->private;
++	struct ftdmac030_chan *ftchan;
++	struct ftdmac030_desc *desc = NULL;
++	struct scatterlist *sg;
++	unsigned int shift;
++	unsigned int i;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	if (unlikely(!slave)) {
++		dev_err(chan2dev(chan), "%s: no slave data\n", __func__);
++		return NULL;
++	}
++
++	if (unlikely(!sg_len)) {
++		dev_err(chan2dev(chan), "%s: scatter list length is 0\n",
++			__func__);
++		return NULL;
++	}
++
++	if (unlikely(slave->common.src_addr_width !=
++		     slave->common.dst_addr_width)) {
++		dev_err(chan2dev(chan), "%s: data width mismatched\n",
++			__func__);
++		return NULL;
++	}
++
++	switch (slave->common.src_addr_width) {
++	case DMA_SLAVE_BUSWIDTH_1_BYTE:
++		shift = 0;
++		break;
++	case DMA_SLAVE_BUSWIDTH_2_BYTES:
++		shift = 1;
++		break;
++	case DMA_SLAVE_BUSWIDTH_4_BYTES:
++		shift = 2;
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect data width\n",
++			__func__);
++		BUG();
++	}
++
++	switch (direction) {
++	case DMA_TO_DEVICE:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac030_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftdmac030_create_chain(ftchan, desc,
++				mem, slave->common.dst_addr, len,
++				shift, 0, 1);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC030_CFG_DST_HANDSHAKE_EN
++				| FTDMAC030_CFG_DST_HANDSHAKE(slave->handshake);
++		break;
++	case DMA_FROM_DEVICE:
++		for_each_sg(sgl, sg, sg_len, i) {
++			struct ftdmac030_desc *tmp;
++			unsigned int len;
++			dma_addr_t mem;
++
++			mem = sg_phys(sg);
++			len = sg_dma_len(sg);
++
++			tmp = ftdmac030_create_chain(ftchan, desc,
++				slave->common.src_addr, mem, len,
++				shift, 1, 0);
++			if (!tmp)
++				goto err;
++
++			if (!desc)
++				desc = tmp;
++		}
++
++		if (slave->handshake >= 0)
++			desc->cfg = FTDMAC030_CFG_SRC_HANDSHAKE_EN
++				| FTDMAC030_CFG_SRC_HANDSHAKE(slave->handshake);
++		break;
++	default:
++		dev_err(chan2dev(chan), "%s: incorrect direction\n",
++			__func__);
++		goto err;
++	}
++
++	desc->txd.flags = flags;
++
++	return &desc->txd;
++
++err:
++	return NULL;
++}
++
++static int ftdmac030_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
++		unsigned long arg)
++{
++	struct ftdmac030_chan *ftchan;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	/* Only supports DMA_TERMINATE_ALL */
++	if (cmd != DMA_TERMINATE_ALL)
++		return -ENXIO;
++
++	/*
++	 * This is only called when something went wrong elsewhere, so
++	 * we don't really care about the data. Just disable the channel.
++	 */
++	spin_lock_bh(&ftchan->lock);
++	ftdmac030_stop_channel(ftchan);
++	ftdmac030_finish_all_chains(ftchan);
++	spin_unlock_bh(&ftchan->lock);
++	return 0;
++}
++
++/**
++ * ftdmac030_tx_status - poll for transaction completion
++ * @chan: DMA channel
++ * @cookie: transaction identifier to check status of
++ * @txstate: if not %NULL updated with transaction state
++ *
++ * If @txstate is passed in, upon return it reflect the driver
++ * internal state and can be used with dma_async_is_complete() to check
++ * the status of multiple cookies without re-checking hardware state.
++ */
++static enum dma_status
++ftdmac030_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++		struct dma_tx_state *txstate)
++{
++	struct ftdmac030_chan *ftchan;
++	dma_cookie_t last_used;
++	dma_cookie_t last_complete;
++	enum dma_status ret;
++
++	dev_dbg(chan2dev(chan), "%s\n", __func__);
++	ftchan = container_of(chan, struct ftdmac030_chan, common);
++
++	last_complete = ftchan->completed_cookie;
++	last_used = chan->cookie;
++
++	ret = dma_async_is_complete(cookie, last_complete, last_used);
++	dma_set_tx_state(txstate, last_complete, last_used, 0);
++
++	return ret;
++}
++
++/**
++ * ftdmac030_issue_pending - try to finish work
++ * @chan: target DMA channel
++ */
++static void ftdmac030_issue_pending(struct dma_chan *chan)
++{
++	/*
++	 * We are posting descriptors to the hardware as soon as
++	 * they are ready, so this function does nothing.
++	 */
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftdmac030_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct ftdmac030 *ftdmac030;
++	struct dma_device *dma;
++	int irq;
++	int i;
++	int err;
++
++	if (pdev == NULL)
++		return -ENODEV;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++
++	ftdmac030 = kzalloc(sizeof(*ftdmac030), GFP_KERNEL);
++	if (!ftdmac030) {
++		return -ENOMEM;
++	}
++
++	dma = &ftdmac030->dma;
++
++	INIT_LIST_HEAD(&dma->channels);
++	dma->dev = &pdev->dev;
++
++	platform_set_drvdata(pdev, ftdmac030);
++	ftdmac030->id = pdev->id;
++
++	/* map io memory */
++
++	ftdmac030->res = request_mem_region(res->start, res->end - res->start + 1,
++			dev_name(&pdev->dev));
++	if (ftdmac030->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftdmac030->base = ioremap(res->start, res->end - res->start + 1);
++	if (ftdmac030->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	/* create a pool of consistent memory blocks for hardware descriptors */
++	ftdmac030->dma_desc_pool = dma_pool_create("ftdmac030_desc_pool",
++			&pdev->dev, sizeof(struct ftdmac030_desc),
++			4 /* word alignment */, 0);
++	if (!ftdmac030->dma_desc_pool) {
++		dev_err(&pdev->dev, "No memory for descriptor pool\n");
++		err = -ENOMEM;
++		goto err_pool_create;
++	}
++
++	/* initialize channels */
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		INIT_LIST_HEAD(&ftchan->active_list);
++		INIT_LIST_HEAD(&ftchan->free_list);
++		ftchan->common.device	= dma;
++		ftchan->common.cookie	= DMA_MIN_COOKIE;
++
++		spin_lock_init(&ftchan->lock);
++		ftchan->ftdmac030		= ftdmac030;
++		ftchan->completed_cookie	= DMA_MIN_COOKIE;
++
++		tasklet_init(&ftchan->tasklet, ftdmac030_tasklet,
++				(unsigned long)ftchan);
++		list_add_tail(&ftchan->common.device_node, &dma->channels);
++	}
++
++	/* initialize dma_device */
++	dma->device_alloc_chan_resources = ftdmac030_alloc_chan_resources;
++	dma->device_free_chan_resources	= ftdmac030_free_chan_resources;
++	dma->device_prep_dma_memcpy	= ftdmac030_prep_dma_memcpy;
++	dma->device_prep_slave_sg	= ftdmac030_prep_slave_sg;
++	dma->device_control		= ftdmac030_control;
++	dma->device_tx_status		= ftdmac030_tx_status;
++	dma->device_issue_pending	= ftdmac030_issue_pending;
++
++	/* set DMA capability */
++	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
++	dma_cap_set(DMA_SLAVE, dma->cap_mask);
++
++	err = request_irq(irq, ftdmac030_interrupt, IRQF_SHARED, pdev->name,
++		ftdmac030);
++	if (err) {
++		dev_err(&pdev->dev, "failed to request irq %d\n", irq);
++		goto err_req_irq;
++	}
++
++	ftdmac030->irq = irq;
++
++	err = dma_async_device_register(dma);
++	if (err) {
++		dev_err(&pdev->dev, "failed to register dma device\n");
++		goto err_register;
++	}
++
++	dev_info(&pdev->dev,
++		"DMA engine driver: irq %d, mapped at %p\n",
++		irq, ftdmac030->base);
++
++	return 0;
++
++err_register:
++	free_irq(irq, ftdmac030);
++err_req_irq:
++	dma_pool_destroy(ftdmac030->dma_desc_pool);
++err_pool_create:
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		list_del(&ftchan->common.device_node);
++		tasklet_kill(&ftchan->tasklet);
++	}
++
++	iounmap(ftdmac030->base);
++err_ioremap:
++	release_resource(ftdmac030->res);
++err_req_mem:
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac030);
++	return err;
++}
++
++static int __exit ftdmac030_remove(struct platform_device *pdev)
++{
++	struct ftdmac030 *ftdmac030;
++	int i;
++
++	ftdmac030 = platform_get_drvdata(pdev);
++
++	dma_async_device_unregister(&ftdmac030->dma);
++
++	free_irq(ftdmac030->irq, ftdmac030);
++	dma_pool_destroy(ftdmac030->dma_desc_pool);
++
++	for (i = 0; i < CHANNEL_NR; i++) {
++		struct ftdmac030_chan *ftchan = &ftdmac030->channel[i];
++
++		tasklet_disable(&ftchan->tasklet);
++		tasklet_kill(&ftchan->tasklet);
++		list_del(&ftchan->common.device_node);
++	}
++
++	iounmap(ftdmac030->base);
++	release_resource(ftdmac030->res);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(ftdmac030);
++	return 0;
++}
++
++static struct platform_driver ftdmac030_driver = {
++	.probe		= ftdmac030_probe,
++	.remove		= __exit_p(ftdmac030_remove),
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftdmac030_init(void)
++{
++	return platform_driver_register(&ftdmac030_driver);
++}
++
++static void __exit ftdmac030_exit(void)
++{
++	platform_driver_unregister(&ftdmac030_driver);
++}
++
++module_init(ftdmac030_init);
++module_exit(ftdmac030_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTDMAC030 DMA engine driver");
++MODULE_LICENSE("GPL");
+diff --git a/arch/arm/mach-faraday/ftintc010.c b/arch/arm/mach-faraday/ftintc010.c
+new file mode 100644
+index 00000000..eb8ff4c2
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftintc010.c
+@@ -0,0 +1,462 @@
++/*
++ *  linux/arch/arm/mach-faraday/ftintc010.c
++ *
++ *  Faraday FTINTC010 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++
++#include <asm/mach/irq.h>
++#include <mach/ftintc010.h>
++
++void __iomem *ftintc010_base_addr __read_mostly;
++
++struct ftintc010_chip_data {
++	unsigned int irq_offset;
++	void __iomem *base;
++};
++
++#ifndef MAX_FTINTC010_NR
++#define MAX_FTINTC010_NR	1
++#endif
++
++static struct ftintc010_chip_data ftintc010_data[MAX_FTINTC010_NR];
++static DEFINE_SPINLOCK(ftintc010_lock);
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline void __iomem *ftintc010_base(unsigned int irq)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_chip_data(irq);
++	return chip_data->base;
++}
++
++/*
++ * return hardware irq number
++ */
++static inline unsigned int ftintc010_irq(unsigned int irq)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_chip_data(irq);
++	return irq - chip_data->irq_offset;
++}
++
++#ifdef CONFIG_FTINTC010EX
++static inline void ftintc010_clear_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	if (hw_irq < 32) {
++		mask = 1 << hw_irq;
++
++		writel(mask, base + FTINTC010_OFFSET_IRQCLEAR);
++	} else {
++		mask = 1 << (hw_irq - 32);
++		writel(mask, base + FTINTC010_OFFSET_IRQCLEAREX);
++	}
++}
++
++static inline void ftintc010_mask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	if (hw_irq < 32) {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASK);
++		mask &= ~(1 << hw_irq);
++		writel(mask, base + FTINTC010_OFFSET_IRQMASK);
++	} else {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASKEX);
++		mask &= ~(1 << (hw_irq - 32));
++		writel(mask, base + FTINTC010_OFFSET_IRQMASKEX);
++	}
++}
++
++static inline void ftintc010_unmask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	if (hw_irq < 32) {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASK);
++		mask |= 1 << hw_irq;
++		writel(mask, base + FTINTC010_OFFSET_IRQMASK);
++	} else {
++		mask = readl(base + FTINTC010_OFFSET_IRQMASKEX);
++		mask |= 1 << (hw_irq - 32);
++		writel(mask, base + FTINTC010_OFFSET_IRQMASKEX);
++	}
++}
++
++static inline void ftintc010_set_trig_mode(void __iomem *base, unsigned int hw_irq,
++	int mode)
++{
++	unsigned int irqmode;
++
++	/*
++	 * 0: level trigger
++	 * 1: edge trigger
++	 */
++	if (hw_irq < 32) {
++		irqmode = readl(base + FTINTC010_OFFSET_IRQMODE);
++		if (mode)
++			irqmode |= 1 << hw_irq;
++		else
++			irqmode &= ~(1 << hw_irq);
++		writel(irqmode, base + FTINTC010_OFFSET_IRQMODE);
++	} else {
++		irqmode = readl(base + FTINTC010_OFFSET_IRQMODEEX);
++		if (mode)
++			irqmode |= 1 << (hw_irq - 32);
++		else
++			irqmode &= ~(1 << (hw_irq - 32));
++		writel(irqmode, base + FTINTC010_OFFSET_IRQMODEEX);
++	}
++}
++
++static inline void ftintc010_set_trig_level(void __iomem *base, unsigned int hw_irq,
++	int level)
++{
++	unsigned int irqlevel;
++
++	/*
++	 * 0: active-high level trigger / rising edge trigger
++	 * 1: active-low level trigger / falling edge trigger
++	 */
++	if (hw_irq < 32) {
++		irqlevel = readl(base + FTINTC010_OFFSET_IRQLEVEL);
++		if (level)
++			irqlevel |= 1 << hw_irq;
++		else
++			irqlevel &= ~(1 << hw_irq);
++		writel(irqlevel, base + FTINTC010_OFFSET_IRQLEVEL);
++	} else {
++		irqlevel = readl(base + FTINTC010_OFFSET_IRQLEVELEX);
++		if (level)
++			irqlevel |= 1 << (hw_irq - 32);
++		else
++			irqlevel &= ~(1 << (hw_irq - 32));
++		writel(irqlevel, base + FTINTC010_OFFSET_IRQLEVELEX);
++	}
++}
++#else	/* CONFIG_FTINTC010EX */
++static inline void ftintc010_clear_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask = 1 << hw_irq;
++
++	writel(mask, base + FTINTC010_OFFSET_IRQCLEAR);
++}
++
++static inline void ftintc010_mask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	mask = readl(base + FTINTC010_OFFSET_IRQMASK);
++	mask &= ~(1 << hw_irq);
++	writel(mask, base + FTINTC010_OFFSET_IRQMASK);
++}
++
++static inline void ftintc010_unmask_irq(void __iomem *base, unsigned int hw_irq)
++{
++	unsigned int mask;
++
++	/*
++	 * 0: masked
++	 * 1: unmasked
++	 */
++	mask = readl(base + FTINTC010_OFFSET_IRQMASK);
++	mask |= 1 << hw_irq;
++	writel(mask, base + FTINTC010_OFFSET_IRQMASK);
++}
++
++static inline void ftintc010_set_trig_mode(void __iomem *base, unsigned int hw_irq,
++	int mode)
++{
++	unsigned int irqmode;
++
++	irqmode = readl(base + FTINTC010_OFFSET_IRQMODE);
++
++	/*
++	 * 0: level trigger
++	 * 1: edge trigger
++	 */
++	if (mode)
++		irqmode |= 1 << hw_irq;
++	else
++		irqmode &= ~(1 << hw_irq);
++
++	writel(irqmode, base + FTINTC010_OFFSET_IRQMODE);
++}
++
++static inline void ftintc010_set_trig_level(void __iomem *base, unsigned int hw_irq,
++	int level)
++{
++	unsigned int irqlevel;
++
++	irqlevel = readl(base + FTINTC010_OFFSET_IRQLEVEL);
++
++	/*
++	 * 0: active-high level trigger / rising edge trigger
++	 * 1: active-low level trigger / falling edge trigger
++	 */
++	if (level)
++		irqlevel |= 1 << hw_irq;
++	else
++		irqlevel &= ~(1 << hw_irq);
++
++	writel(irqlevel, base + FTINTC010_OFFSET_IRQLEVEL);
++}
++#endif	/* CONFIG_FTINTC010EX */
++
++/******************************************************************************
++ * struct irq_chip functions
++ *****************************************************************************/
++static int ftintc010_set_type(struct irq_data *data, unsigned int type)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++	int mode = 0;
++	int level = 0;
++
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_LEVEL_HIGH:
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++		level = 1;
++		/* fall through */
++
++	case IRQ_TYPE_EDGE_RISING:
++		mode = 1;
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_set_trig_mode(base, hw_irq, mode);
++	ftintc010_set_trig_level(base, hw_irq, level);
++	spin_unlock(&ftintc010_lock);
++	return 0;
++}
++
++/*
++ * Edge trigger IRQ chip methods
++ */
++static void ftintc010_edge_ack(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_clear_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static void ftintc010_mask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_mask_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static void ftintc010_unmask(struct irq_data *data)
++{
++	unsigned int hw_irq = ftintc010_irq(data->irq);
++	void __iomem *base = ftintc010_base(data->irq);
++
++	spin_lock(&ftintc010_lock);
++	ftintc010_unmask_irq(base, hw_irq);
++	spin_unlock(&ftintc010_lock);
++}
++
++static struct irq_chip ftintc010_edge_chip = {
++	.irq_ack	= ftintc010_edge_ack,
++	.irq_mask	= ftintc010_mask,
++	.irq_unmask	= ftintc010_unmask,
++	.irq_set_type	= ftintc010_set_type,
++};
++
++/*
++ * Level trigger IRQ chip methods
++ */
++static void ftintc010_level_ack(struct irq_data *data)
++{
++	/* do nothing */
++}
++
++static struct irq_chip ftintc010_level_chip = {
++	.irq_ack	= ftintc010_level_ack,
++	.irq_mask	= ftintc010_mask,
++	.irq_unmask	= ftintc010_unmask,
++	.irq_set_type	= ftintc010_set_type,
++};
++
++/******************************************************************************
++ * initialization functions
++ *****************************************************************************/
++static void ftintc010_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
++{
++	struct ftintc010_chip_data *chip_data = irq_get_handler_data(irq);
++	struct irq_chip *chip = irq_get_chip(irq);
++	unsigned int cascade_irq, hw_irq;
++	unsigned long status;
++
++	chained_irq_enter(chip, desc);
++
++	spin_lock(&ftintc010_lock);
++	status = readl(chip_data->base + FTINTC010_OFFSET_IRQSTATUS);
++	spin_unlock(&ftintc010_lock);
++
++#ifdef CONFIG_FTINTC010EX
++	if (status) {
++		hw_irq = ffs(status) - 1;
++	} else {
++		status = readl(chip_data->base + FTINTC010_OFFSET_IRQSTATUSEX);
++
++		if (!status)
++			goto out;
++
++		hw_irq = ffs(status) - 1 + 32;
++	}
++#else
++	if (!status)
++		goto out;
++
++	hw_irq = ffs(status) - 1;
++#endif
++
++	cascade_irq = hw_irq + chip_data->irq_offset;
++	generic_handle_irq(cascade_irq);
++
++out:
++	chained_irq_exit(chip, desc);
++}
++
++void __init ftintc010_cascade_irq(unsigned int ftintc010_nr, unsigned int irq)
++{
++	if (ftintc010_nr >= MAX_FTINTC010_NR)
++		BUG();
++	if (irq_set_handler_data(irq, &ftintc010_data[ftintc010_nr]) != 0)
++		BUG();
++
++	irq_set_chained_handler(irq, ftintc010_handle_cascade_irq);
++}
++
++int ftintc010_set_irq_type(unsigned int irq, unsigned int type)
++{
++	switch (type) {
++	case IRQ_TYPE_LEVEL_LOW:
++	case IRQ_TYPE_LEVEL_HIGH:
++		irq_set_chip(irq, &ftintc010_level_chip);
++		irq_set_handler(irq, handle_level_irq);
++		break;
++
++	case IRQ_TYPE_EDGE_FALLING:
++	case IRQ_TYPE_EDGE_RISING:
++		irq_set_chip(irq, &ftintc010_edge_chip);
++		irq_set_handler(irq, handle_edge_irq);
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	return irq_set_irq_type(irq, type);
++}
++
++/*
++ * Initialization of master interrupt controller, after this INTC is
++ * enabled, the rest of Linux initialization codes can then be completed.
++ * For example, timer interrupts and UART interrupts must be enabled during
++ * the boot process.
++ */
++void __init ftintc010_init(unsigned int ftintc010_nr, void __iomem *base,
++			   unsigned int irq_start)
++{
++	unsigned int irq;
++	unsigned int irq_end;
++
++	if (ftintc010_nr >= MAX_FTINTC010_NR)
++		BUG();
++
++	ftintc010_data[ftintc010_nr].base = base;
++	ftintc010_data[ftintc010_nr].irq_offset = irq_start;
++
++	/*
++	 * mask all interrupts
++	 */
++	writel(0, base + FTINTC010_OFFSET_IRQMASK);
++	writel(0, base + FTINTC010_OFFSET_FIQMASK);
++	writel(~0, base + FTINTC010_OFFSET_IRQCLEAR);
++	writel(~0, base + FTINTC010_OFFSET_FIQCLEAR);
++#ifdef CONFIG_FTINTC010EX
++	writel(0, base + FTINTC010_OFFSET_IRQMASKEX);
++	writel(~0, base + FTINTC010_OFFSET_IRQCLEAREX);
++#endif
++	/*
++	 * initial trigger mode and level
++	 */
++	writel(0, base + FTINTC010_OFFSET_IRQMODE);
++	writel(0, base + FTINTC010_OFFSET_IRQLEVEL);
++	writel(0, base + FTINTC010_OFFSET_FIQMODE);
++	writel(0, base + FTINTC010_OFFSET_FIQLEVEL);
++#ifdef CONFIG_FTINTC010EX
++	writel(0, base + FTINTC010_OFFSET_IRQMODEEX);
++	writel(0, base + FTINTC010_OFFSET_IRQLEVELEX);
++#endif
++
++	/*
++	 * setup the linux irq subsystem
++	 */
++#ifdef CONFIG_FTINTC010EX
++	irq_end = irq_start + 64;
++#else
++	irq_end = irq_start + 32;
++#endif
++	for (irq = irq_start; irq < irq_end; irq++) {
++		irq_set_chip_data(irq, &ftintc010_data[ftintc010_nr]);
++		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++		irq_set_chip_and_handler(irq, &ftintc010_level_chip, handle_level_irq);
++		irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
++	}
++
++	ftintc010_base_addr = base;
++}
+diff --git a/arch/arm/mach-faraday/ftpci100.c b/arch/arm/mach-faraday/ftpci100.c
+new file mode 100644
+index 00000000..7aa8835a
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftpci100.c
+@@ -0,0 +1,450 @@
++/*
++ *  linux/arch/arm/mach-faraday/ftpci100.c
++ *
++ *  Faraday FTPCI100 PCI Bridge Controller
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/pci.h>
++#include <asm/mach/pci.h>
++#include <linux/ioport.h>
++#include <asm/mach/irq.h>
++
++#include <mach/ftpci100.h>
++
++#include <mach/board-a320.h>
++
++#define CONFIG_FTPCI100_CASCADE_IRQ
++
++#ifndef MAX_FTPCI100_NR
++#define MAX_FTPCI100_NR	1
++#endif
++
++struct ftpci100_chip_data {
++	void __iomem *base;
++
++#ifdef CONFIG_FTPCI100_CASCADE_IRQ
++	unsigned int busnr;
++	unsigned int irq_offset;
++#endif
++};
++
++static struct ftpci100_chip_data ftpci100_data[MAX_FTPCI100_NR];
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline void __iomem *ftpci100_busnr_to_base(unsigned int busnr)
++{
++	void __iomem *base;
++
++	if (busnr >= MAX_FTPCI100_NR)
++		BUG();
++
++	base = ftpci100_data[busnr].base;
++
++	if (!base)
++		BUG();
++
++	return base;
++}
++
++static inline unsigned int
++ftpci100_config_command(unsigned int busnr, unsigned int devfn, int where)
++{
++	return FTPCI100_CONFIG_ENABLE
++		| FTPCI100_CONFIG_BUS(busnr)
++		| FTPCI100_CONFIG_DEVFN(devfn)
++		| FTPCI100_CONFIG_WHERE(where);
++}
++
++/******************************************************************************
++ * struct pci_ops functions
++ *****************************************************************************/
++static int ftpci100_read_config(struct pci_bus *bus, unsigned int devfn, int where,
++			     int size, u32 * val)
++{
++	void __iomem *base = ftpci100_busnr_to_base(bus->number);
++	unsigned int command = ftpci100_config_command(bus->number, devfn, where);
++	unsigned int data;
++
++	writel(command, base + FTPCI100_OFFSET_CONFIG);
++	data = readl(base + FTPCI100_OFFSET_CONFIGDATA);
++
++	switch (size) {
++	case 1:
++		if (where & 2) data >>= 16;
++		if (where & 1) data >>= 8;
++		data &= 0xff;
++
++		break;
++
++	case 2:
++		if (where & 2) data >>= 16;
++		data &= 0xffff;
++		break;
++
++	default:
++		break;
++	}
++
++	*val = data;
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int ftpci100_write_config(struct pci_bus *bus, unsigned int devfn,
++			      int where, int size, u32 val)
++{
++	void __iomem *base = ftpci100_busnr_to_base(bus->number);
++	unsigned int command = ftpci100_config_command(bus->number, devfn, where);
++	unsigned int data;
++	unsigned int shift;
++
++	writel(command, base + FTPCI100_OFFSET_CONFIG);
++
++	switch (size) {
++	case 1:
++		data = readl(base + FTPCI100_OFFSET_CONFIGDATA);
++		shift = (where & 0x3) * 8;
++		data &= ~(0xff << shift);
++		data |= (val & 0xff) << shift;
++		writel(data, base + FTPCI100_OFFSET_CONFIGDATA);
++		break;
++
++	case 2:
++		data = readl(base + FTPCI100_OFFSET_CONFIGDATA);
++		shift = (where & 0x3) * 8;
++		data &= ~(0xffff << shift);
++		data |= (val & 0xffff) << shift;
++		writel(data, base + FTPCI100_OFFSET_CONFIGDATA);
++		break;
++
++	case 4:
++		writel(val, base + FTPCI100_OFFSET_CONFIGDATA);
++		break;
++
++	default:
++		break;
++	}
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops ftpci100_ops = {
++	.read	= ftpci100_read_config,
++	.write	= ftpci100_write_config,
++};
++
++
++/******************************************************************************
++ * struct hw_pci functions
++ *****************************************************************************/
++
++/* using virtual address for pci_resource_start() function*/
++static struct resource ftpci100_io = {
++	.name	= "Faraday PCI I/O Space",
++	.start	= PCIIO_VA_BASE,
++	.end	= PCIIO_VA_LIMIT,
++	.flags	= IORESOURCE_IO,
++};
++
++/* using physical address for memory resource*/
++static struct resource ftpci100_mem = {
++	.name	= "Faraday PCI non-prefetchable Memory Space",
++	.start	= PCIMEM_PA_BASE,
++	.end	= PCIMEM_PA_LIMIT,
++	.flags	= IORESOURCE_MEM,
++};
++
++static int __init ftpci100_setup_resource(struct resource **resource)
++{
++	int ret;
++
++	ret = request_resource(&ioport_resource, &ftpci100_io);
++	if (ret) {
++		printk(KERN_ERR "PCI: unable to allocate io region (%d)\n", ret);
++		goto out;
++	}
++
++	ret = request_resource(&iomem_resource, &ftpci100_mem);
++	if (ret) {
++		printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
++		       "memory region\n");
++		goto release_io;
++	}
++
++	/*
++	 * bus->resource[0] is the IO resource for this bus
++	 * bus->resource[1] is the mem resource for this bus
++	 * bus->resource[2] is the prefetch mem resource for this bus
++	 */
++
++	resource[0] = &ftpci100_io;
++	resource[1] = &ftpci100_mem;
++	resource[2] = NULL;
++
++	return 1;
++
++release_io:
++	release_resource(&ftpci100_io);
++out:
++	return ret;
++}
++
++static int __init ftpci100_setup(int nr, struct pci_sys_data *sys)
++{
++	int ret = 0;
++
++	if (nr == 0) {
++		void __iomem *base = ftpci100_busnr_to_base(nr);
++		unsigned int command;
++		unsigned int data;
++
++		writel(FTPCI100_CONFIG_ENABLE, base + FTPCI100_OFFSET_CONFIG);
++		if (readl(base + FTPCI100_OFFSET_CONFIG) != FTPCI100_CONFIG_ENABLE)
++			return 0;
++
++		printk(KERN_INFO "PCI bridge %d found\n", nr);
++
++		/* enable interrupts (INTA/INTB/INTC/INTD) */
++
++		command = ftpci100_config_command(nr, 0, PCI_CR2);
++		writel(command, base + FTPCI100_OFFSET_CONFIG);
++
++		data = readl(base + FTPCI100_OFFSET_CONFIGDATA);
++		data |= PCI_CR2_INTA_ENABLE
++			| PCI_CR2_INTB_ENABLE
++			| PCI_CR2_INTC_ENABLE
++			| PCI_CR2_INTD_ENABLE;
++
++		writel(data, base + FTPCI100_OFFSET_CONFIGDATA);
++
++		/* write DMA start address/size data to the bridge configuration space */
++
++		command = ftpci100_config_command(nr, 0, PCI_MEM_BASE_SIZE_1);
++		writel(command, base + FTPCI100_OFFSET_CONFIG);
++
++		writel(PCI_MEM_SIZE_1G, base + FTPCI100_OFFSET_CONFIGDATA);
++
++		/* setup resources */
++
++		ret = ftpci100_setup_resource(sys->resource);
++
++		sys->mem_offset = 0;	//PCIMEM_VA_BASE - PCIMEM_PA_BASE;
++		sys->io_offset = PCIIO_VA_BASE - PCIIO_PA_BASE;
++	}
++
++	return ret;
++}
++
++static struct pci_bus __init *ftpci100_scan_bus(int nr, struct pci_sys_data *sys)
++{
++	return pci_scan_bus(sys->busnr, &ftpci100_ops, sys);
++}
++
++/*
++ * map the specified device/slot/pin to an IRQ
++ * different backplanes may need to modify this
++ */
++static int __init ftpci100_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++	int devslot = PCI_SLOT(dev->devfn);
++	int irq = -1;
++
++	switch (devslot) {
++	case 8:
++		irq = IRQ_FTPCI100_0_A;
++		break;
++
++	case 9:
++		irq = IRQ_FTPCI100_0_B;
++		break;
++
++	case 10:
++		irq = IRQ_FTPCI100_0_C;
++		break;
++
++	case 11:
++		irq = IRQ_FTPCI100_0_D;
++		break;
++
++	default:
++		printk(KERN_INFO "slot %d not supported\n", slot);
++		break;
++	}
++
++	printk(KERN_INFO "PCI map irq: slot %d, pin %d, devslot %d, irq: %d\n",
++		slot, pin, devslot, irq);
++
++	return irq;
++}
++static struct hw_pci ftpci100_hw __initdata = {
++	.nr_controllers	= 1,
++	.setup		= ftpci100_setup,
++	.scan		= ftpci100_scan_bus,
++	.map_irq	= ftpci100_map_irq,
++};
++
++/******************************************************************************
++ * initialization
++ *****************************************************************************/
++void __init ftpci100_init(unsigned int nr, void __iomem *base)
++{
++	if (nr >= MAX_FTPCI100_NR)
++		BUG();
++
++	ftpci100_data[nr].base = base;
++}
++
++static int __init ftpci100_bus_init(void)
++{
++	pci_common_init(&ftpci100_hw);
++
++	return 0;
++}
++
++subsys_initcall(ftpci100_bus_init);
++
++/******************************************************************************
++ * irq handling
++ *
++ * There are 4 irq lines on FTPCI100.
++ *
++ * If the 4 irq lines are connected to the same irq line of the upper interrupt
++ * controller, FTPCI100 needs to pretend that it is a secondary interrupt
++ * controller.
++ *
++ * If the 4 lines are connected to 4 irq lines of the upper interrupt
++ * controller directly, we do not need the following stuff at all.
++ *****************************************************************************/
++#ifdef CONFIG_FTPCI100_CASCADE_IRQ
++
++/******************************************************************************
++ * struct irq_chip functions
++ *****************************************************************************/
++static void ftpci100_int_ack(unsigned int irq)
++{
++	/* do nothing */
++}
++
++static void ftpci100_int_mask(unsigned int irq)
++{
++	/* do nothing */
++}
++
++static void ftpci100_int_unmask(unsigned int irq)
++{
++	/* do nothing */
++}
++
++static struct irq_chip ftpci100_int_chip = {
++	.ack	= ftpci100_int_ack,
++	.mask	= ftpci100_int_mask,
++	.unmask	= ftpci100_int_unmask,
++};
++
++/******************************************************************************
++ * initialization functions
++ *****************************************************************************/
++static void ftpci100_int_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
++{
++	struct ftpci100_chip_data *chip_data = get_irq_data(irq);
++	struct irq_chip *chip = get_irq_chip(irq);
++	unsigned int command;
++	void __iomem *base;
++	unsigned int cascade_irq, hw_irq;
++	unsigned int cr2;
++
++	/* primary controller ack'ing */
++	chip->mask(irq);
++	chip->ack(irq);
++
++	command = ftpci100_config_command(chip_data->busnr, 0, PCI_CR2);
++	base = chip_data->base;
++
++	writel(command, base + FTPCI100_OFFSET_CONFIG);
++	cr2 = readl(base + FTPCI100_OFFSET_CONFIGDATA);
++
++
++	if (cr2 & PCI_CR2_STATUS_INTA) {
++		hw_irq = 0;
++		cr2 &= ~PCI_CR2_STATUS_MASK;
++		cr2 |= PCI_CR2_STATUS_INTA;
++
++	} else if (cr2 & PCI_CR2_STATUS_INTB) {
++		hw_irq = 1;
++		cr2 &= ~PCI_CR2_STATUS_MASK;
++		cr2 |= PCI_CR2_STATUS_INTB;
++
++	} else if (cr2 & PCI_CR2_STATUS_INTC) {
++		hw_irq = 2;
++		cr2 &= ~PCI_CR2_STATUS_MASK;
++		cr2 |= PCI_CR2_STATUS_INTC;
++
++	} else if (cr2 & PCI_CR2_STATUS_INTD) {
++		hw_irq = 3;
++		cr2 &= ~PCI_CR2_STATUS_MASK;
++		cr2 |= PCI_CR2_STATUS_INTD;
++
++	} else
++		goto out;
++
++	cascade_irq = hw_irq + chip_data->irq_offset;
++	generic_handle_irq(cascade_irq);
++
++	/* clear interrupt status */
++
++	writel(command, base + FTPCI100_OFFSET_CONFIG);
++	writel(cr2, base + FTPCI100_OFFSET_CONFIGDATA);
++
++out:
++	/* primary controller unmasking */
++	chip->unmask(irq);
++}
++
++void __init ftpci100_int_cascade_irq(unsigned int nr, unsigned int irq)
++{
++	if (nr >= MAX_FTPCI100_NR)
++		BUG();
++
++	if (set_irq_data(irq, &ftpci100_data[nr]) != 0)
++		BUG();
++
++	set_irq_chained_handler(irq, ftpci100_int_handle_cascade_irq);
++}
++
++void __init ftpci100_int_init(unsigned int nr, unsigned int irq_start)
++{
++	int i;
++
++	if (nr >= MAX_FTPCI100_NR)
++		BUG();
++
++	ftpci100_data[nr].irq_offset = irq_start;
++	ftpci100_data[nr].busnr = nr;
++
++	for (i = irq_start; i < ftpci100_data[nr].irq_offset + 4; i++) {
++		set_irq_chip(i ,&ftpci100_int_chip);
++		set_irq_chip_data(i, &ftpci100_data[nr]);
++		set_irq_handler(i, handle_level_irq);
++		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
++	}
++}
++#endif
+diff --git a/arch/arm/mach-faraday/ftpmu010.c b/arch/arm/mach-faraday/ftpmu010.c
+new file mode 100644
+index 00000000..fbd738cb
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftpmu010.c
+@@ -0,0 +1,296 @@
++/*
++ *  linux/arch/arm/mach-faraday/ftpmu010.c
++ *
++ *  Faraday FTPMU010 Power Management Unit
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++
++#include <linux/clkdev.h>
++#include <asm/io.h>
++
++#include <mach/ftpmu010.h>
++
++#include "clock.h"
++
++struct ftpmu010_clk_params {
++	int	mult;
++	int	div;
++};
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static unsigned int __ftpmu010_in_turbo_mode(void __iomem *base)
++{
++	unsigned int pmode = readl(base + FTPMU010_OFFSET_PMODE);
++
++	return pmode & FTPMU010_PMODE_TURBO;
++}
++
++static unsigned int __ftpmu010_get_divahbclk(void __iomem *base)
++{
++	static const unsigned int bits2div[] = { 2, 3, 4, 6, 8, };
++	unsigned int pmode = readl(base + FTPMU010_OFFSET_PMODE);
++	unsigned int divbits = FTPMU010_PMODE_DIVAHBCLK(pmode);
++
++	if (divbits > 4) {
++		printk(KERN_ERR "unknown DIVAHBCLK %d\n", divbits);
++		return 8;
++	}
++
++	return bits2div[divbits];
++}
++
++static unsigned long __ftpmu010_get_pll1_freq(void __iomem *base, unsigned long rate)
++{
++	unsigned int pdllcr0 = readl(base + FTPMU010_OFFSET_PDLLCR0);
++
++	if (!(pdllcr0 & FTPMU010_PDLLCR0_PLL1DIS)) {
++		unsigned long mul = FTPMU010_PDLLCR0_PLL1NS(pdllcr0);
++
++		rate *= mul;
++	}
++
++	return rate;
++}
++
++static unsigned long __ftpmu010_get_hclk(void __iomem *base, unsigned long rate)
++{
++	unsigned int div = __ftpmu010_get_divahbclk(base);
++
++	return __ftpmu010_get_pll1_freq(base, rate) / div;
++}
++
++static unsigned long __ftpmu010_get_cpuclk(void __iomem *base, unsigned long rate)
++{
++	if (__ftpmu010_in_turbo_mode(base))
++		return __ftpmu010_get_pll1_freq(base, rate);
++
++	return __ftpmu010_get_hclk(base, rate);
++}
++
++static int __ftpmu010_enable_32768hz_osc(void __iomem *base)
++{
++	unsigned int oscc;
++
++	/* enable the 32768Hz oscillator */
++	oscc = readl(base + FTPMU010_OFFSET_OSCC);
++	oscc &= ~(FTPMU010_OSCC_OSCL_OFF | FTPMU010_OSCC_OSCL_TRI);
++	writel(oscc, base + FTPMU010_OFFSET_OSCC);
++
++	/* wait until ready */
++	oscc = readl(base + FTPMU010_OFFSET_OSCC);
++	while (!(oscc & FTPMU010_OSCC_OSCL_STABLE)) {
++		udelay(1);
++		oscc = readl(base + FTPMU010_OFFSET_OSCC);
++	}
++
++	/* select 32768Hz oscillator */
++	oscc |= FTPMU010_OSCC_OSCL_RTCLSEL;
++	writel(oscc, base + FTPMU010_OFFSET_OSCC);
++
++	return 0;
++}
++
++static int __ftpmu010_disable_32768hz_osc(void __iomem *base)
++{
++	unsigned int oscc;
++
++	/* deselect 32768Hz oscillator */
++	oscc = readl(base + FTPMU010_OFFSET_OSCC);
++	oscc &= ~FTPMU010_OSCC_OSCL_RTCLSEL;
++	writel(oscc, base + FTPMU010_OFFSET_OSCC);
++
++	/* disable the 32768Hz oscillator */
++	oscc = readl(base + FTPMU010_OFFSET_OSCC);
++	oscc |= FTPMU010_OSCC_OSCL_OFF | FTPMU010_OSCC_OSCL_TRI;
++	writel(oscc, base + FTPMU010_OFFSET_OSCC);
++
++	return 0;
++}
++
++/******************************************************************************
++ * struct clk functions
++ *****************************************************************************/
++
++static unsigned long ftpmu010_get_scaled_clk(struct clk *clk)
++{
++	struct ftpmu010_clk_params *params = clk->params;
++	int mult = params->mult;
++	int div = params->div;
++	unsigned long rate;
++
++	rate = __clk_get_rate(clk->parent);
++	clk->rate = rate * mult / div;
++	return clk->rate;
++}
++
++static unsigned long ftpmu010_get_cpuclk(struct clk *clk)
++{
++	unsigned long rate;
++
++	rate = __clk_get_rate(clk->parent);
++	clk->rate = __ftpmu010_get_cpuclk(clk->base, rate);
++	return clk->rate;
++}
++
++static unsigned long ftpmu010_get_hclk(struct clk *clk)
++{
++	unsigned long rate;
++
++	rate = __clk_get_rate(clk->parent);
++	clk->rate = __ftpmu010_get_hclk(clk->base, rate);
++	return clk->rate;
++}
++
++static int ftpmu010_32768hz_osc_mode(struct clk *clk, int on)
++{
++	if (on)
++		return __ftpmu010_enable_32768hz_osc(clk->base);
++	else
++		return __ftpmu010_disable_32768hz_osc(clk->base);
++}
++
++/******************************************************************************
++ * clocks
++ *****************************************************************************/
++struct clk ftpmu010_main_clk;
++
++struct clk ftpmu010_cpuclk = {
++	.parent		= &ftpmu010_main_clk,
++	.get_rate	= ftpmu010_get_cpuclk,
++};
++
++struct clk ftpmu010_hclk = {
++	.parent		= &ftpmu010_main_clk,
++	.get_rate	= ftpmu010_get_hclk,
++};
++
++static struct ftpmu010_clk_params ftpmu010_pclk_params = {
++	.mult	= 1,
++	.div	= 2,
++};
++
++struct clk ftpmu010_pclk = {
++	.parent		= &ftpmu010_hclk,
++	.get_rate	= ftpmu010_get_scaled_clk,
++	.params		= &ftpmu010_pclk_params,
++};
++
++static struct ftpmu010_clk_params ftpmu010_pll2_params = {
++	.mult	= 13,
++	.div	= 1,
++};
++
++struct clk ftpmu010_pll2_clk = {
++	.parent		= &ftpmu010_main_clk,
++	.get_rate	= ftpmu010_get_scaled_clk,
++	.params		= &ftpmu010_pll2_params,
++};
++
++struct clk ftpmu010_irda_clk = {
++	.parent		= &ftpmu010_pll2_clk,
++};
++
++static struct ftpmu010_clk_params ftpmu010_pll3_params = {
++	.mult	= 40,
++	.div	= 1,
++};
++
++struct clk ftpmu010_pll3_clk = {
++	.parent		= &ftpmu010_main_clk,
++	.get_rate	= ftpmu010_get_scaled_clk,
++	.params		= &ftpmu010_pll3_params,
++};
++
++static struct ftpmu010_clk_params ftpmu010_ssp_params = {
++	.mult	= 1,
++	.div	= 6,
++};
++
++struct clk ftpmu010_ssp_clk = {
++	.parent		= &ftpmu010_pll3_clk,
++	.get_rate	= ftpmu010_get_scaled_clk,
++	.params		= &ftpmu010_ssp_params,
++};
++
++static struct ftpmu010_clk_params ftpmu010_i2s_params = {
++	.mult	= 1,
++	.div	= 12,
++};
++
++struct clk ftpmu010_i2s_clk = {
++	.parent		= &ftpmu010_pll3_clk,
++	.get_rate	= ftpmu010_get_scaled_clk,
++	.params		= &ftpmu010_i2s_params,
++};
++
++static struct ftpmu010_clk_params ftpmu010_ac97_params1 = {
++	.mult	= 1,
++	.div	= 3,
++};
++
++struct clk ftpmu010_ac97_clk1 = {
++	.parent		= &ftpmu010_pll3_clk,
++	.get_rate	= ftpmu010_get_scaled_clk,
++	.params		= &ftpmu010_ac97_params1,
++};
++
++static struct ftpmu010_clk_params ftpmu010_ac97_params2 = {
++	.mult	= 1,
++	.div	= 6,
++};
++
++struct clk ftpmu010_ac97_clk2 = {
++	.parent		= &ftpmu010_pll3_clk,
++	.get_rate	= ftpmu010_get_scaled_clk,
++	.params		= &ftpmu010_ac97_params2,
++};
++
++static struct ftpmu010_clk_params ftpmu010_uart_params = {
++	.mult	= 1,
++	.div	= 8,
++};
++
++struct clk ftpmu010_uart_clk = {
++	.parent		= &ftpmu010_pll3_clk,
++	.get_rate	= ftpmu010_get_scaled_clk,
++	.params		= &ftpmu010_uart_params,
++};
++
++struct clk ftpmu010_32768hz_clk = {
++	.rate	= 32768,
++	.mode	= ftpmu010_32768hz_osc_mode,
++};
++
++/******************************************************************************
++ * initial functions
++ *****************************************************************************/
++void ftpmu010_init(void __iomem *base)
++{
++	ftpmu010_cpuclk.base		= base;
++	ftpmu010_hclk.base		= base;
++	ftpmu010_pclk.base		= base;
++	ftpmu010_32768hz_clk.base	= base;
++}
+diff --git a/arch/arm/mach-faraday/ftpwmtmr010.c b/arch/arm/mach-faraday/ftpwmtmr010.c
+new file mode 100644
+index 00000000..b215166a
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftpwmtmr010.c
+@@ -0,0 +1,244 @@
++/*
++ *  linux/arch/arm/mach-faraday/ftpwmtmr010.c
++ *
++ *  Faraday FTPWMTMR010 Timer
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <asm/io.h>
++#include <asm/mach/irq.h>
++
++#include <mach/ftpwmtmr010.h>
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static inline void ftpwmtmr010_clear_int(void __iomem *base, unsigned int id)
++{
++	writel(1 << id, base + FTPWMTMR010_OFFSET_INTSTAT);
++}
++
++static inline void ftpwmtmr010_write_timer(void __iomem *base, unsigned int id,
++		unsigned int reg, unsigned int value)
++{
++	void __iomem *addr = base + FTPWMTMR010_OFFSET_TIMER(id + 1) + reg;
++	writel(value, addr);
++}
++
++static inline unsigned int ftpwmtmr010_read_timer(void __iomem *base,
++		unsigned int id, unsigned int reg)
++{
++	void __iomem *addr = base + FTPWMTMR010_OFFSET_TIMER(id + 1) + reg;
++	return readl(addr);
++}
++
++static void ftpwmtmr010_enable_noirq(void __iomem *base, unsigned int id)
++{
++	unsigned int cr;
++
++	cr = FTPWMTMR010_CTRL_START | FTPWMTMR010_CTRL_AUTO;
++
++	ftpwmtmr010_write_timer(base, id, FTPWMTMR010_OFFSET_CTRL, cr);
++}
++
++static void ftpwmtmr010_disable(void __iomem *base, unsigned int id)
++{
++	ftpwmtmr010_write_timer(base, id, FTPWMTMR010_OFFSET_CTRL, 0);
++}
++
++static unsigned int ftpwmtmr010_get_counter(void __iomem *base, unsigned int id)
++{
++	return ftpwmtmr010_read_timer(base, id, FTPWMTMR010_OFFSET_CNT);
++}
++
++static void ftpwmtmr010_set_reload(void __iomem *base, unsigned int id,
++		unsigned int value)
++{
++	unsigned int cr;
++
++	ftpwmtmr010_write_timer(base, id, FTPWMTMR010_OFFSET_LOAD, value);
++
++	cr = ftpwmtmr010_read_timer(base, id, FTPWMTMR010_OFFSET_CTRL);
++	cr |= FTPWMTMR010_CTRL_UPDATE;
++	ftpwmtmr010_write_timer(base, id, FTPWMTMR010_OFFSET_CTRL, cr);
++}
++
++static void ftpwmtmr010_set_cmp(void __iomem *base, unsigned int id, unsigned int value)
++{
++	unsigned int cr;
++
++	ftpwmtmr010_write_timer(base, id, FTPWMTMR010_OFFSET_CMP, value);
++
++	cr = ftpwmtmr010_read_timer(base, id, FTPWMTMR010_OFFSET_CTRL);
++	cr |= FTPWMTMR010_CTRL_UPDATE;
++	ftpwmtmr010_write_timer(base, id, FTPWMTMR010_OFFSET_CTRL, cr);
++}
++
++/******************************************************************************
++ * clockevent functions
++ *****************************************************************************/
++static int ftpwmtmr010_set_next_event(unsigned long clc, struct clock_event_device *ce)
++{
++	struct ftpwmtmr010_clockevent *ftpwmtmr010;
++
++	ftpwmtmr010 = container_of(ce, struct ftpwmtmr010_clockevent, clockevent);
++
++	ftpwmtmr010_set_reload(ftpwmtmr010->base, ftpwmtmr010->id, clc);
++
++	return 0;
++}
++
++static void ftpwmtmr010_set_mode(enum clock_event_mode mode, struct clock_event_device *ce)
++{
++	struct ftpwmtmr010_clockevent *ftpwmtmr010;
++	unsigned int cr;
++
++	ftpwmtmr010 = container_of(ce, struct ftpwmtmr010_clockevent, clockevent);
++
++	switch (mode) {
++	case CLOCK_EVT_MODE_PERIODIC:
++		ftpwmtmr010_set_reload(ftpwmtmr010->base, ftpwmtmr010->id,
++				ftpwmtmr010->reload);
++
++		cr = FTPWMTMR010_CTRL_START
++		   | FTPWMTMR010_CTRL_AUTO
++		   | FTPWMTMR010_CTRL_INT_EN;
++
++		break;
++
++	case CLOCK_EVT_MODE_RESUME:
++		cr = ftpwmtmr010_read_timer(ftpwmtmr010->base, ftpwmtmr010->id,
++				FTPWMTMR010_OFFSET_CTRL);
++
++		cr |= FTPWMTMR010_CTRL_START;
++
++		break;
++
++	case CLOCK_EVT_MODE_ONESHOT:
++		cr = FTPWMTMR010_CTRL_START
++		   | FTPWMTMR010_CTRL_INT_EN;
++
++		break;
++
++	case CLOCK_EVT_MODE_UNUSED:
++	case CLOCK_EVT_MODE_SHUTDOWN:
++	default:
++		cr = ftpwmtmr010_read_timer(ftpwmtmr010->base, ftpwmtmr010->id,
++				FTPWMTMR010_OFFSET_CTRL);
++
++		cr &= ~FTPWMTMR010_CTRL_START;
++
++		break;
++	}
++
++	ftpwmtmr010_write_timer(ftpwmtmr010->base, ftpwmtmr010->id,
++			FTPWMTMR010_OFFSET_CTRL, cr);
++}
++
++static irqreturn_t ftpwmtmr010_clockevent_interrupt(int irq, void *dev_id)
++{
++	struct ftpwmtmr010_clockevent *ftpwmtmr010 = dev_id;
++	struct clock_event_device *ce = &ftpwmtmr010->clockevent;
++
++	ftpwmtmr010_clear_int(ftpwmtmr010->base, ftpwmtmr010->id);
++	ce->event_handler(ce);
++	return IRQ_HANDLED;
++}
++
++void __init ftpwmtmr010_clockevent_init(struct ftpwmtmr010_clockevent *ftpwmtmr010)
++{
++	struct clock_event_device *ce = &ftpwmtmr010->clockevent;
++	struct irqaction *action = &ftpwmtmr010->irqaction;
++
++	if (!ftpwmtmr010->base || ftpwmtmr010->id >= 8)
++		BUG();
++
++	/* initialize to a known state */
++	ftpwmtmr010_disable(ftpwmtmr010->base, ftpwmtmr010->id);
++	ftpwmtmr010_set_cmp(ftpwmtmr010->base, ftpwmtmr010->id, 0);
++
++	/* setup reload value for periodic clockevents */
++	ftpwmtmr010->reload	= ftpwmtmr010->freq / HZ;
++
++	/* Make irqs happen for the system timer */
++	action->name		= ce->name;
++	action->handler		= ftpwmtmr010_clockevent_interrupt;
++	action->flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
++	action->dev_id		= ftpwmtmr010;
++
++	setup_irq(ce->irq, action);
++
++	/* setup struct clock_event_device */
++	ce->features		= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
++	ce->shift		= 32;
++	ce->rating		= 200;
++#if 0
++	ce->cpumask		= cpu_all_mask,
++#else
++	ce->cpumask		= cpumask_of(0),
++#endif
++
++	ce->mult		= div_sc(ftpwmtmr010->freq, NSEC_PER_SEC, ce->shift);
++	ce->max_delta_ns	= clockevent_delta2ns(0xffffffff, ce);
++	ce->min_delta_ns	= clockevent_delta2ns(0xf, ce);
++
++	ce->set_next_event	= ftpwmtmr010_set_next_event;
++	ce->set_mode		= ftpwmtmr010_set_mode;
++
++	clockevents_register_device(ce);
++}
++
++/******************************************************************************
++ * clocksource functions
++ *****************************************************************************/
++static cycle_t ftpwmtmr010_clocksource_read(struct clocksource *cs)
++{
++	struct ftpwmtmr010_clocksource *ftpwmtmr010;
++	cycle_t counter;
++
++	ftpwmtmr010 = container_of(cs, struct ftpwmtmr010_clocksource, clocksource);
++	counter = ftpwmtmr010_get_counter(ftpwmtmr010->base, ftpwmtmr010->id);
++	return ~counter;
++}
++
++void __init ftpwmtmr010_clocksource_init(struct ftpwmtmr010_clocksource *ftpwmtmr010)
++{
++	struct clocksource *cs = &ftpwmtmr010->clocksource;
++
++	if (!ftpwmtmr010->base || ftpwmtmr010->id >= 8)
++		BUG();
++
++	cs->rating	= 300;
++	cs->read	= ftpwmtmr010_clocksource_read;
++	cs->mask	= CLOCKSOURCE_MASK(32);
++	cs->shift	= 20;
++	cs->flags	= CLOCK_SOURCE_IS_CONTINUOUS;
++	cs->mult	= clocksource_hz2mult(ftpwmtmr010->freq, cs->shift);
++
++	/* setup as free-running clocksource */
++	ftpwmtmr010_disable(ftpwmtmr010->base, ftpwmtmr010->id);
++	ftpwmtmr010_set_cmp(ftpwmtmr010->base, ftpwmtmr010->id, 0);
++	ftpwmtmr010_set_reload(ftpwmtmr010->base, ftpwmtmr010->id, 0xffffffff);
++	ftpwmtmr010_enable_noirq(ftpwmtmr010->base, ftpwmtmr010->id);
++
++	clocksource_register(cs);
++}
+diff --git a/arch/arm/mach-faraday/ftscu010.c b/arch/arm/mach-faraday/ftscu010.c
+new file mode 100644
+index 00000000..a25087db
+--- /dev/null
++++ b/arch/arm/mach-faraday/ftscu010.c
+@@ -0,0 +1,1214 @@
++/*
++ *  linux/arch/arm/mach-faraday/ftscu010.c
++ *
++ *  Faraday FTSCU010 System Control Unit
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/clk.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/string.h>
++
++#include <linux/clkdev.h>
++#include <asm/io.h>
++
++#include <mach/ftscu010.h>
++
++#include "clock.h"
++
++struct ftscu010_clk_params {
++	int	mult;
++	int	div;
++};
++
++static void __iomem *ftscu010_base;
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static unsigned long __ftscu010_get_pll_freq(void __iomem *base, unsigned long rate)
++{
++	unsigned int pll1cr = readl(base + FTSCU010_OFFSET_PLL1CR);
++	unsigned long ns = FTSCU010_PLL1CR_PLL_NS(pll1cr);
++
++	return rate * ns / 2;
++}
++
++static unsigned long __ftscu010_get_mcpu_clk(void __iomem *base, unsigned long rate)
++{
++	unsigned int csr = readl(base + FTSCU010_OFFSET_CSR);
++	int select = FTSCU010_CSR_CPU_M_FCLK(csr);
++
++	switch(select) {
++	case 0:
++		return rate / 4;
++
++	case 1:
++		return rate / 2;
++
++	default:
++		return rate;
++	}
++}
++
++static unsigned int __ftscu010_get_extahb_clkdiv(void __iomem *base)
++{
++	unsigned int div = readl(base + FTSCU010_OFFSET_SCLK_CFG0);
++
++	div &= FTSCU010_SCLK_CFG0_EXTAHB_FQ_MASK;
++	div >>= FTSCU010_SCLK_CFG0_EXTAHB_FQ_SHIFT;
++	return div + 1;
++}
++
++static void __ftscu010_set_extahb_clkdiv(void __iomem *base, unsigned int div)
++{
++	unsigned int cfg0 = readl(base + FTSCU010_OFFSET_SCLK_CFG0);
++
++	div = div - 1;
++	div <<= FTSCU010_SCLK_CFG0_EXTAHB_FQ_SHIFT;
++	div &= FTSCU010_SCLK_CFG0_EXTAHB_FQ_MASK;
++
++	cfg0 &= ~FTSCU010_SCLK_CFG0_EXTAHB_FQ_MASK;
++	cfg0 |= div;
++	writel(cfg0, base + FTSCU010_OFFSET_SCLK_CFG0);
++}
++
++static int __ftscu010_calc_extahb_clkdiv(unsigned long pll_rate, unsigned long rate)
++{
++	unsigned int div;
++
++	div = pll_rate / 2 / rate;
++	if (div == 0)
++		return -EINVAL;
++
++	if (pll_rate / 2 / div > rate)
++		div++;
++
++	if (div > 0xf + 1)
++		return -EINVAL;
++
++	return div;
++}
++
++static unsigned long __ftscu010_calc_extahb_rate(unsigned long pll_rate, unsigned int div)
++{
++	return pll_rate / 2 / div;
++}
++
++	/*
++	 * Select external clock source (X_SSP_CLK) as SSP0 clock input, or it
++	 * will be (AHB clock * 2) by default.
++	 */
++static void __ftscu010_select_ssp0_extclk(void __iomem *base, int on)
++{
++	unsigned int sclk_cfg1;
++
++	sclk_cfg1 = ioread32(base + FTSCU010_OFFSET_SCLK_CFG1);
++	if (on)
++		sclk_cfg1 |= FTSCU010_SCLK_CFG1_SSP0_SEL;
++	else
++		sclk_cfg1 &= ~FTSCU010_SCLK_CFG1_SSP0_SEL;
++
++	iowrite32(sclk_cfg1, base+ FTSCU010_OFFSET_SCLK_CFG1);
++}
++
++/******************************************************************************
++ * struct clk functions
++ *****************************************************************************/
++
++static unsigned long ftscu010_get_scaled_clk(struct clk *clk)
++{
++	struct ftscu010_clk_params *params = clk->params;
++	int mult = params->mult;
++	int div = params->div;
++	unsigned long rate;
++
++	rate = __clk_get_rate(clk->parent);
++	clk->rate = rate * mult / div;
++	return clk->rate;
++}
++
++static unsigned long ftscu010_get_pll_clk(struct clk *clk)
++{
++	unsigned long rate;
++
++	rate = __clk_get_rate(clk->parent);
++	clk->rate = __ftscu010_get_pll_freq(clk->base, rate);
++	return clk->rate;
++}
++
++static unsigned long ftscu010_get_mcpu_clk(struct clk *clk)
++{
++	unsigned long rate;
++
++	rate = __clk_get_rate(clk->parent);
++	clk->rate = __ftscu010_get_mcpu_clk(clk->base, rate);
++	return clk->rate;
++}
++
++static int ftscu010_scpu_clk_mode(struct clk *clk, int on)
++{
++	unsigned int hclkgate = readl(clk->base + FTSCU010_OFFSET_HCLKGATE);
++
++	if (on)
++		hclkgate &= ~FTSCU010_HCLKGATE_CPU_S;
++	else
++		hclkgate |= FTSCU010_HCLKGATE_CPU_S;
++
++	writel(hclkgate, clk->base + FTSCU010_OFFSET_HCLKGATE);
++	return 0;
++}
++
++static unsigned long ftscu010_get_extahb_clk(struct clk *clk)
++{
++	unsigned long pll_rate = __clk_get_rate(clk->parent);
++	unsigned int div = __ftscu010_get_extahb_clkdiv(clk->base);
++
++	clk->rate = __ftscu010_calc_extahb_rate(pll_rate, div);
++	return clk->rate;
++}
++
++static int ftscu010_set_extahb_clk(struct clk *clk, unsigned long rate)
++{
++	unsigned long pll_rate = __clk_get_rate(clk->parent);
++	int div = __ftscu010_calc_extahb_clkdiv(pll_rate, rate);
++
++	if (div < 0)
++		return -EINVAL;
++
++	__ftscu010_set_extahb_clkdiv(clk->base, div);
++	clk->rate = __ftscu010_calc_extahb_rate(pll_rate, div);
++	printk(KERN_INFO "ftscu010: set extahb clk rate to %ld\n",
++		clk->rate);
++	return 0;
++}
++
++static int ftscu010_ssp0_extclk_mode(struct clk *clk, int on)
++{
++	__ftscu010_select_ssp0_extclk(clk->base, on);
++	return 0;
++}
++
++/******************************************************************************
++ * clocks
++ *****************************************************************************/
++struct clk ftscu010_main_clk;
++
++struct clk ftscu010_pll_clk = {
++	.parent		= &ftscu010_main_clk,
++	.get_rate	= ftscu010_get_pll_clk,
++};
++
++static struct ftscu010_clk_params ftscu010_dclk_params = {
++	.mult	= 1,
++	.div	= 2,
++};
++
++struct clk ftscu010_dclk = {
++	.parent		= &ftscu010_pll_clk,
++	.get_rate	= ftscu010_get_scaled_clk,
++	.params		= &ftscu010_dclk_params,
++};
++
++static struct ftscu010_clk_params ftscu010_mclk_params = {
++	.mult	= 1,
++	.div	= 3,
++};
++
++struct clk ftscu010_mclk = {
++	.parent		= &ftscu010_pll_clk,
++	.get_rate	= ftscu010_get_scaled_clk,
++	.params		= &ftscu010_mclk_params,
++};
++
++static struct ftscu010_clk_params ftscu010_hclk_params = {
++	.mult	= 1,
++	.div	= 4,
++};
++
++struct clk ftscu010_hclk = {
++	.parent		= &ftscu010_pll_clk,
++	.get_rate	= ftscu010_get_scaled_clk,
++	.params		= &ftscu010_hclk_params,
++};
++
++static struct ftscu010_clk_params ftscu010_pclk_params = {
++	.mult	= 1,
++	.div	= 8,
++};
++
++struct clk ftscu010_pclk = {
++	.parent		= &ftscu010_pll_clk,
++	.get_rate	= ftscu010_get_scaled_clk,
++	.params		= &ftscu010_pclk_params,
++};
++
++struct clk ftscu010_extahb_clk = {
++	.parent		= &ftscu010_pll_clk,
++	.get_rate	= ftscu010_get_extahb_clk,
++	.set_rate	= ftscu010_set_extahb_clk,
++};
++
++struct clk ftscu010_mcpu_clk = {
++	.parent		= &ftscu010_pll_clk,
++	.get_rate	= ftscu010_get_mcpu_clk,
++};
++
++struct clk ftscu010_scpu_clk = {
++	.parent		= &ftscu010_hclk,
++	.mode		= ftscu010_scpu_clk_mode,
++};
++
++struct clk ftscu010_ssp0_extclk = {
++	.rate	= 12288000,
++	.mode	= ftscu010_ssp0_extclk_mode,
++};
++
++struct clk ftscu010_tsc_clk = {
++	.parent		= &ftscu010_main_clk,
++};
++
++/******************************************************************************
++ * pin mux setup
++ *
++ * This shit is used to handle the brain-damaged pin mux design.
++ *****************************************************************************/
++struct ftscu010_pinmux_conf {
++	const char *name;
++	unsigned int set;
++};
++
++struct ftscu010_pinmux_fg {
++	const char *name;
++	unsigned int offset;
++	unsigned int mask;
++	struct ftscu010_pinmux_conf conf[4];
++};
++
++static struct ftscu010_pinmux_fg ftscu010_pinmux_fgs[] = {
++	{
++		.name	= "extahb",
++		.offset	= FTSCU010_OFFSET_MFPSR0,
++		.mask	= FTSCU010_MFPSR0_FGEXTAHB_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR0_FGEXTAHB_EXTAHB,
++			}, {
++				.name	= "peripherals",
++				.set	= FTSCU010_MFPSR0_FGEXTAHB_PERIPHERALS,
++			},
++		},
++	}, {
++		.name	= "sata",
++		.offset	= FTSCU010_OFFSET_MFPSR0,
++		.mask	= FTSCU010_MFPSR0_FGSATA_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR0_FGSATA_EXTAHB,
++			}, {
++				.name	= "sata",
++				.set	= FTSCU010_MFPSR0_FGSATA_SATA,
++			}, {
++				.name	= "extdma",
++				.set	= FTSCU010_MFPSR0_FGSATA_EXTDMA,
++			},
++		},
++	}, {
++		.name	= "isp",
++		.offset	= FTSCU010_OFFSET_MFPSR0,
++		.mask	= FTSCU010_MFPSR0_FGISP_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR0_FGISP_EXTAHB,
++			}, {
++				.name	= "gpio1",
++				.set	= FTSCU010_MFPSR0_FGISP_GPIO1,
++			}, {
++				.name	= "isp",
++				.set	= FTSCU010_MFPSR0_FGISP_ISP,
++			},
++		},
++	}, {
++		.name	= "ts",
++		.offset	= FTSCU010_OFFSET_MFPSR0,
++		.mask	= FTSCU010_MFPSR0_FGTS_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR0_FGTS_EXTAHB,
++			}, {
++				.name	= "gpio0",
++				.set	= FTSCU010_MFPSR0_FGTS_GPIO0,
++			}, {
++				.name	= "ts",
++				.set	= FTSCU010_MFPSR0_FGTS_TS,
++			},
++		}
++	}, {
++		.name	= "lcd",
++		.offset	= FTSCU010_OFFSET_MFPSR0,
++		.mask	= FTSCU010_MFPSR0_FGLCD_MASK,
++		.conf	= {
++			{
++				.name	= "lcd",
++				.set	= FTSCU010_MFPSR0_FGLCD_LCD,
++			}, {
++				.name	= "tv_mice",
++				.set	= FTSCU010_MFPSR0_FGLCD_TV_MICE,
++			}, {
++				.name	= "lcd_mice",
++				.set	= FTSCU010_MFPSR0_FGLCD_LCD_MICE,
++			},
++		},
++	}, {
++		.name	= "ebi",
++		.offset	= FTSCU010_OFFSET_MFPSR0,
++		.mask	= FTSCU010_MFPSR0_FGEBI_MASK,
++		.conf	= {
++			{
++				.name	= "ebi",
++				.set	= FTSCU010_MFPSR0_FGEBI_EBI,
++			}, {
++				.name	= "ide",
++				.set	= FTSCU010_MFPSR0_FGEBI_IDE,
++			},
++		},
++	}, {
++		.name	= "uart1",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGUART1_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR1_FGUART1_EXTAHB,
++			}, {
++				.name	= "gpio0",
++				.set	= FTSCU010_MFPSR1_FGUART1_GPIO0,
++			}, {
++				.name	= "uart1",
++				.set	= FTSCU010_MFPSR1_FGUART1_UART1,
++			},
++		},
++	}, {
++		.name	= "uart2",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGUART2_MASK,
++		.conf	= {
++			{
++				.name	= "gpio1",
++				.set	= FTSCU010_MFPSR1_FGUART2_GPIO1,
++			}, {
++				.name	= "pwm",
++				.set	= FTSCU010_MFPSR1_FGUART2_PWM,
++			}, {
++				.name	= "uart2",
++				.set	= FTSCU010_MFPSR1_FGUART2_UART2,
++			},
++		},
++	}, {
++		.name	= "uart3",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGUART3_MASK,
++		.conf	= {
++			{
++				.name	= "gpio1",
++				.set	= FTSCU010_MFPSR1_FGUART3_GPIO1,
++			}, {
++				.name	= "uart3",
++				.set	= FTSCU010_MFPSR1_FGUART3_UART3,
++			},
++		},
++	}, {
++		.name	= "ssp0",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGSSP0_MASK,
++		.conf	= {
++			{
++				.name	= "ssp0",
++				.set	= FTSCU010_MFPSR1_FGSSP0_SSP0,
++			}, {
++				.name	= "sata",
++				.set	= FTSCU010_MFPSR1_FGSSP0_SATA,
++			}, {
++				.name	= "sice",
++				.set	= FTSCU010_MFPSR1_FGSSP0_SICE,
++			},
++		},
++	}, {
++		.name	= "ssp1",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGSSP1_MASK,
++		.conf	= {
++			{
++				.name	= "gpio1",
++				.set	= FTSCU010_MFPSR1_FGSSP1_GPIO1,
++			}, {
++				.name	= "i2c1",
++				.set	= FTSCU010_MFPSR1_FGSSP1_I2C1,
++			}, {
++				.name	= "ssp1",
++				.set	= FTSCU010_MFPSR1_FGSSP1_SSP1,
++			},
++		},
++	}, {
++		.name	= "gmac",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGGMAC_MASK,
++		.conf	= {
++			{
++				.name	= "gmac",
++				.set	= FTSCU010_MFPSR1_FGGMAC_GMAC,
++			}, {
++				.name	= "mcp_ice",
++				.set	= FTSCU010_MFPSR1_FGGMAC_MCP_ICE,
++			},
++		},
++	}, {
++		.name	= "pwm0",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGPWM0_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR1_FGPWM0_EXTAHB,
++			}, {
++				.name	= "pwm",
++				.set	= FTSCU010_MFPSR1_FGPWM0_PWM,
++			}, {
++				.name	= "extdma",
++				.set	= FTSCU010_MFPSR1_FGPWM0_EXTDMA,
++			},
++		},
++	}, {
++		.name	= "pwm1",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGPWM1_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR1_FGPWM1_EXTAHB,
++			}, {
++				.name	= "gpio1",
++				.set	= FTSCU010_MFPSR1_FGPWM1_GPIO1,
++			}, {
++				.name	= "pwm",
++				.set	= FTSCU010_MFPSR1_FGPWM1_PWM,
++			},
++		},
++	}, {
++		.name	= "i2c1",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGI2C1_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR1_FGI2C1_EXTAHB,
++			}, {
++				.name	= "gpio1",
++				.set	= FTSCU010_MFPSR1_FGI2C1_GPIO1,
++			}, {
++				.name	= "i2c1",
++				.set	= FTSCU010_MFPSR1_FGI2C1_I2C1,
++			},
++		},
++	}, {
++		.name	= "gpio0",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGGPIO0_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR1_FGGPIO0_EXTAHB,
++			}, {
++				.name	= "gpio0",
++				.set	= FTSCU010_MFPSR1_FGGPIO0_GPIO0,
++			}, {
++				.name	= "extdma",
++				.set	= FTSCU010_MFPSR1_FGGPIO0_EXTDMA,
++			},
++		},
++	}, {
++		.name	= "kbc",
++		.offset	= FTSCU010_OFFSET_MFPSR1,
++		.mask	= FTSCU010_MFPSR1_FGKBC_MASK,
++		.conf	= {
++			{
++				.name	= "extahb",
++				.set	= FTSCU010_MFPSR1_FGKBC_EXTAHB,
++			}, {
++				.name	= "gpio0",
++				.set	= FTSCU010_MFPSR1_FGKBC_GPIO0,
++			}, {
++				.name	= "kbc",
++				.set	= FTSCU010_MFPSR1_FGKBC_KBC,
++			},
++		},
++	},
++};
++
++static struct ftscu010_pinmux_fg *ftscu010_pinmux_find_fg(const char *name)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(ftscu010_pinmux_fgs); i++) {
++		struct ftscu010_pinmux_fg *p;
++
++		p = &ftscu010_pinmux_fgs[i];
++		if (!p->name)
++			break;
++		if (!strcmp(p->name, name))
++			return p;
++	}
++
++	return NULL;
++}
++
++static struct ftscu010_pinmux_conf *ftscu010_pinmux_find_conf(
++		struct ftscu010_pinmux_fg *fg, const char *name)
++{
++	int i;
++
++	for (i = 0; i < 4; i++) {
++		struct ftscu010_pinmux_conf *p;
++
++		p = &fg->conf[i];
++		if (!p->name)
++			break;
++		if (!strcmp(p->name, name))
++			return p;
++	}
++
++	return NULL;
++}
++
++static void ftscu010_pinmux_set(struct ftscu010_pinmux_fg *fg,
++		struct ftscu010_pinmux_conf *conf)
++{
++	unsigned int reg;
++
++	reg = readl(ftscu010_base + fg->offset);
++	reg &= ~fg->mask;
++	reg |= conf->set;
++	writel(reg, ftscu010_base + fg->offset);
++}
++
++int ftscu010_pinmux_setup(const char *fgname, const char *select)
++{
++	struct ftscu010_pinmux_fg *fg;
++	struct ftscu010_pinmux_conf *conf;
++
++	fg = ftscu010_pinmux_find_fg(fgname);
++	if (!fg) {
++		printk(KERN_ERR "%s: invalid function group %s\n",
++			__func__, fgname);
++		return -EINVAL;
++	}
++
++	conf = ftscu010_pinmux_find_conf(fg, select);
++	if (!conf) {
++		printk(KERN_ERR
++			"%s: invalid selection %s for function group %s\n",
++			__func__, select, fgname);
++		return -EINVAL;
++	}
++
++	ftscu010_pinmux_set(fg, conf);
++	return 0;
++}
++
++/******************************************************************************
++ * DMA configuation
++ *****************************************************************************/
++struct ftscu010_dma_conf_field {
++	unsigned int offset;
++	unsigned int shift;
++	unsigned int mask;
++};
++
++struct ftscu010_dma_device_conf {
++	const char *name;
++	int req_id;
++	struct ftscu010_dma_conf_field handshake;
++	struct ftscu010_dma_conf_field select;
++};
++
++static struct ftscu010_dma_device_conf ftscu010_dma_device_conf[] = {
++	{
++		.name	= "uart0tx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_UART0TX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART0TX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART0TX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART0TX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART0TX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "uart0rx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_UART0RX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART0RX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART0RX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART0RX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART0RX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "uart1tx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_UART1TX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART1TX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART1TX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART1TX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART1TX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "uart1rx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_UART1RX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART1RX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART1RX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART1RX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART1RX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "uart2tx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_UART2TX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART2TX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART2TX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART2TX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART2TX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "uart2rx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_UART2RX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART2RX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART2RX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG0,
++			.mask	= FTSCU010_DMA_ACK_CFG0_UART2RX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG0_UART2RX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "uart3tx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_UART3TX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG1,
++			.mask	= FTSCU010_DMA_ACK_CFG1_UART3TX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG1_UART3TX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG1,
++			.mask	= FTSCU010_DMA_ACK_CFG1_UART3TX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG1_UART3TX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "uart3rx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_UART3RX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG1,
++			.mask	= FTSCU010_DMA_ACK_CFG1_UART3RX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG1_UART3RX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG1,
++			.mask	= FTSCU010_DMA_ACK_CFG1_UART3RX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG1_UART3RX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "irda",
++		.req_id	= FTSCU010_DMA_REQ_CFG_IRDA,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG1,
++			.mask	= FTSCU010_DMA_ACK_CFG1_IRDA_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG1_IRDA_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG1,
++			.mask	= FTSCU010_DMA_ACK_CFG1_IRDA_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG1_IRDA_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "ssp0tx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_SSP0TX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_SSP0TX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_SSP0TX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_SSP0TX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_SSP0TX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "ssp0rx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_SSP0RX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_SSP0RX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_SSP0RX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_SSP0RX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_SSP0RX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "ssp1tx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_SSP1TX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_SSP1TX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_SSP1TX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_SSP1TX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_SSP1TX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "ssp1rx",
++		.req_id	= FTSCU010_DMA_REQ_CFG_SSP1RX,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_SSP1RX_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_SSP1RX_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_SSP1RX_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_SSP1RX_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "tsc",
++		.req_id	= FTSCU010_DMA_REQ_CFG_TSC,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_TSC_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_TSC_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_TSC_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_TSC_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "ts",
++		.req_id	= FTSCU010_DMA_REQ_CFG_TS,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_TS_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_TS_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG2,
++			.mask	= FTSCU010_DMA_ACK_CFG2_TS_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG2_TS_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "tmr1",
++		.req_id	= FTSCU010_DMA_REQ_CFG_TMR1,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR1_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR1_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR1_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR1_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "tmr2",
++		.req_id	= FTSCU010_DMA_REQ_CFG_TMR2,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR2_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR2_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR2_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR2_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "tmr3",
++		.req_id	= FTSCU010_DMA_REQ_CFG_TMR3,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR3_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR3_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR3_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR3_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "tmr5",
++		.req_id	= FTSCU010_DMA_REQ_CFG_TMR5,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR5_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR5_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR5_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR5_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "tmr6",
++		.req_id	= FTSCU010_DMA_REQ_CFG_TMR6,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR6_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR6_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR6_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR6_SELECT_SHIFT,
++		},
++	}, {
++		.name	= "tmr7",
++		.req_id	= FTSCU010_DMA_REQ_CFG_TMR7,
++		.handshake	= {
++			.offset = FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR7_DMAC_HS_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR7_DMAC_HS_SHIFT,
++		},
++		.select	= {
++			.offset	= FTSCU010_OFFSET_DMA_ACK_CFG3,
++			.mask	= FTSCU010_DMA_ACK_CFG3_TMR7_SELECT_MASK,
++			.shift	= FTSCU010_DMA_ACK_CFG3_TMR7_SELECT_SHIFT,
++		},
++	},
++};
++
++static struct ftscu010_dma_conf_field ftscu010_req_conf_dmac0[7] = {
++	{
++		.offset	= FTSCU010_OFFSET_DMAC0_REQ_CFG1,
++		.mask	= FTSCU010_DMAC0_REQ_CFG1_HS0_MASK,
++		.shift	= FTSCU010_DMAC0_REQ_CFG1_HS0_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC0_REQ_CFG1,
++		.mask	= FTSCU010_DMAC0_REQ_CFG1_HS1_MASK,
++		.shift	= FTSCU010_DMAC0_REQ_CFG1_HS1_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC0_REQ_CFG1,
++		.mask	= FTSCU010_DMAC0_REQ_CFG1_HS2_MASK,
++		.shift	= FTSCU010_DMAC0_REQ_CFG1_HS2_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC0_REQ_CFG0,
++		.mask	= FTSCU010_DMAC0_REQ_CFG0_HS3_MASK,
++		.shift	= FTSCU010_DMAC0_REQ_CFG0_HS3_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC0_REQ_CFG0,
++		.mask	= FTSCU010_DMAC0_REQ_CFG0_HS4_MASK,
++		.shift	= FTSCU010_DMAC0_REQ_CFG0_HS4_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC0_REQ_CFG0,
++		.mask	= FTSCU010_DMAC0_REQ_CFG0_HS5_MASK,
++		.shift	= FTSCU010_DMAC0_REQ_CFG0_HS5_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC0_REQ_CFG0,
++		.mask	= FTSCU010_DMAC0_REQ_CFG0_HS6_MASK,
++		.shift	= FTSCU010_DMAC0_REQ_CFG0_HS6_SHIFT,
++	},
++};
++
++static struct ftscu010_dma_conf_field ftscu010_req_conf_dmac1[7] = {
++	{
++		.offset	= FTSCU010_OFFSET_DMAC1_REQ_CFG1,
++		.mask	= FTSCU010_DMAC1_REQ_CFG1_HS0_MASK,
++		.shift	= FTSCU010_DMAC1_REQ_CFG1_HS0_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC1_REQ_CFG1,
++		.mask	= FTSCU010_DMAC1_REQ_CFG1_HS1_MASK,
++		.shift	= FTSCU010_DMAC1_REQ_CFG1_HS1_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC1_REQ_CFG1,
++		.mask	= FTSCU010_DMAC1_REQ_CFG1_HS2_MASK,
++		.shift	= FTSCU010_DMAC1_REQ_CFG1_HS2_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC1_REQ_CFG0,
++		.mask	= FTSCU010_DMAC1_REQ_CFG0_HS3_MASK,
++		.shift	= FTSCU010_DMAC1_REQ_CFG0_HS3_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC1_REQ_CFG0,
++		.mask	= FTSCU010_DMAC1_REQ_CFG0_HS4_MASK,
++		.shift	= FTSCU010_DMAC1_REQ_CFG0_HS4_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC1_REQ_CFG0,
++		.mask	= FTSCU010_DMAC1_REQ_CFG0_HS5_MASK,
++		.shift	= FTSCU010_DMAC1_REQ_CFG0_HS5_SHIFT,
++	}, {
++		.offset	= FTSCU010_OFFSET_DMAC1_REQ_CFG0,
++		.mask	= FTSCU010_DMAC1_REQ_CFG0_HS6_MASK,
++		.shift	= FTSCU010_DMAC1_REQ_CFG0_HS6_SHIFT,
++	},
++};
++
++static struct ftscu010_dma_device_conf *ftscu010_dma_device_conf_find(
++		const char *name)
++{
++	int i;
++
++	for (i = 0; i < ARRAY_SIZE(ftscu010_dma_device_conf); i++) {
++		struct ftscu010_dma_device_conf *p;
++
++		p = &ftscu010_dma_device_conf[i];
++		if (!strcmp(p->name, name))
++			return p;
++	}
++
++	return NULL;
++}
++
++static void ftscu010_dma_conf_field_set(void __iomem *base,
++		struct ftscu010_dma_conf_field *field, unsigned int val)
++{
++	unsigned int reg;
++
++	reg = readl(base + field->offset);
++	reg &= ~field->mask;
++	reg |= (val << field->shift) & field->mask;
++	writel(reg, base + field->offset);
++}
++
++static void ftscu010_dma_config_ack(void __iomem *base,
++		struct ftscu010_dma_device_conf *devconf, unsigned int select,
++		unsigned int handshake)
++{
++	ftscu010_dma_conf_field_set(base, &devconf->handshake, handshake);
++	ftscu010_dma_conf_field_set(base, &devconf->select, select);
++}
++
++
++static void ftscu010_dma_config_req_dmac0(void __iomem *base,
++		unsigned int req_id, unsigned int handshake)
++{
++	ftscu010_dma_conf_field_set(base, &ftscu010_req_conf_dmac0[handshake],
++		req_id);
++}
++
++static void ftscu010_dma_config_req_dmac1(void __iomem *base,
++		unsigned int req_id, unsigned int handshake)
++{
++	ftscu010_dma_conf_field_set(base, &ftscu010_req_conf_dmac1[handshake],
++		req_id);
++}
++static void ftscu010_dma_config_apbb(struct ftscu010_dma_device_conf *devconf)
++{
++	ftscu010_dma_config_ack(ftscu010_base, devconf,
++		FTSCU010_DMA_ACK_CFG_SELECT_APBB, 0);
++}
++
++static void ftscu010_dma_config_dmac0(struct ftscu010_dma_device_conf *devconf,
++		unsigned int handshake)
++{
++	ftscu010_dma_config_req_dmac0(ftscu010_base, devconf->req_id, handshake);
++	ftscu010_dma_config_ack(ftscu010_base, devconf,
++		FTSCU010_DMA_ACK_CFG_SELECT_DMAC0, handshake);
++}
++
++static void ftscu010_dma_config_dmac1(struct ftscu010_dma_device_conf *devconf,
++		unsigned int handshake)
++{
++	ftscu010_dma_config_req_dmac1(ftscu010_base, devconf->req_id, handshake);
++	ftscu010_dma_config_ack(ftscu010_base, devconf,
++		FTSCU010_DMA_ACK_CFG_SELECT_DMAC1, handshake);
++}
++
++static struct ftscu010_dma_device_conf *handshake_to_devconf[7];
++
++/*
++ * ftscu010_handshake_alloc - allocate DMAC handshake number for APB devices
++ * @name: connection name
++ *
++ * Returns handshake number or error code.
++ *
++ * Usually, APB devices use the internal DMA engine of APB bridge, but you
++ * can use DMA controller for performance critical situation.
++ */
++int ftscu010_handshake_alloc(const char *name)
++{
++	struct ftscu010_dma_device_conf *devconf;
++	int i;
++
++	devconf = ftscu010_dma_device_conf_find(name);
++	if (!devconf) {
++		printk(KERN_ERR "%s: %s not found\n", __func__, name);
++		return -EINVAL;
++	}
++
++	for (i = 0; i < 7; i++) {
++		if (handshake_to_devconf[i] == NULL)
++			break;
++	}
++
++	if (i == 7) {
++		printk(KERN_ERR "%s: no free handshake number available\n",
++			__func__);
++		return -ENODEV;
++	}
++
++	handshake_to_devconf[i] = devconf;
++	return i;
++}
++
++/**
++ * ftscu010_handshake_setup - setup allocated handshake number for a dmac
++ * @handshake: previously allocated handshake number
++ * @which: 0 for DMAC0, 1 for DMAC1
++ */
++int ftscu010_handshake_setup(unsigned int handshake, int which)
++{
++	struct ftscu010_dma_device_conf *devconf;
++
++	if (handshake >= 7) {
++		printk(KERN_ERR "%s: invalid handshake number %d\n",
++			__func__, handshake);
++		return -EINVAL;
++	}
++
++	devconf = handshake_to_devconf[handshake];
++	if (!devconf) {
++		printk(KERN_ERR "%s: handshake number %d was not allocated\n",
++			__func__, handshake);
++		return -EINVAL;
++	}
++
++	switch (which) {
++	case 0:
++		ftscu010_dma_config_dmac0(devconf, handshake);
++		return 0;
++	case 1:
++		ftscu010_dma_config_dmac1(devconf, handshake);
++		return 0;
++	default:
++		printk(KERN_ERR "%s: there are only 2 dmac on a369\n",
++			__func__);
++		return -EINVAL;
++	}
++}
++
++/**
++ * ftscu010_handshake_free - free DMAC handshake number
++ * @handshake: previously allocated handshake number
++ */
++int ftscu010_handshake_free(unsigned int handshake)
++{
++	struct ftscu010_dma_device_conf *devconf;
++
++	if (handshake >= 7) {
++		printk(KERN_ERR "%s: invalid handshake number %d\n",
++			__func__, handshake);
++		return -EINVAL;
++	}
++
++	devconf = handshake_to_devconf[handshake];
++	if (!devconf) {
++		printk(KERN_ERR "%s: handshake number %d is already free\n",
++			__func__, handshake);
++		return -EINVAL;
++	}
++
++	ftscu010_dma_config_apbb(devconf);
++	handshake_to_devconf[handshake] = NULL;
++	return 0;
++}
++
++/******************************************************************************
++ * initial functions
++ *****************************************************************************/
++void ftscu010_init(void __iomem *base)
++{
++	unsigned int reg;
++	unsigned int extcpu;
++
++	ftscu010_base	= base;
++
++	ftscu010_pll_clk.base		= base;
++	ftscu010_extahb_clk.base	= base;
++	ftscu010_mcpu_clk.base		= base;
++	ftscu010_scpu_clk.base		= base;
++	ftscu010_ssp0_extclk.base	= base;
++
++	/*
++	 * Enable external AHB
++	 *
++	 * By default, reset signal of external AHB is hold.
++	 * To use external AHB, we have to release it. But be careful!
++	 * The external AHB reset and slave CPU reset are connected together.
++	 * Since we are not using slave CPU and did not prepare program for it,
++	 * we must gate the slave CPU clock before doing reset.
++	 *
++	 * What the fuck!
++	 */
++	reg = readl(base + FTSCU010_OFFSET_HCLKGATE);
++	reg |= FTSCU010_HCLKGATE_CPU_S;
++	writel(reg, base + FTSCU010_OFFSET_HCLKGATE);
++
++	reg = readl(base + FTSCU010_OFFSET_GC);
++	reg |= FTSCU010_GC_CPU_S_EXTAHB_RSTN;
++	writel(reg, base + FTSCU010_OFFSET_GC);
++
++	/*
++	 * Setup external IRQ source
++	 *
++	 * If the external CPU is selected, enable the external IRQ source
++	 * or we cannot receive any interrupt.
++	 */
++	reg = readl(base + FTSCU010_OFFSET_EXT_CS);
++	extcpu = reg & FTSCU010_EXT_CS_CPU_MODE;
++	reg = readl(base + FTSCU010_OFFSET_GC);
++	reg &= ~FTSCU010_GC_EXT_IRQ_SRC;
++	reg |= (extcpu ? FTSCU010_GC_EXT_IRQ_SRC : 0);
++	writel(reg, base + FTSCU010_OFFSET_GC);
++}
+diff --git a/arch/arm/mach-faraday/fttmr010.c b/arch/arm/mach-faraday/fttmr010.c
+new file mode 100644
+index 00000000..4c54b008
+--- /dev/null
++++ b/arch/arm/mach-faraday/fttmr010.c
+@@ -0,0 +1,281 @@
++/*
++ *  linux/arch/arm/mach-faraday/fttmr010.c
++ *
++ *  Faraday FTTMR010 Timer
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <asm/io.h>
++#include <asm/mach/irq.h>
++
++#include <mach/fttmr010.h>
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static const unsigned int fttmr010_cr_mask[3] = {
++	FTTMR010_TM1_ENABLE | FTTMR010_TM1_CLOCK |
++	FTTMR010_TM1_OFENABLE | FTTMR010_TM1_UPDOWN,
++
++	FTTMR010_TM2_ENABLE | FTTMR010_TM2_CLOCK |
++	FTTMR010_TM2_OFENABLE | FTTMR010_TM2_UPDOWN,
++
++	FTTMR010_TM3_ENABLE | FTTMR010_TM3_CLOCK |
++	FTTMR010_TM3_OFENABLE | FTTMR010_TM3_UPDOWN,
++};
++
++/* we always use down counter */
++static const unsigned int fttmr010_cr_enable_flag[3] = {
++	FTTMR010_TM1_ENABLE | FTTMR010_TM1_OFENABLE,
++	FTTMR010_TM2_ENABLE | FTTMR010_TM2_OFENABLE,
++	FTTMR010_TM3_ENABLE | FTTMR010_TM3_OFENABLE,
++};
++
++static const unsigned int fttmr010_cr_enable_noirq_flag[3] = {
++	FTTMR010_TM1_ENABLE,
++	FTTMR010_TM2_ENABLE,
++	FTTMR010_TM3_ENABLE,
++};
++
++static void fttmr010_enable(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	cr |= fttmr010_cr_enable_flag[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static void fttmr010_enable_noirq(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	cr |= fttmr010_cr_enable_noirq_flag[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static void fttmr010_disable(void __iomem *base, unsigned int id)
++{
++	unsigned int cr = readl(base + FTTMR010_OFFSET_CR);
++
++	cr &= ~fttmr010_cr_mask[id];
++	writel(cr, base + FTTMR010_OFFSET_CR);
++}
++
++static const unsigned int fttmr010_irq_mask[3] = {
++	FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_OVERFLOW,
++	FTTMR010_TM2_MATCH1 | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_OVERFLOW,
++	FTTMR010_TM3_MATCH1 | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_OVERFLOW,
++};
++
++static void fttmr010_unmask_irq(void __iomem *base, unsigned int id)
++{
++	unsigned int mask;
++
++	mask = readl(base + FTTMR010_OFFSET_INTR_MASK);
++	mask &= ~fttmr010_irq_mask[id];
++	writel(mask, base + FTTMR010_OFFSET_INTR_MASK);
++}
++
++static void fttmr010_ack_irq(void __iomem *base, unsigned int id)
++{
++	unsigned int state;
++
++	state = readl(base + FTTMR010_OFFSET_INTR_STATE);
++	state &= ~fttmr010_irq_mask[id];
++	writel(state, base + FTTMR010_OFFSET_INTR_STATE);
++}
++
++static inline void fttmr010_write_timer(void __iomem *base, unsigned int id,
++		unsigned int reg, unsigned int value)
++{
++	void __iomem *addr = base + FTTMR010_OFFSET_TIMER(id) + reg;
++	writel (value, addr);
++}
++
++static inline unsigned int fttmr010_read_timer(void __iomem *base,
++		unsigned int id, unsigned int reg)
++{
++	void __iomem *addr = base + FTTMR010_OFFSET_TIMER(id) + reg;
++	return readl(addr);
++}
++
++static void fttmr010_set_counter(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_COUNTER, value);
++}
++
++static unsigned int fttmr010_get_counter(void __iomem *base, unsigned int id)
++{
++	return fttmr010_read_timer(base, id, FTTMR010_OFFSET_COUNTER);
++}
++
++static void fttmr010_set_reload(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_LOAD, value);
++}
++
++static void fttmr010_set_match1(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_MATCH1, value);
++}
++
++static void fttmr010_set_match2(void __iomem *base, unsigned int id, unsigned int value)
++{
++	fttmr010_write_timer(base, id, FTTMR010_OFFSET_MATCH2, value);
++}
++
++/******************************************************************************
++ * clockevent functions
++ *****************************************************************************/
++static int fttmr010_set_next_event(unsigned long clc, struct clock_event_device *ce)
++{
++	struct fttmr010_clockevent *fttmr010;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++
++	fttmr010_set_counter(fttmr010->base, fttmr010->id, clc);
++	return 0;
++}
++
++static void fttmr010_set_mode(enum clock_event_mode mode, struct clock_event_device *ce)
++{
++	struct fttmr010_clockevent *fttmr010;
++
++	fttmr010 = container_of(ce, struct fttmr010_clockevent, clockevent);
++
++	switch (mode) {
++	case CLOCK_EVT_MODE_PERIODIC:
++		fttmr010_set_reload(fttmr010->base, fttmr010->id, fttmr010->reload);
++		fttmr010_set_counter(fttmr010->base, fttmr010->id, fttmr010->reload);
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_RESUME:
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_ONESHOT:
++		fttmr010_set_reload(fttmr010->base, fttmr010->id, 0);
++		fttmr010_enable(fttmr010->base, fttmr010->id);
++		break;
++
++	case CLOCK_EVT_MODE_UNUSED:
++	case CLOCK_EVT_MODE_SHUTDOWN:
++	default:
++		fttmr010_disable(fttmr010->base, fttmr010->id);
++		break;
++	}
++}
++
++static irqreturn_t fttmr010_clockevent_interrupt(int irq, void *dev_id)
++{
++	struct fttmr010_clockevent *fttmr010 = dev_id;
++	struct clock_event_device *ce = &fttmr010->clockevent;
++
++	fttmr010_ack_irq(fttmr010->base, fttmr010->id);
++	ce->event_handler(ce);
++	return IRQ_HANDLED;
++}
++
++void __init fttmr010_clockevent_init(struct fttmr010_clockevent *fttmr010)
++{
++	struct clock_event_device *ce = &fttmr010->clockevent;
++	struct irqaction *action = &fttmr010->irqaction;
++
++	if (!fttmr010->base || fttmr010->id >= 3)
++		BUG();
++
++	/* initialize to a known state */
++	fttmr010_disable(fttmr010->base, fttmr010->id);
++	fttmr010_set_match1(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_match2(fttmr010->base, fttmr010->id, 0);
++	fttmr010_unmask_irq(fttmr010->base, fttmr010->id);
++
++	/* setup reload value for periodic clockevents */
++	fttmr010->reload	= fttmr010->freq / HZ;
++
++	/* Make irqs happen for the system timer */
++	action->name		= ce->name;
++	action->handler		= fttmr010_clockevent_interrupt;
++	action->flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
++	action->dev_id		= fttmr010;
++
++	setup_irq(ce->irq, action);
++
++	/* setup struct clock_event_device */
++	ce->features		= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
++	ce->shift		= 32;
++	ce->rating		= 200;
++#if 0
++	ce->cpumask		= cpu_all_mask,
++#else
++	ce->cpumask		= cpumask_of(0),
++#endif
++	ce->mult		= div_sc(fttmr010->freq, NSEC_PER_SEC, ce->shift);
++	ce->max_delta_ns	= clockevent_delta2ns(0xffffffff, ce);
++	ce->min_delta_ns	= clockevent_delta2ns(0xf, ce);
++
++	ce->set_next_event	= fttmr010_set_next_event;
++	ce->set_mode		= fttmr010_set_mode;
++
++	clockevents_register_device(ce);
++}
++
++/******************************************************************************
++ * clocksource functions
++ *****************************************************************************/
++static cycle_t fttmr010_clocksource_read(struct clocksource *cs)
++{
++	struct fttmr010_clocksource *fttmr010;
++	cycle_t counter;
++
++	fttmr010 = container_of(cs, struct fttmr010_clocksource, clocksource);
++	counter = fttmr010_get_counter(fttmr010->base, fttmr010->id);
++	return ~counter;
++}
++
++void __init fttmr010_clocksource_init(struct fttmr010_clocksource *fttmr010)
++{
++	struct clocksource *cs = &fttmr010->clocksource;
++
++	if (!fttmr010->base || fttmr010->id >= 3)
++		BUG();
++
++	cs->rating	= 300;
++	cs->read	= fttmr010_clocksource_read;
++	cs->mask	= CLOCKSOURCE_MASK(32);
++	cs->shift	= 20;
++	cs->flags	= CLOCK_SOURCE_IS_CONTINUOUS;
++	cs->mult	= clocksource_hz2mult(fttmr010->freq, cs->shift);
++
++	/* setup as free-running clocksource */
++	fttmr010_disable(fttmr010->base, fttmr010->id);
++	fttmr010_set_match1(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_match2(fttmr010->base, fttmr010->id, 0);
++	fttmr010_set_reload(fttmr010->base, fttmr010->id, 0xffffffff);
++	fttmr010_set_counter(fttmr010->base, fttmr010->id, 0xffffffff);
++	fttmr010_enable_noirq(fttmr010->base, fttmr010->id);
++
++	clocksource_register(cs);
++}
+diff --git a/arch/arm/mach-faraday/headsmp.S b/arch/arm/mach-faraday/headsmp.S
+new file mode 100644
+index 00000000..09b2aa91
+--- /dev/null
++++ b/arch/arm/mach-faraday/headsmp.S
+@@ -0,0 +1,40 @@
++/*
++ *  linux/arch/arm/mach-realview/headsmp.S
++ *
++ *  Copyright (c) 2003 ARM Limited
++ *  All Rights Reserved
++ *
++ * 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 <linux/linkage.h>
++#include <linux/init.h>
++
++	__INIT
++
++/*
++ * Realview specific entry point for secondary CPUs.  This provides
++ * a "holding pen" into which all secondary cores are held until we're
++ * ready for them to initialise.
++ */
++ENTRY(platform_secondary_startup)
++	mrc	p15, 0, r0, c0, c0, 5
++	and	r0, r0, #15
++	adr	r4, 1f
++	ldmia	r4, {r5, r6}
++	sub	r4, r4, r5
++	add	r6, r6, r4
++pen:	ldr	r7, [r6]
++	cmp	r7, r0
++	bne	pen
++
++	/*
++	 * we've been released from the holding pen: secondary_stack
++	 * should now contain the SVC stack for this core
++	 */
++	b	secondary_startup
++
++1:	.long	.
++	.long	pen_release
++ENDPROC(platform_secondary_startup)
+diff --git a/arch/arm/mach-faraday/hotplug.c b/arch/arm/mach-faraday/hotplug.c
+new file mode 100644
+index 00000000..ac1aed2a
+--- /dev/null
++++ b/arch/arm/mach-faraday/hotplug.c
+@@ -0,0 +1,127 @@
++/*
++ *  linux/arch/arm/mach-realview/hotplug.c
++ *
++ *  Copyright (C) 2002 ARM Ltd.
++ *  All Rights Reserved
++ *
++ * 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 <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/smp.h>
++
++#include <asm/cacheflush.h>
++
++extern volatile int pen_release;
++
++static inline void cpu_enter_lowpower(void)
++{
++	unsigned int v;
++
++	flush_cache_all();
++	asm volatile(
++	"	mcr	p15, 0, %1, c7, c5, 0\n"
++	"	mcr	p15, 0, %1, c7, c10, 4\n"
++	/*
++	 * Turn off coherency
++	 */
++	"	mrc	p15, 0, %0, c1, c0, 1\n"
++	"	bic	%0, %0, #0x20\n"
++	"	mcr	p15, 0, %0, c1, c0, 1\n"
++	"	mrc	p15, 0, %0, c1, c0, 0\n"
++	"	bic	%0, %0, %2\n"
++	"	mcr	p15, 0, %0, c1, c0, 0\n"
++	  : "=&r" (v)
++	  : "r" (0), "Ir" (CR_C)
++	  : "cc");
++}
++
++static inline void cpu_leave_lowpower(void)
++{
++	unsigned int v;
++
++	asm volatile(	"mrc	p15, 0, %0, c1, c0, 0\n"
++	"	orr	%0, %0, %1\n"
++	"	mcr	p15, 0, %0, c1, c0, 0\n"
++	"	mrc	p15, 0, %0, c1, c0, 1\n"
++	"	orr	%0, %0, #0x20\n"
++	"	mcr	p15, 0, %0, c1, c0, 1\n"
++	  : "=&r" (v)
++	  : "Ir" (CR_C)
++	  : "cc");
++}
++
++static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
++{
++	/*
++	 * there is no power-control hardware on this platform, so all
++	 * we can do is put the core into WFI; this is safe as the calling
++	 * code will have already disabled interrupts
++	 */
++	for (;;) {
++		/*
++		 * here's the WFI
++		 */
++		asm(".word	0xe320f003\n"
++		    :
++		    :
++		    : "memory", "cc");
++
++		if (pen_release == cpu_logical_map(cpu)) {
++			/*
++			 * OK, proper wakeup, we're done
++			 */
++			break;
++		}
++
++		/*
++		 * Getting here, means that we have come out of WFI without
++		 * having been woken up - this shouldn't happen
++		 *
++		 * Just note it happening - when we're woken, we can report
++		 * its occurrence.
++		 */
++		(*spurious)++;
++	}
++}
++
++int platform_cpu_kill(unsigned int cpu)
++{
++	return 1;
++}
++
++/*
++ * platform-specific code to shutdown a CPU
++ *
++ * Called with IRQs disabled
++ */
++void platform_cpu_die(unsigned int cpu)
++{
++	int spurious = 0;
++
++	/*
++	 * we're ready for shutdown now, so do it
++	 */
++	cpu_enter_lowpower();
++	platform_do_lowpower(cpu, &spurious);
++
++	/*
++	 * bring this CPU back into the world of cache
++	 * coherency, and then restore interrupts
++	 */
++	cpu_leave_lowpower();
++
++	if (spurious)
++		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
++}
++
++int platform_cpu_disable(unsigned int cpu)
++{
++	/*
++	 * we don't allow CPU 0 to be shutdown (it is still too special
++	 * e.g. clock tick interrupts)
++	 */
++	return cpu == 0 ? -EPERM : 0;
++}
+diff --git a/arch/arm/mach-faraday/include/mach/board-a320.h b/arch/arm/mach-faraday/include/mach/board-a320.h
+new file mode 100644
+index 00000000..4692c88e
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/board-a320.h
+@@ -0,0 +1,128 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/board-a320.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_BOARD_A320_H
++#define __MACH_BOARD_A320_H
++
++#ifdef CONFIG_PLATFORM_A320
++
++/*
++ * Base addresses
++ */
++
++#ifdef CONFIG_CPU_FMP626
++
++/* private memory region */
++#define PLATFORM_SCU_PA_BASE		0xe0000000
++#define PLATFORM_SCU_VA_BASE		0xf9100000
++
++#define PLATFORM_GIC_CPU_VA_BASE	(PLATFORM_SCU_VA_BASE + 0x100)
++#define PLATFORM_TWD_VA_BASE		(PLATFORM_SCU_VA_BASE + 0x600)
++
++#define PLATFORM_GIC_DIST_PA_BASE	0xe0001000
++#define PLATFORM_GIC_DIST_VA_BASE	0xf9101000
++
++#endif	/* CONFIG_CPU_FMP626 */
++
++/* A320 */
++#define A320_FTFLH010_0_PA_BASE		0x80440000
++#define A320_FTDMAC020_0_PA_BASE	0x90400000
++#define A320_FTAPBB020_0_PA_BASE	0x90500000
++#define A320_FTLCDC100_0_PA_BASE	0x90600000
++#define A320_FTMAC100_0_PA_BASE		0x90900000
++#define A320_FTNANDC020_0_PA_BASE	0x90c00000
++#define A320_FTSDC020_0_PA_BASE		0x92000000
++#define A320_FTPMU010_0_PA_BASE		0x98100000
++#define A320_FTUART010_0_PA_BASE	0x98200000
++#define A320_FTUART010_1_PA_BASE	0x98300000
++#define A320_FTTMR010_0_PA_BASE		0x98400000
++#define A320_FTWDT010_0_PA_BASE		0x98500000
++#define A320_FTRTC010_0_PA_BASE		0x98600000
++#define A320_FTGPIO010_0_PA_BASE	0x98700000
++#define A320_FTINTC010_0_PA_BASE	0x98800000
++#define A320_FTI2C010_0_PA_BASE		0x98a00000
++#define A320_FTCFC010_0_PA_BASE		0x98d00000
++#define A320_FTSDC010_0_PA_BASE		0x98e00000
++#define A320_FTSSP010_0_PA_BASE		0x99400000
++#define A320_FTUART010_2_PA_BASE	0x99600000
++
++#define A320_FTPMU010_0_VA_BASE		0xf9810000
++#define A320_FTUART010_0_VA_BASE	0xf9820000
++#define A320_FTUART010_1_VA_BASE	0xf9830000
++#define A320_FTTMR010_0_VA_BASE		0xf9840000
++#define A320_FTINTC010_0_VA_BASE	0xf9880000
++#define A320_FTUART010_2_VA_BASE	0xf9960000
++
++/* A321 */
++#define A321_FTPCI100_0_PA_BASE		0x90c00000
++#define A321_FTAPBB020_0_PA_BASE	0x90e00000
++#define A321_FTMAC100_0_PA_BASE		0x92000000
++#define A321_FTINTC010_0_PA_BASE	0xb0800000
++#define A321_FTKBC010_0_PA_BASE		0xb1300000
++#define A321_FTKBC010_1_PA_BASE		0xb1700000
++
++#define A321_FTPCI100_0_VA_BASE		0xf9cc0000
++#define A321_FTINTC010_0_VA_BASE	0xfb080000
++
++/* USB */
++#define A320_FUSB220_0_PA_BASE		0x90b00000
++#define A320_FOTG2XX_0_PA_BASE		0x92000000
++#define A320_FUSBH200_0_PA_BASE		0x92000000
++
++/* PCIMEM */
++#define PCIMEM_0_PA_BASE	0xa0000000
++#define PCIMEM_0_PA_LIMIT	0xafffffff
++#define PCIMEM_0_PA_SIZE	0x10000000
++#define PCIMEM_0_VA_BASE	0xe0000000
++#define PCIMEM_0_VA_LIMIT	0xefffffff
++#define PCIMEM_0_VA_SIZE	0x10000000
++#define PCIMEM_PA_BASE	PCIMEM_0_PA_BASE	/* used by ftpci100.c */
++#define PCIMEM_PA_LIMIT	PCIMEM_0_PA_LIMIT	/* used by ftpci100.c */
++#define PCIMEM_PA_SIZE	PCIMEM_0_PA_SIZE
++#define PCIMEM_VA_BASE	PCIMEM_0_VA_BASE
++#define PCIMEM_VA_LIMIT	PCIMEM_0_VA_LIMIT
++#define PCIMEM_VA_SIZE	PCIMEM_0_VA_SIZE
++
++/* PCIIO */
++#define PCIIO_0_PA_BASE		0x90c01000
++#define PCIIO_0_PA_LIMIT	0x90cfffff
++#define PCIIO_0_PA_SIZE		0x000ff000
++#define PCIIO_0_VA_BASE		0xf9d01000
++#define PCIIO_0_VA_LIMIT	0xf9dfffff
++#define PCIIO_0_VA_SIZE		0x000ff000
++#define PCIIO_PA_BASE	PCIIO_0_PA_BASE		/* used by ftpci100.c */
++#define PCIIO_PA_LIMIT	PCIIO_0_PA_LIMIT
++#define PCIIO_PA_SIZE	PCIIO_0_PA_SIZE
++#define PCIIO_VA_BASE	PCIIO_0_VA_BASE		/* used by ftpci100.c */
++#define PCIIO_VA_LIMIT	PCIIO_0_VA_LIMIT	/* used by ftpci100.c */
++#define PCIIO_VA_SIZE	PCIIO_0_VA_SIZE
++
++#define DEBUG_LL_FTUART010_PA_BASE	A320_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE	A320_FTUART010_0_VA_BASE
++
++/*
++ * The "Main CLK" Oscillator on the board which is used by the PLL to generate
++ * CPU/AHB/APB clocks.
++ */
++#define MAIN_CLK	3686400
++
++#endif	/* CONFIG_PLATFORM_A320 */
++
++#endif	/* __MACH_BOARD_A320_H */
+diff --git a/arch/arm/mach-faraday/include/mach/board-a369.h b/arch/arm/mach-faraday/include/mach/board-a369.h
+new file mode 100644
+index 00000000..15b3810e
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/board-a369.h
+@@ -0,0 +1,127 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/board-a369.h
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_BOARD_A369_H
++#define __MACH_BOARD_A369_H
++
++#ifdef CONFIG_PLATFORM_A369
++
++/*
++ * Base addresses
++ */
++
++#ifdef CONFIG_CPU_FMP626
++
++/* private memory region */
++#define PLATFORM_SCU_PA_BASE		0xe0000000
++#define PLATFORM_SCU_VA_BASE		0xf9100000
++
++#define PLATFORM_GIC_CPU_VA_BASE	(PLATFORM_SCU_VA_BASE + 0x100)
++#define PLATFORM_TWD_VA_BASE		(PLATFORM_SCU_VA_BASE + 0x600)
++
++#define PLATFORM_GIC_DIST_PA_BASE	0xe0001000
++#define PLATFORM_GIC_DIST_VA_BASE	0xf9101000
++
++#endif	/* CONFIG_CPU_FMP626 */
++
++#define A369_FTINTC020_0_PA_BASE	0x90100000
++#define A369_FTNANDC021_0_PA_BASE	0x90200000
++#define A369_FTDMAC020_0_PA_BASE	0x90300000
++#define A369_FTIDE020_0_PA_BASE		0x90400000
++#define A369_FTSDC010_0_PA_BASE		0x90500000
++#define A369_FTSDC010_1_PA_BASE		0x90600000
++#define A369_FTPCIE3914_0_PA_BASE	0x90700000
++#define A369_FUSBH200_0_PA_BASE		0x90800000
++#define A369_FOTG2XX_0_PA_BASE		0x90900000
++#define A369_FTSATA100_0_PA_BASE	0x90a00000
++#define A369_FTSATA110_0_PA_BASE	0x90b00000
++#define A369_FTGMAC100_0_PA_BASE	0x90c00000
++#define A369_FTAES020_0_PA_BASE		0x90d00000
++#define A369_FTAPBB020_0_PA_BASE	0x90f00000
++#define A369_FTSCU010_0_PA_BASE		0x92000000
++#define A369_FTRTC011_0_PA_BASE		0x92100000
++#define A369_FTWDT010_0_PA_BASE		0x92200000
++#define A369_FTPWMTMR010_0_PA_BASE	0x92300000
++#define A369_FTTSC010_0_PA_BASE		0x92400000
++#define A369_FTGPIO010_0_PA_BASE	0x92500000
++#define A369_FTGPIO010_1_PA_BASE	0x92600000
++#define A369_FTSSP010_0_PA_BASE		0x92700000
++#define A369_FTSSP010_1_PA_BASE		0x92800000
++#define A369_FTIIC010_0_PA_BASE		0x92900000
++#define A369_FTIIC010_1_PA_BASE		0x92a00000
++#define A369_FTUART010_0_PA_BASE	0x92b00000
++#define A369_FTUART010_1_PA_BASE	0x92c00000
++#define A369_FTUART010_2_PA_BASE	0x92d00000
++#define A369_FTUART010_3_PA_BASE	0x92e00000
++#define A369_FTKBC010_0_PA_BASE		0x92f00000
++#define A369_FTDDRII030_0_PA_BASE	0x93100000
++#define A369_FTAHBC020_0_PA_BASE	0x94000000
++#define A369_FTAHBC020_1_PA_BASE	0x94100000
++#define A369_FTAHBC020_2_PA_BASE	0x94200000
++#define A369_FTAHBB020_0_PA_BASE	0x94400000
++#define A369_FTAHBB020_1_PA_BASE	0x94500000
++#define A369_FTAHBB020_2_PA_BASE	0x94600000
++#define A369_FTAHBB020_3_PA_BASE	0x94700000
++#define A369_FTSMC020_0_PA_BASE		0x94800000
++#define A369_FTEBI020_0_PA_BASE		0x94900000
++#define A369_FTLCDC200_0_PA_BASE	0x94a00000
++#define A369_FTINTC020_1_PA_BASE	0x96000000
++#define A369_FTDMAC020_1_PA_BASE	0x96100000
++#define A369_FTMCP100_0_PA_BASE		0x96200000
++#define A369_FTMCP220_0_PA_BASE		0x96300000
++
++#define A369_FTINTC020_0_VA_BASE	0xf9010000
++#define A369_FTPCIE3914_0_VA_BASE	0xf9070000
++#define A369_FTSCU010_0_VA_BASE		0xf9200000
++#define A369_FTPWMTMR010_0_VA_BASE	0xf9230000
++#define A369_FTUART010_0_VA_BASE	0xf92b0000
++#define A369_FTUART010_1_VA_BASE	0xf92c0000
++#define A369_FTUART010_2_VA_BASE	0xf92d0000
++#define A369_FTUART010_3_VA_BASE	0xf92e0000
++#define A369_FTAHBB020_3_VA_BASE	0xf9470000
++
++/* PCIIO */
++#define PCIIO_FTPCIE3914_0_PA_BASE	0x60000000
++#define PCIIO_FTPCIE3914_0_PA_LIMIT	0x6fffffff
++#define PCIIO_FTPCIE3914_0_PA_SIZE	0x10000000
++#define PCIIO_FTPCIE3914_0_VA_BASE	0xf6000000
++#define PCIIO_FTPCIE3914_0_VA_LIMIT	0xf6000fff
++#define PCIIO_FTPCIE3914_0_VA_SIZE	0x00001000
++
++/* PCIMEM */
++#define PCIMEM_FTPCIE3914_0_PA_BASE	0x40000000
++#define PCIMEM_FTPCIE3914_0_PA_LIMIT	0x4fffffff
++#define PCIMEM_FTPCIE3914_0_PA_SIZE	0x10000000
++#define PCIMEM_FTPCIE3914_0_VA_BASE	0xf4000000
++#define PCIMEM_FTPCIE3914_0_VA_LIMIT	0xf4000fff
++#define PCIMEM_FTPCIE3914_0_VA_SIZE	0x00001000
++
++#define DEBUG_LL_FTUART010_PA_BASE	A369_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE	A369_FTUART010_0_VA_BASE
++
++/*
++ * The "Main CLK" Oscillator on the board which is used by the PLL to generate
++ * CPU/AHB/APB clocks.
++ */
++#define MAIN_CLK	33000000
++
++#endif	/* CONFIG_PLATFORM_A369 */
++
++#endif	/* __MACH_BOARD_A369_H */
+diff --git a/arch/arm/mach-faraday/include/mach/board-axi.h b/arch/arm/mach-faraday/include/mach/board-axi.h
+new file mode 100644
+index 00000000..a7b11862
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/board-axi.h
+@@ -0,0 +1,46 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/board-axi.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_BOARD_AXI_H
++#define __MACH_BOARD_AXI_H
++
++#ifdef CONFIG_PLATFORM_AXI
++
++/*
++ * Base addresses
++ */
++
++#define AXI_FTUART010_0_PA_BASE		0xa8000000
++#define AXI_FTUART010_1_PA_BASE		0xa8100000
++#define AXI_FTTMR010_0_PA_BASE		0xa8200000
++#define AXI_FTINTC010_0_PA_BASE		0xa8300000
++#define AXI_FTDMAC030_0_PA_BASE		0xa8500000
++
++#define AXI_FTUART010_0_VA_BASE		0xfa800000
++#define AXI_FTUART010_1_VA_BASE		0xfa810000
++#define AXI_FTTMR010_0_VA_BASE		0xfa820000
++#define AXI_FTINTC010_0_VA_BASE		0xfa830000
++
++#define DEBUG_LL_FTUART010_PA_BASE	AXI_FTUART010_0_PA_BASE
++#define DEBUG_LL_FTUART010_VA_BASE	AXI_FTUART010_0_VA_BASE
++
++#endif	/* CONFIG_PLATFORM_AXI */
++
++#endif	/* __MACH_BOARD_AXI_H */
+diff --git a/arch/arm/mach-faraday/include/mach/debug-macro.S b/arch/arm/mach-faraday/include/mach/debug-macro.S
+new file mode 100644
+index 00000000..aadb8d57
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/debug-macro.S
+@@ -0,0 +1,44 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/debug-macro.S
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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 <linux/linkage.h>
++#include <mach/hardware.h>
++#include <mach/serial.h>
++
++		.macro	addruart, rp, rv, tmp
++		ldr	\rp, =DEBUG_LL_FTUART010_PA_BASE	@ physical base address of UART
++		ldr	\rv, =DEBUG_LL_FTUART010_VA_BASE	@ virtual base address of UART
++		.endm
++
++		.macro	senduart, rd, rx
++		strb	\rd, [\rx, #SERIAL_THR]
++		.endm
++
++		.macro	waituart, rd, rx
++1001:		ldrb	\rd, [\rx, #SERIAL_LSR]	@ LSR
++		tst	\rd, #SERIAL_LSR_THRE	@ test empty
++		beq	1001b
++		.endm
++
++		.macro	busyuart, rd, rx
++		mov	\rd, #0x100
++1010:		subs	\rd, \rd, #1
++		bne	1010b
++		.endm
+diff --git a/arch/arm/mach-faraday/include/mach/dma-a369.h b/arch/arm/mach-faraday/include/mach/dma-a369.h
+new file mode 100644
+index 00000000..b93c3381
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/dma-a369.h
+@@ -0,0 +1,67 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/dma-a369.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_DMA_A369_H
++#define __MACH_DMA_A369_H
++
++#ifdef CONFIG_PLATFORM_A369
++
++/*
++ * Hardware handshake number for FTDMAC020
++ * 0-6 are reserved for APB devices
++ */
++#define A369_DMAC_HANDSHAKE_EDMACH3	7
++#define A369_DMAC_HANDSHAKE_EDMACH2	8
++#define A369_DMAC_HANDSHAKE_EDMACH1	9
++#define A369_DMAC_HANDSHAKE_EDMACH0	10
++#define A369_DMAC_HANDSHAKE_IDETX	11
++#define A369_DMAC_HANDSHAKE_IDERX	12
++#define A369_DMAC_HANDSHAKE_SD1		13
++#define A369_DMAC_HANDSHAKE_SD0		14
++#define A369_DMAC_HANDSHAKE_NANDC	15
++
++/*
++ * Hardware handshake number for FTAPBB020
++ */
++#define A369_APBB_HANDSHAKE_UART0TX	1
++#define A369_APBB_HANDSHAKE_UART0RX	1
++#define A369_APBB_HANDSHAKE_UART1TX	2
++#define A369_APBB_HANDSHAKE_UART1RX	2
++#define A369_APBB_HANDSHAKE_UART2TX	3
++#define A369_APBB_HANDSHAKE_UART2RX	3
++#define A369_APBB_HANDSHAKE_UART3TX	4
++#define A369_APBB_HANDSHAKE_UART3RX	5
++#define A369_APBB_HANDSHAKE_IRDA	6
++#define A369_APBB_HANDSHAKE_SSP0TX	7
++#define A369_APBB_HANDSHAKE_SSP0RX	8
++#define A369_APBB_HANDSHAKE_SSP1TX	9
++#define A369_APBB_HANDSHAKE_SSP1RX	10
++#define A369_APBB_HANDSHAKE_TSC		11
++#define A369_APBB_HANDSHAKE_TMR1	12
++#define A369_APBB_HANDSHAKE_TMR2	13
++#define A369_APBB_HANDSHAKE_TMR5	14
++
++int a369_dmac_handshake_alloc(const char *name);
++int a369_dmac_handshake_setup(unsigned int handshake, int which);
++int a369_dmac_handshake_free(unsigned int handshake);
++
++#endif	/* CONFIG_PLATFORM_A369 */
++
++#endif	/* __MACH_DMA_A369_H */
+diff --git a/arch/arm/mach-faraday/include/mach/entry-macro.S b/arch/arm/mach-faraday/include/mach/entry-macro.S
+new file mode 100644
+index 00000000..f9a2a581
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/entry-macro.S
+@@ -0,0 +1,101 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/entry-macro.S
++ *
++ *  Low-level IRQ helper macros for Faraday platforms
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef CONFIG_CPU_FMP626
++
++#include <mach/ftintc010.h>
++
++	.macro	disable_fiq
++	.endm
++
++	.macro	get_irqnr_preamble, base, tmp
++	ldr	\base, =ftintc010_base_addr
++	ldr	\base, [\base]
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++	/*
++	 * Get IRQ number and base
++	 * Input: base
++	 * Output: irqnr, Z flag
++	 * Local R/W: irqstat, tmp
++	 */
++	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++
++	ldr	\irqstat, [\base, #FTINTC010_OFFSET_IRQSTATUS]
++	cmp	\irqstat, #0
++
++#ifndef CONFIG_FTINTC010EX
++	beq	1001f
++#endif
++	movne	\irqnr, #0
++
++#ifdef CONFIG_FTINTC010EX
++	bne	1002f
++
++	ldr	\irqstat, [\base, #FTINTC010_OFFSET_IRQSTATUSEX]
++	cmp	\irqstat, #0
++
++	beq	1001f
++	mov	\irqnr, #32
++1002:
++#endif
++
++#if __LINUX_ARM_ARCH__ >= 5
++	clz	\tmp, \irqstat
++	rsb	\tmp, \tmp, #31
++	add	\irqnr, \irqnr, \tmp
++#else
++	movs	\tmp, \irqstat, lsl #16
++	movne	\irqstat, \tmp
++	addeq	\irqnr, \irqnr, #16
++
++	movs	\tmp, \irqstat, lsl #8
++	movne	\irqstat, \tmp
++	addeq	\irqnr, \irqnr, #8
++
++	movs	\tmp, \irqstat, lsl #4
++	movne	\irqstat, \tmp
++	addeq	\irqnr, \irqnr, #4
++
++	movs	\tmp, \irqstat, lsl #2
++	movne	\irqstat, \tmp
++	addeq	\irqnr, \irqnr, #2
++
++	movs	\tmp, \irqstat, lsl #1
++	addeqs	\irqnr, \irqnr, #1
++#endif
++
++1001:
++	.endm	/* get_irqnr_and_base */
++
++#else	/* CONFIG_CPU_FMP626 */
++
++	.macro	disable_fiq
++	.endm
++
++	.macro	arch_ret_to_user, tmp1, tmp2
++	.endm
++
++#endif	/* CONFIG_CPU_FMP626 */
+diff --git a/arch/arm/mach-faraday/include/mach/ftahbb020.h b/arch/arm/mach-faraday/include/mach/ftahbb020.h
+new file mode 100644
+index 00000000..9e6357e3
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftahbb020.h
+@@ -0,0 +1,69 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftahbb020.h
++ *
++ *  Faraday FTAHBB020 AHB Bridge
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTAHBB020_H
++#define __FTAHBB020_H
++
++#define FTAHBB020_OFFSET_P2S_IRQSRC	0x0
++#define FTAHBB020_OFFSET_P2S_IRQMASK	0x4
++#define FTAHBB020_OFFSET_P2S_IRQCLEAR	0x8
++#define FTAHBB020_OFFSET_P2S_BUFATTR	0xc
++#define FTAHBB020_OFFSET_P2S_PROTENABLE	0x10
++#define FTAHBB020_OFFSET_P2S_XIRQSRC	0x14
++#define FTAHBB020_OFFSET_P2S_XIRQMASK	0x18
++#define FTAHBB020_OFFSET_P2S_XIRQCLEAR	0x1c
++#define FTAHBB020_OFFSET_P2S_XIRQMODE	0x20
++#define FTAHBB020_OFFSET_P2S_XIRQBOTH	0x24
++#define FTAHBB020_OFFSET_P2S_XIRQLEVEL	0x28
++#define FTAHBB020_OFFSET_P2S_XIRQENABLE	0x2c
++#define FTAHBB020_OFFSET_P2S_IWBA(x)	(0x100 + (x) * 0x10)
++#define FTAHBB020_OFFSET_P2S_IWAT(x)	(0x104 + (x) * 0x10)
++#define FTAHBB020_OFFSET_P2S_IWTA(x)	(0x108 + (x) * 0x10)
++#define FTAHBB020_OFFSET_S2P_IRQSRC	0x400
++#define FTAHBB020_OFFSET_S2P_IRQMASK	0x404
++#define FTAHBB020_OFFSET_S2P_IRQCLEAR	0x408
++#define FTAHBB020_OFFSET_S2P_BUFATTR	0x40c
++#define FTAHBB020_OFFSET_S2P_PROTENABLE	0x410
++#define FTAHBB020_OFFSET_S2P_XIRQSRC	0x414
++#define FTAHBB020_OFFSET_S2P_XIRQMASK	0x418
++#define FTAHBB020_OFFSET_S2P_XIRQCLEAR	0x41c
++#define FTAHBB020_OFFSET_S2P_XIRQMODE	0x420
++#define FTAHBB020_OFFSET_S2P_XIRQBOTH	0x424
++#define FTAHBB020_OFFSET_S2P_XIRQLEVEL	0x428
++#define FTAHBB020_OFFSET_S2P_XIRQENABLE	0x42c
++#define FTAHBB020_OFFSET_S2P_IWBA(x)	(0x500 + (x) * 0x10)
++#define FTAHBB020_OFFSET_S2P_IWAT(x)	(0x504 + (x) * 0x10)
++#define FTAHBB020_OFFSET_S2P_IWTA(x)	(0x508 + (x) * 0x10)
++
++#ifndef __ASSEMBLY__
++
++#include <linux/irq.h>
++
++void __init ftahbb020_init(unsigned int ftahbb020_nr, void __iomem *base,
++			   unsigned int irq_start);
++void __init ftahbb020_cascade_irq(unsigned int ftahbb020_nr, unsigned int irq);
++int ftahbb020_set_irq_type(unsigned int irq, unsigned int type);
++
++#endif	/* __ASSEMBLY__ */
++
++#endif	/* __FTAHBB020_H */
+diff --git a/arch/arm/mach-faraday/include/mach/ftapbb020.h b/arch/arm/mach-faraday/include/mach/ftapbb020.h
+new file mode 100644
+index 00000000..cb1f8777
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftapbb020.h
+@@ -0,0 +1,138 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftapbb020.h
++ *
++ *  Faraday FTAPBB020 APB Bridge with DMA function
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTAPBB020_H
++#define __FTAPBB020_H
++
++#define FTAPBB020_OFFSET_BSR(x)		((x) * 0x4)		/* BSR of slave x */
++#define FTAPBB020_OFFSET_SAR(x)		(0x80 + (x) * 0x10)	/* src addr of channel x */
++#define FTAPBB020_OFFSET_DAR(x)		(0x84 + (x) * 0x10)	/* dst addr of channel x */
++#define FTAPBB020_OFFSET_CYC(x)		(0x88 + (x) * 0x10)	/* cycles of channel x */
++#define FTAPBB020_OFFSET_CMD(x)		(0x8c + (x) * 0x10)	/* command of channel x */
++#define FTAPBB020_OFFSET_CR		0xc0
++#define FTAPBB020_OFFSET_SR		0xc4
++#define FTAPBB020_OFFSET_REV		0xc8
++
++/*
++ * Base/size of each slave
++ */
++#define FTAPBB020_BSR_SIZE_1M		(0 << 16)
++#define FTAPBB020_BSR_SIZE_2M		(1 << 16)
++#define FTAPBB020_BSR_SIZE_4M		(2 << 16)
++#define FTAPBB020_BSR_SIZE_8M		(3 << 16)
++#define FTAPBB020_BSR_SIZE_16M		(4 << 16)
++#define FTAPBB020_BSR_SIZE_32M		(5 << 16)
++#define FTAPBB020_BSR_SIZE_64M		(6 << 16)
++#define FTAPBB020_BSR_SIZE_128M		(7 << 16)
++#define FTAPBB020_BSR_SIZE_256M		(8 << 16)
++#define FTAPBB020_BSR_BASE(x)		((x) & (0x3ff << 20))
++
++/*
++ * Cycle count of each DMA channel
++ */
++#define FTAPBB020_CYC_MASK		0x00ffffff
++
++/*
++ * Command of each DMA channel
++ */
++#define FTAPBB020_CMD_ENABLE		(1 << 0)
++#define FTAPBB020_CMD_FININT_S		(1 << 1)
++#define FTAPBB020_CMD_FININT_E		(1 << 2)
++#define FTAPBB020_CMD_BURST		(1 << 3)
++#define FTAPBB020_CMD_ERRINT_S		(1 << 4)
++#define FTAPBB020_CMD_ERRINT_E		(1 << 5)
++#define FTAPBB020_CMD_SRC_TYPE_AHB	(1 << 6)
++#define FTAPBB020_CMD_DST_TYPE_AHB	(1 << 7)
++#define FTAPBB020_CMD_SRC_MODE_FIXED	(0 << 8)
++#define FTAPBB020_CMD_SRC_MODE_BYTE_INC	(1 << 8)
++#define FTAPBB020_CMD_SRC_MODE_HALF_INC	(2 << 8)
++#define FTAPBB020_CMD_SRC_MODE_WORD_INC	(3 << 8)
++#define FTAPBB020_CMD_SRC_MODE_BYTE_DEC	(5 << 8)
++#define FTAPBB020_CMD_SRC_MODE_HALF_DEC	(6 << 8)
++#define FTAPBB020_CMD_SRC_MODE_WORD_DEC	(7 << 8)
++#define FTAPBB020_CMD_DST_MODE_FIXED	(0 << 12)
++#define FTAPBB020_CMD_DST_MODE_BYTE_INC	(1 << 12)
++#define FTAPBB020_CMD_DST_MODE_HALF_INC	(2 << 12)
++#define FTAPBB020_CMD_DST_MODE_WORD_INC	(3 << 12)
++#define FTAPBB020_CMD_DST_MODE_BYTE_DEC	(5 << 12)
++#define FTAPBB020_CMD_DST_MODE_HALF_DEC	(6 << 12)
++#define FTAPBB020_CMD_DST_MODE_WORD_DEC	(7 << 12)
++#define FTAPBB020_CMD_DST_HANDSHAKE(x)	(((x) & 0xf) << 16)	/* destination handshake channel */
++#define FTAPBB020_CMD_WIDTH_WORD	(0 << 20)
++#define FTAPBB020_CMD_WIDTH_HALF	(1 << 20)
++#define FTAPBB020_CMD_WIDTH_BYTE	(2 << 20)
++#define FTAPBB020_CMD_SRC_HANDSHAKE(x)	(((x) & 0xf) << 24)	/* source handshake channel */
++
++/*
++ * Control register
++ */
++#define FTAPBB020_CR_BUF_NORMAL		(0 << 0)
++#define FTAPBB020_CR_BUF_ALWAYS		(1 << 0)
++#define FTAPBB020_CR_BUF_NEVER		(2 << 0)
++#define FTAPBB020_CR_BWERRINT_E		(1 << 2)
++
++/*
++ * Status register
++ */
++#define FTAPBB020_SR_BWERRINT		(1 << 0)
++
++/*
++ * Revision register
++ */
++#define FTAPBB020_REV_REVISION(rev)	((rev) & ~(0xff << 24))
++
++enum ftapbb020_bus_type {
++	FTAPBB020_BUS_TYPE_AHB,
++	FTAPBB020_BUS_TYPE_APB,
++};
++
++enum ftapbb020_channels {
++	FTAPBB020_CHANNEL_0 = (1 << 0),
++	FTAPBB020_CHANNEL_1 = (1 << 1),
++	FTAPBB020_CHANNEL_2 = (1 << 2),
++	FTAPBB020_CHANNEL_3 = (1 << 3),
++	FTAPBB020_CHANNEL_ALL = 0xf,
++};
++
++/**
++ * struct ftapbb020_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @type: bus type of the device
++ * @channels: bitmap of usable DMA channels
++ * @handshake: hardware handshake number
++ */
++struct ftapbb020_dma_slave {
++	struct dma_slave_config common;
++	enum ftapbb020_bus_type type;
++	enum ftapbb020_channels channels;
++	unsigned int handshake;
++};
++
++/**
++ * ftapbb020_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftapbb020_dma_slave
++ */
++bool ftapbb020_chan_filter(struct dma_chan *chan, void *data);
++
++#endif	/* __FTAPBB020_H */
+diff --git a/arch/arm/mach-faraday/include/mach/ftdmac020.h b/arch/arm/mach-faraday/include/mach/ftdmac020.h
+new file mode 100644
+index 00000000..dc0e0f92
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftdmac020.h
+@@ -0,0 +1,206 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftdmac020.h
++ *
++ *  Faraday FTDMAC020 DMA controller
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *  Copyright (C) 2010 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTDMAC020_H
++#define __FTDMAC020_H
++
++#define FTDMAC020_OFFSET_ISR		0x0
++#define FTDMAC020_OFFSET_TCISR		0x4
++#define FTDMAC020_OFFSET_TCICR		0x8
++#define FTDMAC020_OFFSET_EAISR		0xc
++#define FTDMAC020_OFFSET_EAICR		0x10
++#define FTDMAC020_OFFSET_TCRAW		0x14
++#define FTDMAC020_OFFSET_EARAW		0x18
++#define FTDMAC020_OFFSET_CH_ENABLED	0x1c
++#define FTDMAC020_OFFSET_CH_BUSY	0x20
++#define FTDMAC020_OFFSET_CR		0x24
++#define FTDMAC020_OFFSET_SYNC		0x28
++#define FTDMAC020_OFFSET_REVISION	0x2c
++#define FTDMAC020_OFFSET_FEATURE	0x30
++
++#define FTDMAC020_OFFSET_CCR_CH(x)	(0x100 + (x) * 0x20)
++#define FTDMAC020_OFFSET_CFG_CH(x)	(0x104 + (x) * 0x20)
++#define FTDMAC020_OFFSET_SRC_CH(x)	(0x108 + (x) * 0x20)
++#define FTDMAC020_OFFSET_DST_CH(x)	(0x10c + (x) * 0x20)
++#define FTDMAC020_OFFSET_LLP_CH(x)	(0x110 + (x) * 0x20)
++#define FTDMAC020_OFFSET_CYC_CH(x)	(0x114 + (x) * 0x20)
++
++/*
++ * Error/abort interrupt status/clear register
++ * Error/abort status register
++ */
++#define FTDMAC020_EA_ERR_CH(x)		(1 << (x))
++#define FTDMAC020_EA_ABT_CH(x)		(1 << ((x) + 16))
++
++/*
++ * Main configuration status register
++ */
++#define FTDMAC020_CR_ENABLE		(1 << 0)
++#define FTDMAC020_CR_M0_BE		(1 << 1)	/* master 0 big endian */
++#define FTDMAC020_CR_M1_BE		(1 << 2)	/* master 1 big endian */
++
++/*
++ * Channel control register
++ */
++#define FTDMAC020_CCR_ENABLE		(1 << 0)
++#define FTDMAC020_CCR_DST_M1		(1 << 1)
++#define FTDMAC020_CCR_SRC_M1		(1 << 2)
++#define FTDMAC020_CCR_DST_INC		(0x0 << 3)
++#define FTDMAC020_CCR_DST_DEC		(0x1 << 3)
++#define FTDMAC020_CCR_DST_FIXED		(0x2 << 3)
++#define FTDMAC020_CCR_SRC_INC		(0x0 << 5)
++#define FTDMAC020_CCR_SRC_DEC		(0x1 << 5)
++#define FTDMAC020_CCR_SRC_FIXED		(0x2 << 5)
++#define FTDMAC020_CCR_HANDSHAKE		(1 << 7)
++#define FTDMAC020_CCR_DST_WIDTH_8	(0x0 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_16	(0x1 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_32	(0x2 << 8)
++#define FTDMAC020_CCR_DST_WIDTH_64	(0x3 << 8)
++#define FTDMAC020_CCR_SRC_WIDTH_8	(0x0 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_16	(0x1 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_32	(0x2 << 11)
++#define FTDMAC020_CCR_SRC_WIDTH_64	(0x3 << 11)
++#define FTDMAC020_CCR_ABORT		(1 << 15)
++#define FTDMAC020_CCR_BURST_1		(0x0 << 16)
++#define FTDMAC020_CCR_BURST_4		(0x1 << 16)
++#define FTDMAC020_CCR_BURST_8		(0x2 << 16)
++#define FTDMAC020_CCR_BURST_16		(0x3 << 16)
++#define FTDMAC020_CCR_BURST_32		(0x4 << 16)
++#define FTDMAC020_CCR_BURST_64		(0x5 << 16)
++#define FTDMAC020_CCR_BURST_128		(0x6 << 16)
++#define FTDMAC020_CCR_BURST_256		(0x7 << 16)
++#define FTDMAC020_CCR_PRIVILEGED	(1 << 19)
++#define FTDMAC020_CCR_BUFFERABLE	(1 << 20)
++#define FTDMAC020_CCR_CACHEABLE		(1 << 21)
++#define FTDMAC020_CCR_PRIO_0		(0x0 << 22)
++#define FTDMAC020_CCR_PRIO_1		(0x1 << 22)
++#define FTDMAC020_CCR_PRIO_2		(0x2 << 22)
++#define FTDMAC020_CCR_PRIO_3		(0x2 << 22)
++#define FTDMAC020_CCR_FIFOTH_1		(0x0 << 24)
++#define FTDMAC020_CCR_FIFOTH_2		(0x1 << 24)
++#define FTDMAC020_CCR_FIFOTH_4		(0x2 << 24)
++#define FTDMAC020_CCR_FIFOTH_8		(0x3 << 24)
++#define FTDMAC020_CCR_FIFOTH_16		(0x4 << 24)
++#define FTDMAC020_CCR_MASK_TC		(1 << 31)
++
++/*
++ * Channel configuration register
++ */
++#define FTDMAC020_CFG_MASK_TCI		(1 << 0)	/* mask tc interrupt */
++#define FTDMAC020_CFG_MASK_EI		(1 << 1)	/* mask error interrupt */
++#define FTDMAC020_CFG_MASK_AI		(1 << 2)	/* mask abort interrupt */
++#define FTDMAC020_CFG_SRC_HANDSHAKE(x)	(((x) & 0xf) << 3)
++#define FTDMAC020_CFG_SRC_HANDSHAKE_EN	(1 << 7)
++#define FTDMAC020_CFG_BUSY		(1 << 8)
++#define FTDMAC020_CFG_DST_HANDSHAKE(x)	(((x) & 0xf) << 9)
++#define FTDMAC020_CFG_DST_HANDSHAKE_EN	(1 << 13)
++#define FTDMAC020_CFG_LLP_CNT(cfg)	(((cfg) >> 16) & 0xf)
++
++/*
++ * Link list descriptor pointer
++ */
++#define FTDMAC020_LLP_M1		(1 << 0)
++#define FTDMAC020_LLP_ADDR(a)		((a) & ~0x3)
++
++/*
++ * Transfer size register
++ */
++#define FTDMAC020_CYC_MASK		0x3fffff
++
++/**
++ * struct ftdmac020_lld - hardware link list descriptor.
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the next link list descriptor
++ * @ctrl: control field
++ * @cycle: transfer size
++ *
++ * should be word aligned
++ */
++struct ftdmac020_lld {
++	dma_addr_t src;
++	dma_addr_t dst;
++	dma_addr_t next;
++	unsigned int ctrl;
++	unsigned int cycle;
++};
++
++#define FTDMAC020_LLD_CTRL_DST_M1	(1 << 16)
++#define FTDMAC020_LLD_CTRL_SRC_M1	(1 << 17)
++#define FTDMAC020_LLD_CTRL_DST_INC	(0x0 << 18)
++#define FTDMAC020_LLD_CTRL_DST_DEC	(0x1 << 18)
++#define FTDMAC020_LLD_CTRL_DST_FIXED	(0x2 << 18)
++#define FTDMAC020_LLD_CTRL_SRC_INC	(0x0 << 20)
++#define FTDMAC020_LLD_CTRL_SRC_DEC	(0x1 << 20)
++#define FTDMAC020_LLD_CTRL_SRC_FIXED	(0x2 << 20)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_8	(0x0 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_16	(0x1 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_32	(0x2 << 22)
++#define FTDMAC020_LLD_CTRL_DST_WIDTH_64	(0x3 << 22)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_8	(0x0 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_16	(0x1 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_32	(0x2 << 25)
++#define FTDMAC020_LLD_CTRL_SRC_WIDTH_64	(0x3 << 25)
++#define FTDMAC020_LLD_CTRL_MASK_TC	(1 << 28)
++#define FTDMAC020_LLD_CTRL_FIFOTH_1	(0x0 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_2	(0x1 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_4	(0x2 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_8	(0x3 << 29)
++#define FTDMAC020_LLD_CTRL_FIFOTH_16	(0x4 << 29)
++
++#define FTDMAC020_LLD_CYCLE_MASK	0x3fffff
++
++enum ftdmac020_channels {
++	FTDMAC020_CHANNEL_0 = (1 << 0),
++	FTDMAC020_CHANNEL_1 = (1 << 1),
++	FTDMAC020_CHANNEL_2 = (1 << 2),
++	FTDMAC020_CHANNEL_3 = (1 << 3),
++	FTDMAC020_CHANNEL_4 = (1 << 4),
++	FTDMAC020_CHANNEL_5 = (1 << 5),
++	FTDMAC020_CHANNEL_6 = (1 << 6),
++	FTDMAC020_CHANNEL_7 = (1 << 7),
++	FTDMAC020_CHANNEL_ALL = 0xff,
++};
++
++/**
++ * struct ftdmac020_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @id: specify which ftdmac020 device to use, -1 for wildcard
++ * @channels: bitmap of usable DMA channels
++ * @handshake: hardware handshake number, -1 to disable handshake mode
++ */
++struct ftdmac020_dma_slave {
++	struct dma_slave_config common;
++	int id;
++	enum ftdmac020_channels channels;
++	int handshake;
++};
++
++/**
++ * ftdmac020_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftdmac020_dma_slave
++ */
++bool ftdmac020_chan_filter(struct dma_chan *chan, void *data);
++
++#endif	/* __FTDMAC020_H */
+diff --git a/arch/arm/mach-faraday/include/mach/ftdmac030.h b/arch/arm/mach-faraday/include/mach/ftdmac030.h
+new file mode 100644
+index 00000000..7f526d24
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftdmac030.h
+@@ -0,0 +1,177 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftdmac030.h
++ *
++ *  Faraday FTDMAC030 DMA controller
++ *
++ *  Copyright (C) 2011 Faraday Technology
++ *  Copyright (C) 2011 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTDMAC030_H
++#define __FTDMAC030_H
++
++#define FTDMAC030_OFFSET_ISR		0x0
++#define FTDMAC030_OFFSET_TCISR		0x4
++#define FTDMAC030_OFFSET_TCICR		0x8
++#define FTDMAC030_OFFSET_EAISR		0xc
++#define FTDMAC030_OFFSET_EAICR		0x10
++#define FTDMAC030_OFFSET_TCRAW		0x14
++#define FTDMAC030_OFFSET_EARAW		0x18
++#define FTDMAC030_OFFSET_CH_ENABLED	0x1c
++#define FTDMAC030_OFFSET_SYNC		0x20
++#define FTDMAC030_OFFSET_LDM		0x24
++#define FTDMAC030_OFFSET_WDT		0x28
++#define FTDMAC030_OFFSET_GE		0x2c
++#define FTDMAC030_OFFSET_PSE		0x30
++#define FTDMAC030_OFFSET_REVISION	0x34
++#define FTDMAC030_OFFSET_FEATURE	0x38
++#define FTDMAC030_OFFSET_LDMFFS0	0x3c
++#define FTDMAC030_OFFSET_LDMFFS1	0x40
++#define FTDMAC030_OFFSET_LDMFFS2	0x44
++#define FTDMAC030_OFFSET_LDMFFS3	0x48
++
++#define FTDMAC030_OFFSET_CTRL_CH(x)	(0x100 + (x) * 0x20)
++#define FTDMAC030_OFFSET_CFG_CH(x)	(0x104 + (x) * 0x20)
++#define FTDMAC030_OFFSET_SRC_CH(x)	(0x108 + (x) * 0x20)
++#define FTDMAC030_OFFSET_DST_CH(x)	(0x10c + (x) * 0x20)
++#define FTDMAC030_OFFSET_LLP_CH(x)	(0x110 + (x) * 0x20)
++#define FTDMAC030_OFFSET_CYC_CH(x)	(0x114 + (x) * 0x20)
++#define FTDMAC030_OFFSET_STRIDE_CH(x)	(0x118 + (x) * 0x20)
++
++/*
++ * Error/abort interrupt status/clear register
++ * Error/abort status register
++ */
++#define FTDMAC030_EA_ERR_CH(x)		(1 << (x))
++#define FTDMAC030_EA_WDT_CH(x)		(1 << ((x) + 8))
++#define FTDMAC030_EA_ABT_CH(x)		(1 << ((x) + 16))
++
++/*
++ * Control register
++ */
++#define FTDMAC030_CTRL_WE(x)		((1 << (x)) & 0xff)
++#define FTDMAC030_CTRL_WSYNC		(1 << 8)
++#define FTDMAC030_CTRL_SE(x)		(((x) & 0x7) << 9)
++#define FTDMAC030_CTRL_SE_ENABLE	(1 << 12)
++#define FTDMAC030_CTRL_WE_ENABLE	(1 << 13)
++#define FTDMAC030_CTRL_2D		(1 << 14)
++#define FTDMAC030_CTRL_EXP		(1 << 15)
++#define FTDMAC030_CTRL_ENABLE		(1 << 16)
++#define FTDMAC030_CTRL_WDT_ENABLE	(1 << 17)
++#define FTDMAC030_CTRL_DST_INC		(0x0 << 18)
++#define FTDMAC030_CTRL_DST_FIXED	(0x2 << 18)
++#define FTDMAC030_CTRL_SRC_INC		(0x0 << 20)
++#define FTDMAC030_CTRL_SRC_FIXED	(0x2 << 20)
++#define FTDMAC030_CTRL_DST_WIDTH_8	(0x0 << 22)
++#define FTDMAC030_CTRL_DST_WIDTH_16	(0x1 << 22)
++#define FTDMAC030_CTRL_DST_WIDTH_32	(0x2 << 22)
++#define FTDMAC030_CTRL_DST_WIDTH_64	(0x3 << 22)
++#define FTDMAC030_CTRL_SRC_WIDTH_8	(0x0 << 25)
++#define FTDMAC030_CTRL_SRC_WIDTH_16	(0x1 << 25)
++#define FTDMAC030_CTRL_SRC_WIDTH_32	(0x2 << 25)
++#define FTDMAC030_CTRL_SRC_WIDTH_64	(0x3 << 25)
++#define FTDMAC030_CTRL_MASK_TC		(1 << 28)
++#define FTDMAC030_CTRL_1BEAT		(0x0 << 29)
++#define FTDMAC030_CTRL_2BEATS		(0x1 << 29)
++#define FTDMAC030_CTRL_4BEATS		(0x2 << 29)
++#define FTDMAC030_CTRL_8BEATS		(0x3 << 29)
++#define FTDMAC030_CTRL_16BEATS		(0x4 << 29)
++#define FTDMAC030_CTRL_32BEATS		(0x5 << 29)
++#define FTDMAC030_CTRL_64BEATS		(0x6 << 29)
++#define FTDMAC030_CTRL_128BEATS		(0x7 << 29)
++
++/*
++ * Configuration register
++ */
++#define FTDMAC030_CFG_MASK_TCI		(1 << 0)	/* mask tc interrupt */
++#define FTDMAC030_CFG_MASK_EI		(1 << 1)	/* mask error interrupt */
++#define FTDMAC030_CFG_MASK_AI		(1 << 2)	/* mask abort interrupt */
++#define FTDMAC030_CFG_SRC_HANDSHAKE(x)	(((x) & 0xf) << 3)
++#define FTDMAC030_CFG_SRC_HANDSHAKE_EN	(1 << 7)
++#define FTDMAC030_CFG_DST_HANDSHAKE(x)	(((x) & 0xf) << 9)
++#define FTDMAC030_CFG_DST_HANDSHAKE_EN	(1 << 13)
++#define FTDMAC030_CFG_LLP_CNT(cfg)	(((cfg) >> 16) & 0xf)
++#define FTDMAC030_CFG_GW(x)		(((x) & 0xff) << 20)
++#define FTDMAC030_CFG_HIGH_PRIO		(1 << 28)
++
++/*
++ * Transfer size register
++ */
++#define FTDMAC030_CYC_MASK		0x3fffff
++#define FTDMAC030_CYC_TOTAL(x)		((x) & FTDMAC030_CYC_MASK)
++#define FTDMAC030_CYC_2D(x, y)		(((x) & 0xffff) | (((y) & 0xffff) << 16))
++
++/*
++ * Stride register
++ */
++#define FTDMAC030_STRIDE_SRC(x)		((x) & 0xffff)
++#define FTDMAC030_STRIDE_DST(x)		(((x) & 0xffff) << 16)
++
++/**
++ * struct ftdmac030_lld - hardware link list descriptor.
++ * @src: source physical address
++ * @dst: destination physical addr
++ * @next: phsical address to the next link list descriptor
++ * @ctrl: control field
++ * @cycle: transfer size
++ * @stride: stride for 2D mode
++ *
++ * should be 32 or 64 bits aligned depends on AXI configuration
++ */
++struct ftdmac030_lld {
++	dma_addr_t src;
++	dma_addr_t dst;
++	dma_addr_t next;
++	unsigned int ctrl;
++	unsigned int cycle;
++	unsigned int stride;
++};
++
++enum ftdmac030_channels {
++	FTDMAC030_CHANNEL_0 = (1 << 0),
++	FTDMAC030_CHANNEL_1 = (1 << 1),
++	FTDMAC030_CHANNEL_2 = (1 << 2),
++	FTDMAC030_CHANNEL_3 = (1 << 3),
++	FTDMAC030_CHANNEL_4 = (1 << 4),
++	FTDMAC030_CHANNEL_5 = (1 << 5),
++	FTDMAC030_CHANNEL_6 = (1 << 6),
++	FTDMAC030_CHANNEL_7 = (1 << 7),
++	FTDMAC030_CHANNEL_ALL = 0xff,
++};
++
++/**
++ * struct ftdmac030_dma_slave - DMA slave data
++ * @common: physical address and register width...
++ * @id: specify which ftdmac030 device to use, -1 for wildcard
++ * @channels: bitmap of usable DMA channels
++ * @handshake: hardware handshake number, -1 to disable handshake mode
++ */
++struct ftdmac030_dma_slave {
++	struct dma_slave_config common;
++	int id;
++	enum ftdmac030_channels channels;
++	int handshake;
++};
++
++/**
++ * ftdmac030_chan_filter() - filter function for dma_request_channel().
++ * @chan: DMA channel
++ * @data: pointer to ftdmac030_dma_slave
++ */
++bool ftdmac030_chan_filter(struct dma_chan *chan, void *data);
++
++#endif	/* __FTDMAC030_H */
+diff --git a/arch/arm/mach-faraday/include/mach/ftintc010.h b/arch/arm/mach-faraday/include/mach/ftintc010.h
+new file mode 100644
+index 00000000..707d321a
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftintc010.h
+@@ -0,0 +1,59 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftintc010.h
++ *
++ *  Faraday FTINTC010 Interrupt Controller
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTINTC010_H
++#define __FTINTC010_H
++
++#define FTINTC010_OFFSET_IRQSRC		0x00
++#define FTINTC010_OFFSET_IRQMASK	0x04
++#define FTINTC010_OFFSET_IRQCLEAR	0x08
++#define FTINTC010_OFFSET_IRQMODE	0x0c
++#define FTINTC010_OFFSET_IRQLEVEL	0x10
++#define FTINTC010_OFFSET_IRQSTATUS	0x14
++
++#define FTINTC010_OFFSET_FIQSRC		0x20
++#define FTINTC010_OFFSET_FIQMASK	0x24
++#define FTINTC010_OFFSET_FIQCLEAR	0x28
++#define FTINTC010_OFFSET_FIQMODE	0x2c
++#define FTINTC010_OFFSET_FIQLEVEL	0x30
++#define FTINTC010_OFFSET_FIQSTATUS	0x34
++
++#define FTINTC010_OFFSET_IRQSRCEX	0x60
++#define FTINTC010_OFFSET_IRQMASKEX	0x64
++#define FTINTC010_OFFSET_IRQCLEAREX	0x68
++#define FTINTC010_OFFSET_IRQMODEEX	0x6c
++#define FTINTC010_OFFSET_IRQLEVELEX	0x70
++#define FTINTC010_OFFSET_IRQSTATUSEX	0x74
++
++#ifndef __ASSEMBLY__
++
++#include <linux/irq.h>
++
++void __init ftintc010_init(unsigned int ftintc010_nr, void __iomem *base,
++			   unsigned int irq_start);
++void __init ftintc010_cascade_irq(unsigned int ftintc010_nr, unsigned int irq);
++int ftintc010_set_irq_type(unsigned int irq, unsigned int type);
++
++#endif	/* __ASSEMBLY__ */
++
++#endif /* __FTINTC010_H */
+diff --git a/arch/arm/mach-faraday/include/mach/ftpci100.h b/arch/arm/mach-faraday/include/mach/ftpci100.h
+new file mode 100644
+index 00000000..40459d41
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftpci100.h
+@@ -0,0 +1,99 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftpci100.h
++ *
++ *  Faraday FTPCI100 PCI Bridge Controller
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTPCI100_H
++#define __FTPCI100_H
++
++#define FTPCI100_OFFSET_IOSIZE		0x00
++#define FTPCI100_OFFSET_PROT		0x04
++#define FTPCI100_OFFSET_CONFIG		0x28
++#define FTPCI100_OFFSET_CONFIGDATA	0x2c
++
++/*
++ * I/O space size signal register
++ */
++#define FTPCI100_IOSIZE_1M		0x0
++#define FTPCI100_IOSIZE_2M		0x1
++#define FTPCI100_IOSIZE_4M		0x2
++#define FTPCI100_IOSIZE_8M		0x3
++#define FTPCI100_IOSIZE_16M		0x4
++#define FTPCI100_IOSIZE_32M		0x5
++#define FTPCI100_IOSIZE_64M		0x6
++#define FTPCI100_IOSIZE_128M		0x7
++#define FTPCI100_IOSIZE_256M		0x8
++#define FTPCI100_IOSIZE_512M		0x9
++#define FTPCI100_IOSIZE_1G		0xa
++#define FTPCI100_IOSIZE_2G		0xb
++
++/*
++ * AHB protection register
++ */
++#define FTPCI100_PROT_DATA		(1 << 0)
++#define FTPCI100_PROT_PRIVILEGED	(1 << 1)
++#define FTPCI100_PROT_BUFFERABLE	(1 << 2)
++#define FTPCI100_PROT_CACHEABLE		(1 << 3)
++
++/*
++ * PCI configuration register
++ */
++#define FTPCI100_CONFIG_WHERE(where)	((where) & 0xfc)
++#define FTPCI100_CONFIG_DEVFN(devfn)	(((devfn) & 0xff) << 8)
++#define FTPCI100_CONFIG_BUS(bus)	(((bus) & 0xff) << 16)
++#define FTPCI100_CONFIG_ENABLE		(1 << 31)
++
++/*
++ * PCI registers
++ */
++#define PCI_CR2			0x4c
++#define  PCI_CR2_INTA_ENABLE	(1 << 22)
++#define  PCI_CR2_INTB_ENABLE	(1 << 23)
++#define  PCI_CR2_INTC_ENABLE	(1 << 24)
++#define  PCI_CR2_INTD_ENABLE	(1 << 25)
++#define  PCI_CR2_STATUS_MASK	(0xf << 28)
++#define  PCI_CR2_STATUS_INTA	(1 << 28)
++#define  PCI_CR2_STATUS_INTB	(1 << 29)
++#define  PCI_CR2_STATUS_INTC	(1 << 30)
++#define  PCI_CR2_STATUS_INTD	(1 << 31)
++
++#define PCI_MEM_BASE_SIZE_1	0x50
++#define PCI_MEM_BASE_SIZE_2	0x54
++#define PCI_MEM_BASE_SIZE_3	0x58
++#define  PCI_MEM_SIZE_1M	(0x0 << 16)
++#define  PCI_MEM_SIZE_2M	(0x1 << 16)
++#define  PCI_MEM_SIZE_4M	(0x2 << 16)
++#define  PCI_MEM_SIZE_8M	(0x3 << 16)
++#define  PCI_MEM_SIZE_16M	(0x4 << 16)
++#define  PCI_MEM_SIZE_32M	(0x5 << 16)
++#define  PCI_MEM_SIZE_64M	(0x6 << 16)
++#define  PCI_MEM_SIZE_128M	(0x7 << 16)
++#define  PCI_MEM_SIZE_256M	(0x8 << 16)
++#define  PCI_MEM_SIZE_512M	(0x9 << 16)
++#define  PCI_MEM_SIZE_1G	(0xa << 16)
++#define  PCI_MEM_SIZE_2G	(0xb << 16)
++#define  PCI_MEM_BASE(x)	((x) & ~0xfffff)
++
++void __init ftpci100_init(unsigned int nr, void __iomem *base);
++void __init ftpci100_int_init(unsigned int nr, unsigned int irq_start);
++void __init ftpci100_int_cascade_irq(unsigned int nr, unsigned int irq);
++
++#endif	/* __FTPCI100_H */
+diff --git a/arch/arm/mach-faraday/include/mach/ftpmu010.h b/arch/arm/mach-faraday/include/mach/ftpmu010.h
+new file mode 100644
+index 00000000..7215a309
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftpmu010.h
+@@ -0,0 +1,168 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftpmu010.h
++ *
++ *  Faraday FTPMU010 Power Management Unit
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTPMU010_H
++#define __FTPMU010_H
++
++#define FTPMU010_OFFSET_IDNMBR0		0x00
++#define FTPMU010_OFFSET_OSCC		0x08
++#define FTPMU010_OFFSET_PMODE		0x0c
++#define FTPMU010_OFFSET_PMCR		0x10
++#define FTPMU010_OFFSET_PED		0x14
++#define FTPMU010_OFFSET_PEDSR		0x18
++#define FTPMU010_OFFSET_PMSR		0x20
++#define FTPMU010_OFFSET_PGSR		0x24
++#define FTPMU010_OFFSET_MFPSR		0x28
++#define FTPMU010_OFFSET_MISC		0x2c
++#define FTPMU010_OFFSET_PDLLCR0		0x30
++#define FTPMU010_OFFSET_PDLLCR1		0x34
++#define FTPMU010_OFFSET_AHBMCLKOFF	0x38
++#define FTPMU010_OFFSET_APBMCLKOFF	0x3c
++#define FTPMU010_OFFSET_DCSRCR0		0x40
++#define FTPMU010_OFFSET_DCSRCR1		0x44
++#define FTPMU010_OFFSET_DCSRCR2		0x48
++#define FTPMU010_OFFSET_SDRAMHTC	0x4c
++#define FTPMU010_OFFSET_PSPR0		0x50
++#define FTPMU010_OFFSET_PSPR1		0x54
++#define FTPMU010_OFFSET_PSPR2		0x58
++#define FTPMU010_OFFSET_PSPR3		0x5c
++#define FTPMU010_OFFSET_PSPR4		0x60
++#define FTPMU010_OFFSET_PSPR5		0x64
++#define FTPMU010_OFFSET_PSPR6		0x68
++#define FTPMU010_OFFSET_PSPR7		0x6c
++#define FTPMU010_OFFSET_PSPR8		0x70
++#define FTPMU010_OFFSET_PSPR9		0x74
++#define FTPMU010_OFFSET_PSPR10		0x78
++#define FTPMU010_OFFSET_PSPR11		0x7c
++#define FTPMU010_OFFSET_PSPR12		0x80
++#define FTPMU010_OFFSET_PSPR13		0x84
++#define FTPMU010_OFFSET_PSPR14		0x88
++#define FTPMU010_OFFSET_PSPR15		0x8c
++#define FTPMU010_OFFSET_AHBDMA_RACCS	0x90
++#define FTPMU010_OFFSET_JSS		0x9c
++#define FTPMU010_OFFSET_CFC_RACC	0xa0
++#define FTPMU010_OFFSET_SSP1_RACC	0xa4
++#define FTPMU010_OFFSET_UART1TX_RACC	0xa8
++#define FTPMU010_OFFSET_UART1RX_RACC	0xac
++#define FTPMU010_OFFSET_UART2TX_RACC	0xb0
++#define FTPMU010_OFFSET_UART2RX_RACC	0xb4
++#define FTPMU010_OFFSET_SDC_RACC	0xb8
++#define FTPMU010_OFFSET_I2SAC97_RACC	0xbc
++#define FTPMU010_OFFSET_IRDATX_RACC	0xc0
++#define FTPMU010_OFFSET_USBD_RACC	0xc8
++#define FTPMU010_OFFSET_IRDARX_RACC	0xcc
++#define FTPMU010_OFFSET_IRDA_RACC	0xd0
++#define FTPMU010_OFFSET_ED0_RACC	0xd4
++#define FTPMU010_OFFSET_ED1_RACC	0xd8
++
++/*
++ * ID Number 0 Register
++ */
++#define FTPMU010_ID_A320A	0x03200000
++#define FTPMU010_ID_A320C	0x03200010
++#define FTPMU010_ID_A320D	0x03200030
++
++/*
++ * OSC Control Register
++ */
++#define FTPMU010_OSCC_OSCH_TRI		(1 << 11)
++#define FTPMU010_OSCC_OSCH_STABLE	(1 << 9)
++#define FTPMU010_OSCC_OSCH_OFF		(1 << 8)
++#define FTPMU010_OSCC_OSCL_TRI		(1 << 3)
++#define FTPMU010_OSCC_OSCL_RTCLSEL	(1 << 2)
++#define FTPMU010_OSCC_OSCL_STABLE	(1 << 1)
++#define FTPMU010_OSCC_OSCL_OFF		(1 << 0)
++
++/*
++ * Power Mode Register
++ */
++#define FTPMU010_PMODE_DIVAHBCLK_MASK	(0x7 << 4)
++#define FTPMU010_PMODE_DIVAHBCLK_2	(0x0 << 4)
++#define FTPMU010_PMODE_DIVAHBCLK_3	(0x1 << 4)
++#define FTPMU010_PMODE_DIVAHBCLK_4	(0x2 << 4)
++#define FTPMU010_PMODE_DIVAHBCLK_6	(0x3 << 4)
++#define FTPMU010_PMODE_DIVAHBCLK_8	(0x4 << 4)
++#define FTPMU010_PMODE_DIVAHBCLK(pmode)	(((pmode) >> 4) & 0x7)
++#define FTPMU010_PMODE_FCS		(1 << 2)
++#define FTPMU010_PMODE_TURBO		(1 << 1)
++#define FTPMU010_PMODE_SLEEP		(1 << 0)
++
++/*
++ * Power Manager Status Register
++ */
++#define FTPMU010_PMSR_SMR	(1 << 10)
++#define FTPMU010_PMSR_RDH	(1 << 2)
++#define FTPMU010_PMSR_PH	(1 << 1)
++#define FTPMU010_PMSR_CKEHLOW	(1 << 0)
++
++/*
++ * Multi-Function Port Setting Register
++ */
++#define FTPMU010_MFPSR_MODEMPINSEL	(1 << 14)
++#define FTPMU010_MFPSR_AC97CLKOUTSEL	(1 << 13)
++#define FTPMU010_MFPSR_AC97PINSEL	(1 << 3)
++
++/*
++ * PLL/DLL Control Register 0
++ */
++#define FTPMU010_PDLLCR0_HCLKOUTDIS(cr0)	(((cr0) >> 20) & 0xf)
++#define FTPMU010_PDLLCR0_DLLFRAG		(1 << 19)
++#define FTPMU010_PDLLCR0_DLLSTSEL		(1 << 18)
++#define FTPMU010_PDLLCR0_DLLSTABLE		(1 << 17)
++#define FTPMU010_PDLLCR0_DLLDIS			(1 << 16)
++#define FTPMU010_PDLLCR0_PLL1NS(cr0)		(((cr0) >> 3) & 0x1ff)
++#define FTPMU010_PDLLCR0_PLL1STSEL		(1 << 2)
++#define FTPMU010_PDLLCR0_PLL1STABLE		(1 << 1)
++#define FTPMU010_PDLLCR0_PLL1DIS		(1 << 0)
++
++/*
++ * PLL/DLL Control Register 1
++ */
++#define FTPMU010_PDLLCR1_PWMCLKDIV(x)		(((x) & 0xf) << 20)
++#define FTPMU010_PDLLCR1_PWMCLKDIV_OF(cr1)	(((cr1) >> 20) & 0xf)
++#define FTPMU010_PDLLCR1_I2SCLKDIV(x)		(((x) & 0xf) << 16)
++#define FTPMU010_PDLLCR1_I2SCLKDIV_OF(cr1)	(((cr1) >> 16) & 0xf)
++#define FTPMU010_PDLLCR1_PLL2STSEL		(1 << 10)
++#define FTPMU010_PDLLCR1_PLL2STABLE		(1 << 9)
++#define FTPMU010_PDLLCR1_PLL2DIS		(1 << 8)
++#define FTPMU010_PDLLCR1_PLL3STSEL		(1 << 2)
++#define FTPMU010_PDLLCR1_PLL3STABLE		(1 << 1)
++#define FTPMU010_PDLLCR1_PLL3DIS		(1 << 0)
++
++void ftpmu010_init(void __iomem *base);
++
++extern struct clk ftpmu010_main_clk;
++extern struct clk ftpmu010_cpuclk;
++extern struct clk ftpmu010_hclk;
++extern struct clk ftpmu010_pclk;
++extern struct clk ftpmu010_pll2_clk;
++extern struct clk ftpmu010_irda_clk;
++extern struct clk ftpmu010_pll3_clk;
++extern struct clk ftpmu010_ssp_clk;
++extern struct clk ftpmu010_i2s_clk;
++extern struct clk ftpmu010_ac97_clk1;
++extern struct clk ftpmu010_ac97_clk2;
++extern struct clk ftpmu010_uart_clk;
++extern struct clk ftpmu010_32768hz_clk;
++
++#endif	/* __FTPMU010_H */
+diff --git a/arch/arm/mach-faraday/include/mach/ftpwmtmr010.h b/arch/arm/mach-faraday/include/mach/ftpwmtmr010.h
+new file mode 100644
+index 00000000..55aef8e3
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftpwmtmr010.h
+@@ -0,0 +1,71 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftpwmtmr010.h
++ *
++ *  Faraday FTPWMTMR010 Timer
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTPWMTMR010_H
++#define __FTPWMTMR010_H
++
++#define FTPWMTMR010_OFFSET_INTSTAT	0x00
++#define FTPWMTMR010_OFFSET_TIMER(x)	((x) * 0x10)
++#define FTPWMTMR010_OFFSET_CTRL		0x00
++#define FTPWMTMR010_OFFSET_LOAD		0x04
++#define FTPWMTMR010_OFFSET_CMP		0x08
++#define FTPWMTMR010_OFFSET_CNT		0x0c
++
++/*
++ * Timer Control Register
++ */
++#define FTPWMTMR010_CTRL_SRC		(1 << 0)
++#define FTPWMTMR010_CTRL_START		(1 << 1)
++#define FTPWMTMR010_CTRL_UPDATE		(1 << 2)
++#define FTPWMTMR010_CTRL_OUT_INV	(1 << 3)
++#define FTPWMTMR010_CTRL_AUTO		(1 << 4)
++#define FTPWMTMR010_CTRL_INT_EN		(1 << 5)
++#define FTPWMTMR010_CTRL_INT_MODE	(1 << 6)
++#define FTPWMTMR010_CTRL_DMA_EN		(1 << 7)
++#define FTPWMTMR010_CTRL_PWM_EN		(1 << 8)
++#define FTPWMTMR010_CTRL_DZ(x)		(((x) & 0xff) << 24)
++
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++
++struct ftpwmtmr010_clockevent {
++	struct clock_event_device	clockevent;
++	struct irqaction		irqaction;
++	void __iomem			*base;
++	unsigned int			id;	/* one of 8 counters */
++	unsigned int			reload;
++	unsigned int			freq;
++};
++
++struct ftpwmtmr010_clocksource {
++	struct clocksource	clocksource;
++	void __iomem		*base;
++	unsigned int		id;	/* one of 8 counters */
++	unsigned int		freq;
++};
++
++void __init ftpwmtmr010_clockevent_init(struct ftpwmtmr010_clockevent *ftpwmtmr010);
++void __init ftpwmtmr010_clocksource_init(struct ftpwmtmr010_clocksource *ftpwmtmr010);
++
++#endif	/* __FTPWMTMR010_H */
+diff --git a/arch/arm/mach-faraday/include/mach/ftscu010.h b/arch/arm/mach-faraday/include/mach/ftscu010.h
+new file mode 100644
+index 00000000..c9925036
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/ftscu010.h
+@@ -0,0 +1,475 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/ftscu010.h
++ *
++ *  Faraday FTSCU010 System Control Unit
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTSCU010_H
++#define __FTSCU010_H
++
++#define FTSCU010_OFFSET_ID		0x00
++#define FTSCU010_OFFSET_VER		0x04
++#define FTSCU010_OFFSET_CSR		0x08
++#define FTSCU010_OFFSET_MFCR		0x0c
++#define FTSCU010_OFFSET_CR		0x10
++#define FTSCU010_OFFSET_SR		0x14
++#define FTSCU010_OFFSET_GPIO_SLEEP	0x18
++#define FTSCU010_OFFSET_OSCC		0x1c
++#define FTSCU010_OFFSET_PLL1CR		0x20
++#define FTSCU010_OFFSET_DLL		0x24
++#define FTSCU010_OFFSET_HCLKGATE	0x28
++#define FTSCU010_OFFSET_PCLKGATE	0x2c
++#define FTSCU010_OFFSET_SPR0		0x100
++#define FTSCU010_OFFSET_SPR1		0x104
++#define FTSCU010_OFFSET_SPR2		0x108
++#define FTSCU010_OFFSET_SPR3		0x10c
++#define FTSCU010_OFFSET_SPR4		0x110
++#define FTSCU010_OFFSET_SPR5		0x114
++#define FTSCU010_OFFSET_SPR6		0x118
++#define FTSCU010_OFFSET_SPR7		0x11c
++#define FTSCU010_OFFSET_SPR8		0x120
++#define FTSCU010_OFFSET_SPR9		0x124
++#define FTSCU010_OFFSET_SPR10		0x128
++#define FTSCU010_OFFSET_SPR11		0x12c
++#define FTSCU010_OFFSET_SPR12		0x130
++#define FTSCU010_OFFSET_SPR13		0x134
++#define FTSCU010_OFFSET_SPR14		0x138
++#define FTSCU010_OFFSET_SPR15		0x13c
++#define FTSCU010_OFFSET_GC		0x200
++#define FTSCU010_OFFSET_EXT_CS		0x204
++#define FTSCU010_OFFSET_DMAC0_REQ_CFG0	0x208
++#define FTSCU010_OFFSET_DMAC0_REQ_CFG1	0x20c
++#define FTSCU010_OFFSET_DMAC1_REQ_CFG0	0x210
++#define FTSCU010_OFFSET_DMAC1_REQ_CFG1	0x214
++#define FTSCU010_OFFSET_DMA_ACK_CFG0	0x218
++#define FTSCU010_OFFSET_DMA_ACK_CFG1	0x21c
++#define FTSCU010_OFFSET_DMA_ACK_CFG2	0x220
++#define FTSCU010_OFFSET_DMA_ACK_CFG3	0x224
++#define FTSCU010_OFFSET_SCLK_CFG0	0x228
++#define FTSCU010_OFFSET_SCLK_CFG1	0x22c
++#define FTSCU010_OFFSET_SCLK_EN		0x230
++#define FTSCU010_OFFSET_EDG_SYN_CTRL	0x234
++#define FTSCU010_OFFSET_MFPSR0		0x238
++#define FTSCU010_OFFSET_MFPSR1		0x23c
++#define FTSCU010_OFFSET_DCSRCR0		0x240
++#define FTSCU010_OFFSET_DCSRCR1		0x244
++#define FTSCU010_OFFSET_DBG_CFG		0x248
++#define FTSCU010_OFFSET_DLY_CTRL	0x254
++#define FTSCU010_OFFSET_PWR_CTRL	0x258
++#define FTSCU010_OFFSET_SATA_DBG	0x25c
++
++/*
++ * Configuration Strap Register
++ */
++#define FTSCU010_CSR_OSCH_CNT_DIS	(1 << 0)
++#define FTSCU010_CSR_PLL_DIS		(1 << 1)
++#define FTSCU010_CSR_DLL_DIS		(1 << 2)
++#define FTSCU010_CSR_CPU_M_FCLK(csr)	(((csr) >> 3) & 0x3)
++#define FTSCU010_CSR_PLL_NS(csr)	(((csr) >> 5) & 0x3f)
++
++/*
++ * PLL1 Control Register
++ */
++#define FTSCU010_PLL1CR_PLL_DIS		(1 << 0)
++#define FTSCU010_PLL1CR_PLL_STABLE	(1 << 1)
++#define FTSCU010_PLL1CR_PLL_NS(cr)	(((cr) >> 24) & 0x3f)
++
++/*
++ * AHB Module AHB Clock Gating Register
++ */
++#define FTSCU010_HCLKGATE_SCU		(1 << 0)
++#define FTSCU010_HCLKGATE_INTC0		(1 << 1)
++#define FTSCU010_HCLKGATE_INTC1		(1 << 2)
++#define FTSCU010_HCLKGATE_EMRAM0	(1 << 3)
++#define FTSCU010_HCLKGATE_EMRAM1	(1 << 4)
++#define FTSCU010_HCLKGATE_IDE		(1 << 5)
++#define FTSCU010_HCLKGATE_SDC0		(1 << 6)
++#define FTSCU010_HCLKGATE_SDC1		(1 << 7)
++#define FTSCU010_HCLKGATE_OTG		(1 << 8)
++#define FTSCU010_HCLKGATE_USBH		(1 << 9)
++#define FTSCU010_HCLKGATE_PCIE		(1 << 10)
++#define FTSCU010_HCLKGATE_SATAD		(1 << 11)
++#define FTSCU010_HCLKGATE_SATAH		(1 << 12)
++#define FTSCU010_HCLKGATE_GMAC		(1 << 13)
++#define FTSCU010_HCLKGATE_AES		(1 << 14)
++#define FTSCU010_HCLKGATE_ISP		(1 << 15)
++#define FTSCU010_HCLKGATE_LCDC		(1 << 16)
++#define FTSCU010_HCLKGATE_2DGE		(1 << 17)
++#define FTSCU010_HCLKGATE_MCP100	(1 << 18)
++#define FTSCU010_HCLKGATE_MCP220	(1 << 19)
++#define FTSCU010_HCLKGATE_DMAC0		(1 << 20)
++#define FTSCU010_HCLKGATE_DMAC1		(1 << 21)
++#define FTSCU010_HCLKGATE_SMC		(1 << 22)
++#define FTSCU010_HCLKGATE_NANDC		(1 << 23)
++#define FTSCU010_HCLKGATE_APBB		(1 << 24)
++#define FTSCU010_HCLKGATE_AHBC0		(1 << 25)
++#define FTSCU010_HCLKGATE_AHBC1		(1 << 26)
++#define FTSCU010_HCLKGATE_AHBC2		(1 << 27)
++#define FTSCU010_HCLKGATE_TS		(1 << 28)
++#define FTSCU010_HCLKGATE_CPU_S		(1 << 30)
++#define FTSCU010_HCLKGATE_CPU_M		(1 << 31)
++
++/*
++ * General Configuration Register
++ */
++#define FTSCU010_GC_SW_RST		(1 << 0)
++#define FTSCU010_GC_MASK_INTR0		(1 << 1)
++#define FTSCU010_GC_MASK_INTR1		(1 << 2)
++#define FTSCU010_GC_OTG_OSC_EN		(1 << 3)
++#define FTSCU010_GC_OTG_PLL_ALIVE	(1 << 4)
++#define FTSCU010_GC_USBH_OSC_EN		(1 << 5)
++#define FTSCU010_GC_USBH_PLL_ALIVE	(1 << 6)
++#define FTSCU010_GC_VDT_PD		(1 << 7)
++#define FTSCU010_GC_SATA_RSTN		(1 << 8)
++#define FTSCU010_GC_CPU_S_EXTAHB_RSTN	(1 << 11)
++#define FTSCU010_GC_IO_OUT_EN		(1 << 12)
++#define FTSCU010_GC_CS0_RELEASE		(1 << 13)
++#define FTSCU010_GC_EXT_IRQ_SRC		(1 << 14)
++#define FTSCU010_GC_GLB_CLK_SEL		(1 << 15)
++
++/*
++ * Extended Configuration Strap Register
++ */
++#define FTSCU010_EXT_CS_BOOT_MODE(csr)		(((csr) >> 0) & 0x3)
++#define FTSCU010_EXT_CS_CPU_MODE		(1 << 2)
++#define FTSCU010_EXT_CS_NAND_X16		(1 << 4)
++#define FTSCU010_EXT_CS_NAND_ADD_CYC(csr)	(((csr) >> 5) & 0x3)
++#define FTSCU010_EXT_CS_NAND_PSIZE(csr)		(((csr) >> 7) & 0x3)
++#define FTSCU010_EXT_CS_NAND_BSIZE(csr)		(((csr) >> 9) & 0x3)
++#define FTSCU010_EXT_CS_PCIE_MODE		(1 << 11)
++#define FTSCU010_EXT_CS_SATA_MODE		(1 << 12)
++#define FTSCU010_EXT_CS_DBG_BY_SW		(1 << 13)
++#define FTSCU010_EXT_CS_DBG_EN			(1 << 14)
++#define FTSCU010_EXT_CS_AST_EN			(1 << 15)
++
++/*
++ * DMAC0/1 Request Configuration Register 0/1
++ */
++#define FTSCU010_DMA_REQ_CFG_UART0TX	0x1
++#define FTSCU010_DMA_REQ_CFG_UART0RX	0x2
++#define FTSCU010_DMA_REQ_CFG_UART1TX	0x3
++#define FTSCU010_DMA_REQ_CFG_UART1RX	0x4
++#define FTSCU010_DMA_REQ_CFG_UART2TX	0x5
++#define FTSCU010_DMA_REQ_CFG_UART2RX	0x6
++#define FTSCU010_DMA_REQ_CFG_UART3TX	0x7
++#define FTSCU010_DMA_REQ_CFG_UART3RX	0x8
++#define FTSCU010_DMA_REQ_CFG_IRDA	0x9
++#define FTSCU010_DMA_REQ_CFG_SSP0TX	0xa
++#define FTSCU010_DMA_REQ_CFG_SSP0RX	0xb
++#define FTSCU010_DMA_REQ_CFG_SSP1TX	0xc
++#define FTSCU010_DMA_REQ_CFG_SSP1RX	0xd
++#define FTSCU010_DMA_REQ_CFG_TSC	0xe
++#define FTSCU010_DMA_REQ_CFG_TS		0xf
++#define FTSCU010_DMA_REQ_CFG_TMR1	0x10
++#define FTSCU010_DMA_REQ_CFG_TMR2	0x11
++#define FTSCU010_DMA_REQ_CFG_TMR3	0x12
++#define FTSCU010_DMA_REQ_CFG_TMR5	0x13
++#define FTSCU010_DMA_REQ_CFG_TMR6	0x14
++#define FTSCU010_DMA_REQ_CFG_TMR7	0x15
++
++/*
++ * DMAC0 Request Configuration Register 0
++ */
++#define FTSCU010_DMAC0_REQ_CFG0_HS3_SHIFT	0
++#define FTSCU010_DMAC0_REQ_CFG0_HS3_MASK	(0x1f << 0)
++#define FTSCU010_DMAC0_REQ_CFG0_HS4_SHIFT	8
++#define FTSCU010_DMAC0_REQ_CFG0_HS4_MASK	(0x1f << 8)
++#define FTSCU010_DMAC0_REQ_CFG0_HS5_SHIFT	16
++#define FTSCU010_DMAC0_REQ_CFG0_HS5_MASK	(0x1f << 16)
++#define FTSCU010_DMAC0_REQ_CFG0_HS6_SHIFT	24
++#define FTSCU010_DMAC0_REQ_CFG0_HS6_MASK	(0x1f << 24)
++
++/*
++ * DMAC0 Request Configuration Register 1
++ */
++#define FTSCU010_DMAC0_REQ_CFG1_HS0_SHIFT	8
++#define FTSCU010_DMAC0_REQ_CFG1_HS0_MASK	(0x1f << 8)
++#define FTSCU010_DMAC0_REQ_CFG1_HS1_SHIFT	16
++#define FTSCU010_DMAC0_REQ_CFG1_HS1_MASK	(0x1f << 16)
++#define FTSCU010_DMAC0_REQ_CFG1_HS2_SHIFT	24
++#define FTSCU010_DMAC0_REQ_CFG1_HS2_MASK	(0x1f << 24)
++
++/*
++ * DMAC1 Request Configuration Register 0
++ */
++#define FTSCU010_DMAC1_REQ_CFG0_HS3_SHIFT	0
++#define FTSCU010_DMAC1_REQ_CFG0_HS3_MASK	(0x1f << 0)
++#define FTSCU010_DMAC1_REQ_CFG0_HS4_SHIFT	8
++#define FTSCU010_DMAC1_REQ_CFG0_HS4_MASK	(0x1f << 8)
++#define FTSCU010_DMAC1_REQ_CFG0_HS5_SHIFT	16
++#define FTSCU010_DMAC1_REQ_CFG0_HS5_MASK	(0x1f << 16)
++#define FTSCU010_DMAC1_REQ_CFG0_HS6_SHIFT	24
++#define FTSCU010_DMAC1_REQ_CFG0_HS6_MASK	(0x1f << 24)
++
++/*
++ * DMAC1 Request Configuration Register 1
++ */
++#define FTSCU010_DMAC1_REQ_CFG1_HS0_SHIFT	8
++#define FTSCU010_DMAC1_REQ_CFG1_HS0_MASK	(0x1f << 8)
++#define FTSCU010_DMAC1_REQ_CFG1_HS1_SHIFT	16
++#define FTSCU010_DMAC1_REQ_CFG1_HS1_MASK	(0x1f << 16)
++#define FTSCU010_DMAC1_REQ_CFG1_HS2_SHIFT	24
++#define FTSCU010_DMAC1_REQ_CFG1_HS2_MASK	(0x1f << 24)
++
++/*
++ * DMA Acknowledge Configuration Register 0/1/2/3
++ */
++#define FTSCU010_DMA_ACK_CFG_SELECT_APBB	0
++#define FTSCU010_DMA_ACK_CFG_SELECT_DMAC0	1
++#define FTSCU010_DMA_ACK_CFG_SELECT_DMAC1	2
++
++/*
++ * DMA Acknowledge Configuration Register 0
++ */
++#define FTSCU010_DMA_ACK_CFG0_UART2RX_DMAC_HS_SHIFT	0
++#define FTSCU010_DMA_ACK_CFG0_UART2RX_DMAC_HS_MASK	(0x7 << 0)
++#define FTSCU010_DMA_ACK_CFG0_UART2RX_SELECT_SHIFT	3
++#define FTSCU010_DMA_ACK_CFG0_UART2RX_SELECT_MASK	(0x3 << 3)
++#define FTSCU010_DMA_ACK_CFG0_UART2TX_DMAC_HS_SHIFT	5
++#define FTSCU010_DMA_ACK_CFG0_UART2TX_DMAC_HS_MASK	(0x7 << 5)
++#define FTSCU010_DMA_ACK_CFG0_UART2TX_SELECT_SHIFT	8
++#define FTSCU010_DMA_ACK_CFG0_UART2TX_SELECT_MASK	(0x3 << 8)
++#define FTSCU010_DMA_ACK_CFG0_UART1RX_DMAC_HS_SHIFT	10
++#define FTSCU010_DMA_ACK_CFG0_UART1RX_DMAC_HS_MASK	(0x7 << 10)
++#define FTSCU010_DMA_ACK_CFG0_UART1RX_SELECT_SHIFT	13
++#define FTSCU010_DMA_ACK_CFG0_UART1RX_SELECT_MASK	(0x3 << 13)
++#define FTSCU010_DMA_ACK_CFG0_UART1TX_DMAC_HS_SHIFT	15
++#define FTSCU010_DMA_ACK_CFG0_UART1TX_DMAC_HS_MASK	(0x7 << 15)
++#define FTSCU010_DMA_ACK_CFG0_UART1TX_SELECT_SHIFT	18
++#define FTSCU010_DMA_ACK_CFG0_UART1TX_SELECT_MASK	(0x3 << 18)
++#define FTSCU010_DMA_ACK_CFG0_UART0RX_DMAC_HS_SHIFT	20
++#define FTSCU010_DMA_ACK_CFG0_UART0RX_DMAC_HS_MASK	(0x7 << 20)
++#define FTSCU010_DMA_ACK_CFG0_UART0RX_SELECT_SHIFT	23
++#define FTSCU010_DMA_ACK_CFG0_UART0RX_SELECT_MASK	(0x3 << 23)
++#define FTSCU010_DMA_ACK_CFG0_UART0TX_DMAC_HS_SHIFT	25
++#define FTSCU010_DMA_ACK_CFG0_UART0TX_DMAC_HS_MASK	(0x7 << 25)
++#define FTSCU010_DMA_ACK_CFG0_UART0TX_SELECT_SHIFT	28
++#define FTSCU010_DMA_ACK_CFG0_UART0TX_SELECT_MASK	(0x3 << 28)
++
++/*
++ * DMA Acknowledge Configuration Register 1
++ */
++#define FTSCU010_DMA_ACK_CFG1_IRDA_DMAC_HS_SHIFT	0
++#define FTSCU010_DMA_ACK_CFG1_IRDA_DMAC_HS_MASK		(0x7 << 0)
++#define FTSCU010_DMA_ACK_CFG1_IRDA_SELECT_SHIFT		3
++#define FTSCU010_DMA_ACK_CFG1_IRDA_SELECT_MASK		(0x3 << 3)
++#define FTSCU010_DMA_ACK_CFG1_UART3RX_DMAC_HS_SHIFT	5
++#define FTSCU010_DMA_ACK_CFG1_UART3RX_DMAC_HS_MASK	(0x7 << 5)
++#define FTSCU010_DMA_ACK_CFG1_UART3RX_SELECT_SHIFT	8
++#define FTSCU010_DMA_ACK_CFG1_UART3RX_SELECT_MASK	(0x3 << 8)
++#define FTSCU010_DMA_ACK_CFG1_UART3TX_DMAC_HS_SHIFT	10
++#define FTSCU010_DMA_ACK_CFG1_UART3TX_DMAC_HS_MASK	(0x7 << 10)
++#define FTSCU010_DMA_ACK_CFG1_UART3TX_SELECT_SHIFT	13
++#define FTSCU010_DMA_ACK_CFG1_UART3TX_SELECT_MASK	(0x3 << 13)
++
++/*
++ * DMA Acknowledge Configuration Register 2
++ */
++#define FTSCU010_DMA_ACK_CFG2_TS_DMAC_HS_SHIFT		0
++#define FTSCU010_DMA_ACK_CFG2_TS_DMAC_HS_MASK		(0x7 << 0)
++#define FTSCU010_DMA_ACK_CFG2_TS_SELECT_SHIFT		3
++#define FTSCU010_DMA_ACK_CFG2_TS_SELECT_MASK		(0x3 << 3)
++#define FTSCU010_DMA_ACK_CFG2_TSC_DMAC_HS_SHIFT		5
++#define FTSCU010_DMA_ACK_CFG2_TSC_DMAC_HS_MASK		(0x7 << 5)
++#define FTSCU010_DMA_ACK_CFG2_TSC_SELECT_SHIFT		8
++#define FTSCU010_DMA_ACK_CFG2_TSC_SELECT_MASK		(0x3 << 8)
++#define FTSCU010_DMA_ACK_CFG2_SSP1RX_DMAC_HS_SHIFT	10
++#define FTSCU010_DMA_ACK_CFG2_SSP1RX_DMAC_HS_MASK	(0x7 << 10)
++#define FTSCU010_DMA_ACK_CFG2_SSP1RX_SELECT_SHIFT	13
++#define FTSCU010_DMA_ACK_CFG2_SSP1RX_SELECT_MASK	(0x3 << 13)
++#define FTSCU010_DMA_ACK_CFG2_SSP1TX_DMAC_HS_SHIFT	15
++#define FTSCU010_DMA_ACK_CFG2_SSP1TX_DMAC_HS_MASK	(0x7 << 15)
++#define FTSCU010_DMA_ACK_CFG2_SSP1TX_SELECT_SHIFT	18
++#define FTSCU010_DMA_ACK_CFG2_SSP1TX_SELECT_MASK	(0x3 << 18)
++#define FTSCU010_DMA_ACK_CFG2_SSP0RX_DMAC_HS_SHIFT	20
++#define FTSCU010_DMA_ACK_CFG2_SSP0RX_DMAC_HS_MASK	(0x7 << 20)
++#define FTSCU010_DMA_ACK_CFG2_SSP0RX_SELECT_SHIFT	23
++#define FTSCU010_DMA_ACK_CFG2_SSP0RX_SELECT_MASK	(0x3 << 23)
++#define FTSCU010_DMA_ACK_CFG2_SSP0TX_DMAC_HS_SHIFT	25
++#define FTSCU010_DMA_ACK_CFG2_SSP0TX_DMAC_HS_MASK	(0x7 << 25)
++#define FTSCU010_DMA_ACK_CFG2_SSP0TX_SELECT_SHIFT	28
++#define FTSCU010_DMA_ACK_CFG2_SSP0TX_SELECT_MASK	(0x3 << 28)
++
++/*
++ * DMA Acknowledge Configuration Register 3
++ */
++#define FTSCU010_DMA_ACK_CFG3_TMR7_DMAC_HS_SHIFT	0
++#define FTSCU010_DMA_ACK_CFG3_TMR7_DMAC_HS_MASK		(0x7 << 0)
++#define FTSCU010_DMA_ACK_CFG3_TMR7_SELECT_SHIFT		3
++#define FTSCU010_DMA_ACK_CFG3_TMR7_SELECT_MASK		(0x3 << 3)
++#define FTSCU010_DMA_ACK_CFG3_TMR6_DMAC_HS_SHIFT	5
++#define FTSCU010_DMA_ACK_CFG3_TMR6_DMAC_HS_MASK		(0x7 << 5)
++#define FTSCU010_DMA_ACK_CFG3_TMR6_SELECT_SHIFT		8
++#define FTSCU010_DMA_ACK_CFG3_TMR6_SELECT_MASK		(0x3 << 8)
++#define FTSCU010_DMA_ACK_CFG3_TMR5_DMAC_HS_SHIFT	10
++#define FTSCU010_DMA_ACK_CFG3_TMR5_DMAC_HS_MASK		(0x7 << 10)
++#define FTSCU010_DMA_ACK_CFG3_TMR5_SELECT_SHIFT		13
++#define FTSCU010_DMA_ACK_CFG3_TMR5_SELECT_MASK		(0x3 << 13)
++#define FTSCU010_DMA_ACK_CFG3_TMR3_DMAC_HS_SHIFT	15
++#define FTSCU010_DMA_ACK_CFG3_TMR3_DMAC_HS_MASK		(0x7 << 15)
++#define FTSCU010_DMA_ACK_CFG3_TMR3_SELECT_SHIFT		18
++#define FTSCU010_DMA_ACK_CFG3_TMR3_SELECT_MASK		(0x3 << 18)
++#define FTSCU010_DMA_ACK_CFG3_TMR2_DMAC_HS_SHIFT	20
++#define FTSCU010_DMA_ACK_CFG3_TMR2_DMAC_HS_MASK		(0x7 << 20)
++#define FTSCU010_DMA_ACK_CFG3_TMR2_SELECT_SHIFT		23
++#define FTSCU010_DMA_ACK_CFG3_TMR2_SELECT_MASK		(0x3 << 23)
++#define FTSCU010_DMA_ACK_CFG3_TMR1_DMAC_HS_SHIFT	25
++#define FTSCU010_DMA_ACK_CFG3_TMR1_DMAC_HS_MASK		(0x7 << 25)
++#define FTSCU010_DMA_ACK_CFG3_TMR1_SELECT_SHIFT		28
++#define FTSCU010_DMA_ACK_CFG3_TMR1_SELECT_MASK		(0x3 << 28)
++
++/*
++ * Special Clock Configuration Register 0
++ */
++#define FTSCU010_SCLK_CFG0_LCD_SEL_MASK		(0x3 << 0)
++#define FTSCU010_SCLK_CFG0_LCD_SEL_133MHz	(0x0 << 0)
++#define FTSCU010_SCLK_CFG0_LCD_SEL_66MHz	(0x1 << 0)
++#define FTSCU010_SCLK_CFG0_LCD_SEL_EXT		(0x2 << 0)
++#define FTSCU010_SCLK_CFG0_LCD_SCK_SEL_MASK	(0x3 << 2)
++#define FTSCU010_SCLK_CFG0_LCD_SCK_SEL_133MHz	(0x0 << 2)
++#define FTSCU010_SCLK_CFG0_LCD_SCK_SEL_66MHz	(0x1 << 2)
++#define FTSCU010_SCLK_CFG0_LCD_SCK_SEL_EXT	(0x2 << 2)
++#define FTSCU010_SCLK_CFG0_EXTAHB_FQ_MASK	(0xf << 4)
++#define FTSCU010_SCLK_CFG0_EXTAHB_FQ_SHIFT	4
++#define FTSCU010_SCLK_CFG0_IDE_FQ_MASK		(0xf << 8)
++#define FTSCU010_SCLK_CFG0_ISP_ACK_FQ_MASK	(0xf << 12)
++#define FTSCU010_SCLK_CFG0_ISP_BCK_FQ_MASK	(0xf << 16)
++#define FTSCU010_SCLK_CFG0_GMAC_PLL_N_MASK	(0x3f << 20)
++#define FTSCU010_SCLK_CFG0_GMAC_PLL_PDN		(1 << 26)
++#define FTSCU010_SCLK_CFG0_GMAC_PLL_DIS		(1 << 27)
++#define FTSCU010_SCLK_CFG0_SATA_PLL_PDN		(1 << 28)
++#define FTSCU010_SCLK_CFG0_SATA_SEL_25MHz	(1 << 29)
++
++/*
++ * Special Clock Configuration Register 1
++ */
++#define FTSCU010_SCLK_CFG1_SSP0_FQ_MASK		(0xf << 0)
++#define FTSCU010_SCLK_CFG1_SSP0_SEL		(1 << 4)
++#define FTSCU010_SCLK_CFG1_SSP1_FQ_MASK		(0xf << 8)
++#define FTSCU010_SCLK_CFG1_SSP1_SEL		(1 << 12)
++#define FTSCU010_SCLK_CFG1_SD0_SEL_MASK		(0x3 << 16)
++#define FTSCU010_SCLK_CFG1_SD0_SEL_266MHz	(0x0 << 16)
++#define FTSCU010_SCLK_CFG1_SD0_SEL_177MHz	(0x1 << 16)
++#define FTSCU010_SCLK_CFG1_SD0_SEL_133MHz	(0x2 << 16)
++#define FTSCU010_SCLK_CFG1_SD1_SEL_MASK		(0x3 << 18)
++#define FTSCU010_SCLK_CFG1_SD1_SEL_266MHz	(0x0 << 18)
++#define FTSCU010_SCLK_CFG1_SD1_SEL_177MHz	(0x1 << 18)
++#define FTSCU010_SCLK_CFG1_SD1_SEL_133MHz	(0x2 << 18)
++#define FTSCU010_SCLK_CFG1_UART3_SEL		(1 << 20)
++#define FTSCU010_SCLK_CFG1_TMR1_SEL		(1 << 24)
++#define FTSCU010_SCLK_CFG1_TMR2_SEL		(1 << 25)
++#define FTSCU010_SCLK_CFG1_TMR3_SEL		(1 << 26)
++#define FTSCU010_SCLK_CFG1_TMR4_SEL		(1 << 27)
++#define FTSCU010_SCLK_CFG1_TMR5_SEL		(1 << 28)
++#define FTSCU010_SCLK_CFG1_TMR6_SEL		(1 << 29)
++#define FTSCU010_SCLK_CFG1_TMR7_SEL		(1 << 30)
++#define FTSCU010_SCLK_CFG1_TMR8_SEL		(1 << 31)
++
++/*
++ * Multi-Function Pin Setting Register 0
++ */
++#define FTSCU010_MFPSR0_FGEXTAHB_EXTAHB		(0x0 << 0)
++#define FTSCU010_MFPSR0_FGEXTAHB_PERIPHERALS	(0x1 << 0)
++#define FTSCU010_MFPSR0_FGEXTAHB_MASK		(0x3 << 0)
++#define FTSCU010_MFPSR0_FGSATA_EXTAHB		(0x0 << 2)
++#define FTSCU010_MFPSR0_FGSATA_SATA		(0x1 << 2)
++#define FTSCU010_MFPSR0_FGSATA_EXTDMA		(0x2 << 2)
++#define FTSCU010_MFPSR0_FGSATA_MASK		(0x3 << 2)
++#define FTSCU010_MFPSR0_FGISP_EXTAHB		(0x0 << 4)
++#define FTSCU010_MFPSR0_FGISP_GPIO1		(0x1 << 4)
++#define FTSCU010_MFPSR0_FGISP_ISP		(0x2 << 4)
++#define FTSCU010_MFPSR0_FGISP_MASK		(0x3 << 4)
++#define FTSCU010_MFPSR0_FGTS_EXTAHB		(0x0 << 6)
++#define FTSCU010_MFPSR0_FGTS_GPIO0		(0x1 << 6)
++#define FTSCU010_MFPSR0_FGTS_TS			(0x2 << 6)
++#define FTSCU010_MFPSR0_FGTS_MASK		(0x3 << 6)
++#define FTSCU010_MFPSR0_FGLCD_LCD		(0x0 << 8)
++#define FTSCU010_MFPSR0_FGLCD_TV_MICE		(0x1 << 8)
++#define FTSCU010_MFPSR0_FGLCD_LCD_MICE		(0x2 << 8)
++#define FTSCU010_MFPSR0_FGLCD_MASK		(0x3 << 8)
++#define FTSCU010_MFPSR0_FGEBI_EBI		(0x0 << 10)
++#define FTSCU010_MFPSR0_FGEBI_IDE		(0x1 << 10)
++#define FTSCU010_MFPSR0_FGEBI_MASK		(0x3 << 10)
++
++/*
++ * Multi-Function Pin Setting Register 1
++ */
++#define FTSCU010_MFPSR1_FGUART1_EXTAHB		(0x0 << 0)
++#define FTSCU010_MFPSR1_FGUART1_GPIO0		(0x1 << 0)
++#define FTSCU010_MFPSR1_FGUART1_UART1		(0x2 << 0)
++#define FTSCU010_MFPSR1_FGUART1_MASK		(0x3 << 0)
++#define FTSCU010_MFPSR1_FGUART2_GPIO1		(0x0 << 2)
++#define FTSCU010_MFPSR1_FGUART2_PWM		(0x1 << 2)
++#define FTSCU010_MFPSR1_FGUART2_UART2		(0x2 << 2)
++#define FTSCU010_MFPSR1_FGUART2_MASK		(0x3 << 2)
++#define FTSCU010_MFPSR1_FGUART3_GPIO1		(0x0 << 4)
++#define FTSCU010_MFPSR1_FGUART3_UART3		(0x2 << 4)
++#define FTSCU010_MFPSR1_FGUART3_MASK		(0x3 << 4)
++#define FTSCU010_MFPSR1_FGSSP0_SSP0		(0x0 << 6)
++#define FTSCU010_MFPSR1_FGSSP0_SATA		(0x1 << 6)
++#define FTSCU010_MFPSR1_FGSSP0_SICE		(0x2 << 6)
++#define FTSCU010_MFPSR1_FGSSP0_MASK		(0x3 << 6)
++#define FTSCU010_MFPSR1_FGSSP1_GPIO1		(0x0 << 8)
++#define FTSCU010_MFPSR1_FGSSP1_I2C1		(0x1 << 8)
++#define FTSCU010_MFPSR1_FGSSP1_SSP1		(0x2 << 8)
++#define FTSCU010_MFPSR1_FGSSP1_MASK		(0x3 << 8)
++#define FTSCU010_MFPSR1_FGGMAC_GMAC		(0x0 << 10)
++#define FTSCU010_MFPSR1_FGGMAC_MCP_ICE		(0x1 << 10)
++#define FTSCU010_MFPSR1_FGGMAC_MASK		(0x3 << 10)
++#define FTSCU010_MFPSR1_FGPWM0_EXTAHB		(0x0 << 12)
++#define FTSCU010_MFPSR1_FGPWM0_PWM		(0x1 << 12)
++#define FTSCU010_MFPSR1_FGPWM0_EXTDMA		(0x2 << 12)
++#define FTSCU010_MFPSR1_FGPWM0_MASK		(0x3 << 12)
++#define FTSCU010_MFPSR1_FGPWM1_EXTAHB		(0x0 << 14)
++#define FTSCU010_MFPSR1_FGPWM1_GPIO1		(0x1 << 14)
++#define FTSCU010_MFPSR1_FGPWM1_PWM		(0x2 << 14)
++#define FTSCU010_MFPSR1_FGPWM1_MASK		(0x3 << 14)
++#define FTSCU010_MFPSR1_FGI2C1_EXTAHB		(0x0 << 16)
++#define FTSCU010_MFPSR1_FGI2C1_GPIO1		(0x1 << 16)
++#define FTSCU010_MFPSR1_FGI2C1_I2C1		(0x2 << 16)
++#define FTSCU010_MFPSR1_FGI2C1_MASK		(0x3 << 16)
++#define FTSCU010_MFPSR1_FGGPIO0_EXTAHB		(0x0 << 18)
++#define FTSCU010_MFPSR1_FGGPIO0_GPIO0		(0x1 << 18)
++#define FTSCU010_MFPSR1_FGGPIO0_EXTDMA		(0x2 << 18)
++#define FTSCU010_MFPSR1_FGGPIO0_MASK		(0x3 << 18)
++#define FTSCU010_MFPSR1_FGKBC_EXTAHB		(0x0 << 20)
++#define FTSCU010_MFPSR1_FGKBC_GPIO0		(0x1 << 20)
++#define FTSCU010_MFPSR1_FGKBC_KBC		(0x2 << 20)
++#define FTSCU010_MFPSR1_FGKBC_MASK		(0x3 << 20)
++
++void ftscu010_init(void __iomem *base);
++int ftscu010_pinmux_setup(const char *fgname, const char *select);
++int ftscu010_handshake_alloc(const char *name);
++int ftscu010_handshake_setup(unsigned int handshake, int which);
++int ftscu010_handshake_free(unsigned int handshake);
++
++extern struct clk ftscu010_main_clk;
++extern struct clk ftscu010_pll_clk;
++extern struct clk ftscu010_dclk;
++extern struct clk ftscu010_mclk;
++extern struct clk ftscu010_hclk;
++extern struct clk ftscu010_pclk;
++extern struct clk ftscu010_extahb_clk;
++extern struct clk ftscu010_mcpu_clk;
++extern struct clk ftscu010_scpu_clk;
++extern struct clk ftscu010_ssp0_extclk;
++extern struct clk ftscu010_tsc_clk;
++
++#endif	/* __FTSCU010_H */
+diff --git a/arch/arm/mach-faraday/include/mach/fttmr010.h b/arch/arm/mach-faraday/include/mach/fttmr010.h
+new file mode 100644
+index 00000000..cb982e5f
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/fttmr010.h
+@@ -0,0 +1,88 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/fttmr010.h
++ *
++ *  Faraday FTTMR010 Timer
++ *
++ *  Copyright (C) 2009 Faraday Technology
++ *  Copyright (C) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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
++ */
++
++#ifndef __FTTMR010_H
++#define __FTTMR010_H
++
++#define FTTMR010_OFFSET_COUNTER		0x00
++#define FTTMR010_OFFSET_LOAD		0x04
++#define FTTMR010_OFFSET_MATCH1		0x08
++#define FTTMR010_OFFSET_MATCH2		0x0c
++#define FTTMR010_OFFSET_TIMER(x)	((x) * 0x10)
++#define FTTMR010_OFFSET_CR		0x30
++#define FTTMR010_OFFSET_INTR_STATE	0x34
++#define FTTMR010_OFFSET_INTR_MASK	0x38
++
++/*
++ * Timer Control Register
++ */
++#define FTTMR010_TM3_UPDOWN	(1 << 11)
++#define FTTMR010_TM2_UPDOWN	(1 << 10)
++#define FTTMR010_TM1_UPDOWN	(1 << 9)
++#define FTTMR010_TM3_OFENABLE	(1 << 8)
++#define FTTMR010_TM3_CLOCK	(1 << 7)
++#define FTTMR010_TM3_ENABLE	(1 << 6)
++#define FTTMR010_TM2_OFENABLE	(1 << 5)
++#define FTTMR010_TM2_CLOCK	(1 << 4)
++#define FTTMR010_TM2_ENABLE	(1 << 3)
++#define FTTMR010_TM1_OFENABLE	(1 << 2)
++#define FTTMR010_TM1_CLOCK	(1 << 1)
++#define FTTMR010_TM1_ENABLE	(1 << 0)
++
++/*
++ * Timer Interrupt State & Mask Registers
++ */
++#define FTTMR010_TM3_OVERFLOW	(1 << 8)
++#define FTTMR010_TM3_MATCH2	(1 << 7)
++#define FTTMR010_TM3_MATCH1	(1 << 6)
++#define FTTMR010_TM2_OVERFLOW	(1 << 5)
++#define FTTMR010_TM2_MATCH2	(1 << 4)
++#define FTTMR010_TM2_MATCH1	(1 << 3)
++#define FTTMR010_TM1_OVERFLOW	(1 << 2)
++#define FTTMR010_TM1_MATCH2	(1 << 1)
++#define FTTMR010_TM1_MATCH1	(1 << 0)
++
++#include <linux/interrupt.h>
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++
++struct fttmr010_clockevent {
++	struct clock_event_device	clockevent;
++	struct irqaction		irqaction;
++	void __iomem			*base;
++	unsigned int			id;	/* one of 3 counters */
++	unsigned int			reload;
++	unsigned int			freq;
++};
++
++struct fttmr010_clocksource {
++	struct clocksource	clocksource;
++	void __iomem		*base;
++	unsigned int		id;	/* one of 3 counters */
++	unsigned int		freq;
++};
++
++void __init fttmr010_clockevent_init(struct fttmr010_clockevent *fttmr010);
++void __init fttmr010_clocksource_init(struct fttmr010_clocksource *fttmr010);
++
++#endif	/* __FTTMR010_H */
+diff --git a/arch/arm/mach-faraday/include/mach/hardware.h b/arch/arm/mach-faraday/include/mach/hardware.h
+new file mode 100644
+index 00000000..cd3c7737
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/hardware.h
+@@ -0,0 +1,38 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/hardware.h
++ *
++ *  This file contains the hardware definitions of the Faraday boards.
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_H
++#define __ASM_ARCH_HARDWARE_H
++
++#ifndef PCIBIOS_MIN_IO
++/* the mini io address is 0x6000,that is IO will allocate from 0-0x6000 offset*/
++#define PCIBIOS_MIN_IO	0x0
++#endif
++
++#ifndef PCIBIOS_MIN_MEM
++/* the mini MEM address is 0x100000,that is MEM will allocate from 0-0x100000 offset*/
++#define PCIBIOS_MIN_MEM	0x0
++#endif
++
++#define pcibios_assign_all_busses()	1
++
++#endif /* __ASM_ARCH_HARDWARE_H */
+diff --git a/arch/arm/mach-faraday/include/mach/io.h b/arch/arm/mach-faraday/include/mach/io.h
+new file mode 100644
+index 00000000..2e35c0a9
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/io.h
+@@ -0,0 +1,29 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/io.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT      0xffffffff
++
++#define __io(a)		__typesafe_io(a)
++#define __mem_pci(a)	(a)
++
++#endif /* __ASM_ARM_ARCH_IO_H */
+diff --git a/arch/arm/mach-faraday/include/mach/irqs-a320.h b/arch/arm/mach-faraday/include/mach/irqs-a320.h
+new file mode 100644
+index 00000000..4bdc352e
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/irqs-a320.h
+@@ -0,0 +1,103 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/irqs-a320.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_IRQS_A320_H
++#define __MACH_IRQS_A320_H
++
++#ifdef CONFIG_PLATFORM_A320
++
++/*
++ * Interrupt numbers of Hierarchical Architecture
++ */
++
++#ifdef CONFIG_CPU_FMP626
++
++/* GIC DIST in FMP626 */
++#define IRQ_LOCALTIMER		29
++#define IRQ_LOCALWDOG		30
++#define PLATFORM_LEGACY_IRQ	31
++#define IRQ_FMP626_GIC_START	32
++
++#define IRQ_FMP626_PMU_CPU0	(IRQ_FMP626_GIC_START + 17)
++#define IRQ_FMP626_PMU_CPU1	(IRQ_FMP626_GIC_START + 18)
++#define IRQ_FMP626_PMU_SCU0	(IRQ_FMP626_GIC_START + 21)
++#define IRQ_FMP626_PMU_SCU1	(IRQ_FMP626_GIC_START + 22)
++#define IRQ_FMP626_PMU_SCU2	(IRQ_FMP626_GIC_START + 23)
++#define IRQ_FMP626_PMU_SCU3	(IRQ_FMP626_GIC_START + 24)
++
++#define IRQ_A320_START	256	/* this is determined by irqs supported by GIC */
++
++#else	/* CONFIG_CPU_FMP626 */
++
++#define IRQ_A320_START	0
++
++#endif	/* CONFIG_CPU_FMP626 */
++
++#define IRQ_A320_FTCFC010_0_CD		(IRQ_A320_START + 0)
++#define IRQ_A320_FTCFC010_0_DMA		(IRQ_A320_START + 1)
++#define IRQ_A320_FTI2C010_0		(IRQ_A320_START + 3)
++#define IRQ_A320_FTSDC010_0		(IRQ_A320_START + 5)
++#define IRQ_A320_FTSSP010_0		(IRQ_A320_START + 6)
++#define IRQ_A320_FTUART010_2		(IRQ_A320_START + 7)
++#define IRQ_A320_FTPMU010_0		(IRQ_A320_START + 8)
++#define IRQ_A320_FTUART010_0		(IRQ_A320_START + 10)
++#define IRQ_A320_FTUART010_1		(IRQ_A320_START + 11)
++#define IRQ_A320_FTGPIO010_0		(IRQ_A320_START + 13)
++#define IRQ_A320_FTTMR010_0_T1		(IRQ_A320_START + 14)
++#define IRQ_A320_FTTMR010_0_T2		(IRQ_A320_START + 15)
++#define IRQ_A320_FTWDT010_0		(IRQ_A320_START + 16)
++#define IRQ_A320_FTRTC010_0_ALRM	(IRQ_A320_START + 17)
++#define IRQ_A320_FTRTC010_0_SEC		(IRQ_A320_START + 18)
++#define IRQ_A320_FTTMR010_0_T0		(IRQ_A320_START + 19)
++#define IRQ_A320_FTLCDC100_0		(IRQ_A320_START + 20)
++#define IRQ_A320_FTDMAC020_0		(IRQ_A320_START + 21)
++#define IRQ_A320_FTAPBB020_0		(IRQ_A320_START + 24)
++#define IRQ_A320_FTMAC100_0		(IRQ_A320_START + 25)
++#define IRQ_A320_FUSB220_0		(IRQ_A320_START + 26)
++#define IRQ_A320_FTSDC020_0		(IRQ_A320_START + 29)
++#define IRQ_A320_FTNANDC020_0		(IRQ_A320_START + 29)
++#define IRQ_A320_FOTG2XX_0		(IRQ_A320_START + 29)
++#define IRQ_A320_FUSBH200_0		(IRQ_A320_START + 29)
++#define IRQ_A320_A321			(IRQ_A320_START + 30)
++
++/* A321 */
++#define IRQ_A321_START			(IRQ_A320_START + 32)
++
++#define IRQ_A321_FTKBC010_0		(IRQ_A321_START + 4)
++#define IRQ_A321_FTKBC010_1		(IRQ_A321_START + 9)
++#define IRQ_A321_FTAPBB020_0		(IRQ_A321_START + 24)
++#define IRQ_A321_FTMAC100_0		(IRQ_A321_START + 25)
++#define IRQ_A321_FTPCI100_0		(IRQ_A321_START + 28)
++
++/* PCIC */
++#define IRQ_FTPCI100_0_START		(IRQ_A321_START + 32)
++
++#define IRQ_FTPCI100_0_A		(IRQ_FTPCI100_0_START + 0)
++#define IRQ_FTPCI100_0_B		(IRQ_FTPCI100_0_START + 1)
++#define IRQ_FTPCI100_0_C		(IRQ_FTPCI100_0_START + 2)
++#define IRQ_FTPCI100_0_D		(IRQ_FTPCI100_0_START + 3)
++
++#define NR_IRQS				(IRQ_FTPCI100_0_START + 4)
++
++#define MAX_FTINTC010_NR	2
++
++#endif	/* CONFIG_PLATFORM_A320 */
++
++#endif	/* __MACH_IRQS_A320_H */
+diff --git a/arch/arm/mach-faraday/include/mach/irqs-a369.h b/arch/arm/mach-faraday/include/mach/irqs-a369.h
+new file mode 100644
+index 00000000..7b300ae1
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/irqs-a369.h
+@@ -0,0 +1,117 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/irqs-a369.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_IRQS_A369_H
++#define __MACH_IRQS_A369_H
++
++#ifdef CONFIG_PLATFORM_A369
++
++/*
++ * Interrupt numbers of Hierarchical Architecture
++ */
++
++#ifdef CONFIG_CPU_FMP626
++
++/* GIC DIST in FMP626 */
++#define IRQ_LOCALTIMER		29
++#define IRQ_LOCALWDOG		30
++#define PLATFORM_LEGACY_IRQ	31
++#define IRQ_FMP626_GIC_START	32
++
++#define IRQ_FMP626_PMU_CPU0	(IRQ_FMP626_GIC_START + 17)
++#define IRQ_FMP626_PMU_CPU1	(IRQ_FMP626_GIC_START + 18)
++#define IRQ_FMP626_PMU_SCU0	(IRQ_FMP626_GIC_START + 21)
++#define IRQ_FMP626_PMU_SCU1	(IRQ_FMP626_GIC_START + 22)
++#define IRQ_FMP626_PMU_SCU2	(IRQ_FMP626_GIC_START + 23)
++#define IRQ_FMP626_PMU_SCU3	(IRQ_FMP626_GIC_START + 24)
++
++#define IRQ_A369_START	256	/* this is determined by irqs supported by GIC */
++
++#else	/* CONFIG_CPU_FMP626 */
++
++#define IRQ_A369_START	0
++
++#endif	/* CONFIG_CPU_FMP626 */
++
++#define IRQ_A369_FTPWMTMR010_0_T0	(IRQ_A369_START + 8)
++#define IRQ_A369_FTPWMTMR010_0_T1	(IRQ_A369_START + 9)
++#define IRQ_A369_FTPWMTMR010_0_T2	(IRQ_A369_START + 10)
++#define IRQ_A369_FTPWMTMR010_0_T3	(IRQ_A369_START + 11)
++#define IRQ_A369_FTDDRII030_0		(IRQ_A369_START + 12)
++#define IRQ_A369_FTAHBB020_3		(IRQ_A369_START + 13)
++#define IRQ_A369_FTAPBB020_0		(IRQ_A369_START + 14)
++#define IRQ_A369_FTDMAC020_0_TC		(IRQ_A369_START + 15)
++#define IRQ_A369_FTDMAC020_0_ERR	(IRQ_A369_START + 16)
++#define IRQ_A369_FTDMAC020_1_TC		(IRQ_A369_START + 17)
++#define IRQ_A369_FTDMAC020_1_ERR	(IRQ_A369_START + 18)
++#define IRQ_A369_FTTSC010_0_ADC		(IRQ_A369_START + 19)
++#define IRQ_A369_FTTSC010_0_PANEL	(IRQ_A369_START + 20)
++#define IRQ_A369_FTKBC010_0		(IRQ_A369_START + 21)
++#define IRQ_A369_FTLCDC200_0_MERR	(IRQ_A369_START + 22)
++#define IRQ_A369_FTLCDC200_0_FUR	(IRQ_A369_START + 23)
++#define IRQ_A369_FTLCDC200_0_BAUPD	(IRQ_A369_START + 24)
++#define IRQ_A369_FTLCDC200_0_VSTATUS	(IRQ_A369_START + 25)
++#define IRQ_A369_FTMCP100_0		(IRQ_A369_START + 27)
++#define IRQ_A369_FTMCP220_0		(IRQ_A369_START + 28)
++#define IRQ_A369_FTNANDC021_0		(IRQ_A369_START + 30)
++#define IRQ_A369_FTAES020_0		(IRQ_A369_START + 31)
++#define IRQ_A369_FTGMAC100_0_IRQ	(IRQ_A369_START + 32)
++#define IRQ_A369_FTSATA100_0		(IRQ_A369_START + 33)
++#define IRQ_A369_FTSATA110_0		(IRQ_A369_START + 34)
++#define IRQ_A369_FTPCIE3914_0		(IRQ_A369_START + 35)
++#define IRQ_A369_FUSBH200_0		(IRQ_A369_START + 36)
++#define IRQ_A369_FOTG2XX_0		(IRQ_A369_START + 37)
++#define IRQ_A369_FTSDC010_0		(IRQ_A369_START + 38)
++#define IRQ_A369_FTSDC010_1		(IRQ_A369_START + 39)
++#define IRQ_A369_FTIDE020_0		(IRQ_A369_START + 40)
++#define IRQ_A369_FTSCU010_0		(IRQ_A369_START + 41)
++#define IRQ_A369_FTRTC011_0_ALRM	(IRQ_A369_START + 42)
++#define IRQ_A369_FTRTC011_0_SEC		(IRQ_A369_START + 43)
++#define IRQ_A369_FTRTC011_0_MIN		(IRQ_A369_START + 44)
++#define IRQ_A369_FTRTC011_0_HOUR	(IRQ_A369_START + 45)
++#define IRQ_A369_FTWDT010_0		(IRQ_A369_START + 46)
++#define IRQ_A369_FTGPIO010_0		(IRQ_A369_START + 47)
++#define IRQ_A369_FTGPIO010_1		(IRQ_A369_START + 48)
++#define IRQ_A369_FTSSP010_0		(IRQ_A369_START + 49)
++#define IRQ_A369_FTSSP010_1		(IRQ_A369_START + 50)
++#define IRQ_A369_FTIIC010_0		(IRQ_A369_START + 51)
++#define IRQ_A369_FTIIC010_1		(IRQ_A369_START + 52)
++#define IRQ_A369_FTUART010_0		(IRQ_A369_START + 53)
++#define IRQ_A369_FTUART010_1		(IRQ_A369_START + 54)
++#define IRQ_A369_FTUART010_2		(IRQ_A369_START + 55)
++#define IRQ_A369_FTUART010_3		(IRQ_A369_START + 56)
++
++/* AHBB */
++#define IRQ_FTAHBB020_3_START		(IRQ_A369_START + 64)
++#define IRQ_FTAHBB020_3_EXINT(x)	(IRQ_FTAHBB020_3_START + (x))
++
++/* PCI */
++#define IRQ_FTPCIE3914_0_START		(IRQ_FTAHBB020_3_START + 32)
++
++#define IRQ_FTPCIE3914_0_A		(IRQ_FTPCIE3914_0_START + 0)
++#define IRQ_FTPCIE3914_0_B		(IRQ_FTPCIE3914_0_START + 1)
++#define IRQ_FTPCIE3914_0_C		(IRQ_FTPCIE3914_0_START + 2)
++#define IRQ_FTPCIE3914_0_D		(IRQ_FTPCIE3914_0_START + 3)
++
++#define NR_IRQS				(IRQ_FTPCIE3914_0_START + 4)
++
++#endif	/* CONFIG_PLATFORM_A369 */
++
++#endif	/* __MACH_IRQS_A369_H */
+diff --git a/arch/arm/mach-faraday/include/mach/irqs-axi.h b/arch/arm/mach-faraday/include/mach/irqs-axi.h
+new file mode 100644
+index 00000000..b0e7458e
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/irqs-axi.h
+@@ -0,0 +1,46 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/irqs-axi.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_IRQS_AXI_H
++#define __MACH_IRQS_AXI_H
++
++#ifdef CONFIG_PLATFORM_AXI
++
++/*
++ * Interrupt numbers of Hierarchical Architecture
++ */
++
++#define IRQ_AXI_START	0
++
++#define IRQ_AXI_FTTMR010_0_T0	(IRQ_AXI_START + 1)
++#define IRQ_AXI_FTTMR010_0_T1	(IRQ_AXI_START + 2)
++#define IRQ_AXI_FTTMR010_0_T2	(IRQ_AXI_START + 3)
++#define IRQ_AXI_FTUART010_0	(IRQ_AXI_START + 4)
++#define IRQ_AXI_FTUART010_1	(IRQ_AXI_START + 5)
++
++#define IRQ_AXI_FTDMAC030_0_INT	(IRQ_AXI_START + 11)
++#define IRQ_AXI_FTDMAC030_0_TC	(IRQ_AXI_START + 12)
++#define IRQ_AXI_FTDMAC030_0_ERR	(IRQ_AXI_START + 13)
++
++#define NR_IRQS			(IRQ_AXI_START + 32)
++
++#endif	/* CONFIG_PLATFORM_AXI */
++
++#endif	/* __MACH_IRQS_AXI_H */
+diff --git a/arch/arm/mach-faraday/include/mach/irqs.h b/arch/arm/mach-faraday/include/mach/irqs.h
+new file mode 100644
+index 00000000..4e0b6e92
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/irqs.h
+@@ -0,0 +1,32 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/irqs.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_IRQS_H
++#define __MACH_IRQS_H
++
++#include <mach/irqs-a320.h>
++#include <mach/irqs-a369.h>
++#include <mach/irqs-axi.h>
++
++#ifndef NR_IRQS
++#error "NR_IRQS not defined by the board-specific files"
++#endif
++
++#endif /* __MACH_IRQS_H */
+diff --git a/arch/arm/mach-faraday/include/mach/memory-axi.h b/arch/arm/mach-faraday/include/mach/memory-axi.h
+new file mode 100644
+index 00000000..88435851
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/memory-axi.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/memory-axi.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_MEMORY_AXI_H
++#define __MACH_MEMORY_AXI_H
++
++#ifdef CONFIG_PLATFORM_AXI
++
++#define PHYS_OFFSET	UL(0x00000000)
++#define MEM_SIZE	SZ_256M
++
++#endif	/* CONFIG_PLATFORM_AXI */
++
++#endif	/* __MACH_MEMORY_AXI_H */
+diff --git a/arch/arm/mach-faraday/include/mach/serial-a320.h b/arch/arm/mach-faraday/include/mach/serial-a320.h
+new file mode 100644
+index 00000000..ebed8c1d
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/serial-a320.h
+@@ -0,0 +1,36 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/serial-a320.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_SERIAL_A320_H
++#define __MACH_SERIAL_A320_H
++
++#ifdef CONFIG_PLATFORM_A320
++
++#include <mach/board-a320.h>
++#include <mach/irqs-a320.h>
++
++#define SERIAL_PORT_DFNS									\
++	FTUART010_SERIAL_PORT(A320_FTUART010_0_VA_BASE, IRQ_A320_FTUART010_0),	/* ttyS0 */	\
++	FTUART010_SERIAL_PORT(A320_FTUART010_1_VA_BASE, IRQ_A320_FTUART010_1),	/* ttyS1 */	\
++	FTUART010_SERIAL_PORT(A320_FTUART010_2_VA_BASE, IRQ_A320_FTUART010_2),	/* ttyS2 */
++
++#endif	/* CONFIG_PLATFORM_A320 */
++
++#endif	/* __MACH_SERIAL_A320_H */
+diff --git a/arch/arm/mach-faraday/include/mach/serial-a369.h b/arch/arm/mach-faraday/include/mach/serial-a369.h
+new file mode 100644
+index 00000000..198a6f30
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/serial-a369.h
+@@ -0,0 +1,37 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/serial-a369.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_SERIAL_A369_H
++#define __MACH_SERIAL_A369_H
++
++#ifdef CONFIG_PLATFORM_A369
++
++#include <mach/board-a369.h>
++#include <mach/irqs-a369.h>
++
++#define SERIAL_PORT_DFNS									\
++	FTUART010_SERIAL_PORT(A369_FTUART010_0_VA_BASE, IRQ_A369_FTUART010_0),	/* ttyS0 */	\
++	FTUART010_SERIAL_PORT(A369_FTUART010_1_VA_BASE, IRQ_A369_FTUART010_1),	/* ttyS1 */	\
++	FTUART010_SERIAL_PORT(A369_FTUART010_2_VA_BASE, IRQ_A369_FTUART010_2),	/* ttyS2 */	\
++	FTUART010_SERIAL_PORT(A369_FTUART010_3_VA_BASE, IRQ_A369_FTUART010_3),	/* ttyS3 */
++
++#endif	/* CONFIG_PLATFORM_A369 */
++
++#endif	/* __MACH_SERIAL_A369_H */
+diff --git a/arch/arm/mach-faraday/include/mach/serial-axi.h b/arch/arm/mach-faraday/include/mach/serial-axi.h
+new file mode 100644
+index 00000000..de46430b
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/serial-axi.h
+@@ -0,0 +1,35 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/serial-axi.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_SERIAL_AXI_H
++#define __MACH_SERIAL_AXI_H
++
++#ifdef CONFIG_PLATFORM_AXI
++
++#include <mach/board-axi.h>
++#include <mach/irqs-axi.h>
++
++#define SERIAL_PORT_DFNS									\
++	FTUART010_SERIAL_PORT(AXI_FTUART010_0_VA_BASE, IRQ_AXI_FTUART010_0),	/* ttyS0 */	\
++	FTUART010_SERIAL_PORT(AXI_FTUART010_1_VA_BASE, IRQ_AXI_FTUART010_1),	/* ttyS1 */
++
++#endif	/* CONFIG_PLATFORM_AXI */
++
++#endif	/* __MACH_SERIAL_AXI_H */
+diff --git a/arch/arm/mach-faraday/include/mach/serial.h b/arch/arm/mach-faraday/include/mach/serial.h
+new file mode 100644
+index 00000000..ba8868a5
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/serial.h
+@@ -0,0 +1,54 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/serial.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_SERIAL_H
++#define __ASM_ARCH_SERIAL_H
++
++#ifndef __ASSEMBLY__
++#include <linux/serial.h>
++
++/*
++ * We use a 18.432MHz clock rather than typical 1.8432 MHz clock for UART.
++ */
++#define UART_CLK	18432000
++
++#define BASE_BAUD	(UART_CLK / 16)
++#define STD_COM_FLAGS	(UPF_BOOT_AUTOCONF)
++
++#define FTUART010_SERIAL_PORT(_port, _irq)	{	\
++		.baud_base	= BASE_BAUD,		\
++		.port		= (_port),		\
++		.irq		= (_irq),		\
++		.flags		= STD_COM_FLAGS,	\
++		.io_type	= UPIO_PORT,		\
++		.iomem_reg_shift= 2,			\
++	}
++
++#endif	/* __ASSEMBLY__ */
++
++#define SERIAL_THR	0x00
++#define SERIAL_LSR	0x14
++#define SERIAL_LSR_THRE	0x20
++
++#include <mach/serial-a320.h>
++#include <mach/serial-a369.h>
++#include <mach/serial-axi.h>
++
++#endif /* __ASM_ARCH_SERIAL_H */
+diff --git a/arch/arm/mach-faraday/include/mach/smp.h b/arch/arm/mach-faraday/include/mach/smp.h
+new file mode 100644
+index 00000000..f68d71c2
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/smp.h
+@@ -0,0 +1,15 @@
++#ifndef ASMARM_ARCH_SMP_H
++#define ASMARM_ARCH_SMP_H
++
++
++#include <asm/hardware/gic.h>
++
++/*
++ * We use IRQ1 as the IPI
++ */
++static inline void smp_cross_call(const struct cpumask *mask, int ipi)
++{
++	gic_raise_softirq(mask, ipi);
++}
++
++#endif
+diff --git a/arch/arm/mach-faraday/include/mach/system.h b/arch/arm/mach-faraday/include/mach/system.h
+new file mode 100644
+index 00000000..bd00664c
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/system.h
+@@ -0,0 +1,31 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/system.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_SYSTEM_H
++#define __ASM_ARCH_SYSTEM_H
++
++#include <asm/proc-fns.h>
++
++static inline void arch_idle(void)
++{
++	cpu_do_idle();
++}
++
++#endif /* __ASM_ARCH_SYSTEM_H */
+diff --git a/arch/arm/mach-faraday/include/mach/timex-a320.h b/arch/arm/mach-faraday/include/mach/timex-a320.h
+new file mode 100644
+index 00000000..63c14269
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/timex-a320.h
+@@ -0,0 +1,30 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/timex-a320.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_TIMEX_A320_H
++#define __MACH_TIMEX_A320_H
++
++#ifdef CONFIG_PLATFORM_A320
++
++#define CLOCK_TICK_RATE	16588800
++
++#endif	/* CONFIG_PLATFORM_A320 */
++
++#endif	/* __MACH_TIMEX_A320_H */
+diff --git a/arch/arm/mach-faraday/include/mach/timex-a369.h b/arch/arm/mach-faraday/include/mach/timex-a369.h
+new file mode 100644
+index 00000000..e0f33ee1
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/timex-a369.h
+@@ -0,0 +1,30 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/timex-a369.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_TIMEX_A369_H
++#define __MACH_TIMEX_A369_H
++
++#ifdef CONFIG_PLATFORM_A369
++
++#define CLOCK_TICK_RATE	66000000
++
++#endif	/* CONFIG_PLATFORM_A369 */
++
++#endif	/* __MACH_TIMEX_A369_H */
+diff --git a/arch/arm/mach-faraday/include/mach/timex-axi.h b/arch/arm/mach-faraday/include/mach/timex-axi.h
+new file mode 100644
+index 00000000..11136bd5
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/timex-axi.h
+@@ -0,0 +1,30 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/timex-axi.h
++ *
++ *  Copyright (C) 2010 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __MACH_TIMEX_AXI_H
++#define __MACH_TIMEX_AXI_H
++
++#ifdef CONFIG_PLATFORM_AXI
++
++#define CLOCK_TICK_RATE	18000000
++
++#endif	/* CONFIG_PLATFORM_AXI */
++
++#endif	/* __MACH_TIMEX_AXI_H */
+diff --git a/arch/arm/mach-faraday/include/mach/timex.h b/arch/arm/mach-faraday/include/mach/timex.h
+new file mode 100644
+index 00000000..c5c0e9c4
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/timex.h
+@@ -0,0 +1,28 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/timex.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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
++ */
++
++#ifndef __ASM_ARCH_TIMEX_H
++#define __ASM_ARCH_TIMEX_H
++
++#include <mach/timex-a320.h>
++#include <mach/timex-a369.h>
++#include <mach/timex-axi.h>
++
++#endif /* __ASM_ARCH_TIMEX_H */
+diff --git a/arch/arm/mach-faraday/include/mach/uncompress.h b/arch/arm/mach-faraday/include/mach/uncompress.h
+new file mode 100644
+index 00000000..2a54ee04
+--- /dev/null
++++ b/arch/arm/mach-faraday/include/mach/uncompress.h
+@@ -0,0 +1,51 @@
++/*
++ *  arch/arm/mach-faraday/include/mach/uncompress.h
++ *
++ *  Copyright (C) 2005 Faraday Technology
++ *
++ * 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 <mach/serial.h>
++
++#include <mach/board-a320.h>
++#include <mach/board-a369.h>
++#include <mach/board-axi.h>
++
++#define readl(a)	(*(volatile unsigned int *)(a))
++#define writel(v,a)	(*(volatile unsigned int *)(a) = (v))
++
++/*
++ * This does not append a newline
++ */
++static inline void putc(int c)
++{
++	unsigned long base = DEBUG_LL_FTUART010_PA_BASE;
++
++	while ((readl(base + SERIAL_LSR) & SERIAL_LSR_THRE) == 0)
++		barrier();
++
++	writel(c, base + SERIAL_THR);
++}
++
++static inline void flush(void)
++{
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
+diff --git a/arch/arm/mach-faraday/localtimer.c b/arch/arm/mach-faraday/localtimer.c
+new file mode 100644
+index 00000000..aca29ce2
+--- /dev/null
++++ b/arch/arm/mach-faraday/localtimer.c
+@@ -0,0 +1,27 @@
++/*
++ *  linux/arch/arm/mach-realview/localtimer.c
++ *
++ *  Copyright (C) 2002 ARM Ltd.
++ *  All Rights Reserved
++ *
++ * 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 <linux/init.h>
++#include <linux/smp.h>
++#include <linux/clockchips.h>
++
++#include <asm/irq.h>
++#include <asm/smp_twd.h>
++#include <asm/localtimer.h>
++
++/*
++ * Setup the local clock events for a CPU.
++ */
++int __cpuinit local_timer_setup(struct clock_event_device *evt)
++{
++	evt->irq = IRQ_LOCALTIMER;
++	twd_timer_setup(evt);
++	return 0;
++}
+diff --git a/arch/arm/mach-faraday/platsmp.c b/arch/arm/mach-faraday/platsmp.c
+new file mode 100644
+index 00000000..f68698c5
+--- /dev/null
++++ b/arch/arm/mach-faraday/platsmp.c
+@@ -0,0 +1,168 @@
++/*
++ *  linux/arch/arm/mach-realview/platsmp.c
++ *
++ *  Copyright (C) 2002 ARM Ltd.
++ *  All Rights Reserved
++ *
++ * 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 <linux/init.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/jiffies.h>
++#include <linux/smp.h>
++#include <linux/io.h>
++
++#include <asm/cacheflush.h>
++#include <mach/hardware.h>
++#include <asm/hardware/gic.h>
++#include <asm/mach-types.h>
++#include <asm/smp_scu.h>
++#include <asm/smp_plat.h>
++
++#include <mach/board-a320.h>
++#include <mach/board-a369.h>
++
++#include "core.h"
++
++extern void platform_secondary_startup(void);
++
++/*
++ * control for which core is the next to come out of the secondary
++ * boot "holding pen"
++ */
++volatile int __cpuinitdata pen_release = -1;
++
++/*
++ * Write pen_release in a way that is guaranteed to be visible to all
++ * observers, irrespective of whether they're taking part in coherency
++ * or not.  This is necessary for the hotplug code to work reliably.
++ */
++static void __cpuinit write_pen_release(int val)
++{
++	pen_release = val;
++	smp_wmb();
++	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
++	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
++}
++
++static void __iomem *scu_base_addr(void)
++{
++	return __io(PLATFORM_SCU_VA_BASE);
++}
++
++static DEFINE_SPINLOCK(boot_lock);
++
++void __cpuinit platform_secondary_init(unsigned int cpu)
++{
++	/*
++	 * if any interrupts are already enabled for the primary
++	 * core (e.g. timer irq), then they will not have been enabled
++	 * for us: do so
++	 */
++	gic_secondary_init(0);
++
++	/*
++	 * let the primary processor know we're out of the
++	 * pen, then head off into the C entry point
++	 */
++	write_pen_release(-1);
++
++	/*
++	 * Synchronise with the boot thread.
++	 */
++	spin_lock(&boot_lock);
++	spin_unlock(&boot_lock);
++}
++
++int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++	unsigned long timeout;
++
++	/*
++	 * set synchronisation state between this boot processor
++	 * and the secondary one
++	 */
++	spin_lock(&boot_lock);
++
++	/*
++	 * The secondary processor is waiting to be released from
++	 * the holding pen - release it, then wait for it to flag
++	 * that it has been released by resetting pen_release.
++	 *
++	 * Note that "pen_release" is the hardware CPU ID, whereas
++	 * "cpu" is Linux's internal ID.
++	 */
++	write_pen_release(cpu_logical_map(cpu));
++
++	/*
++	 * Send the secondary CPU a soft interrupt, thereby causing
++	 * the boot monitor to read the system wide flags register,
++	 * and branch to the address found there.
++	 */
++	gic_raise_softirq(cpumask_of(cpu), 1);
++
++	timeout = jiffies + (1 * HZ);
++	while (time_before(jiffies, timeout)) {
++		smp_rmb();
++		if (pen_release == -1)
++			break;
++
++		udelay(10);
++	}
++
++	/*
++	 * now the secondary core is starting up let it run its
++	 * calibrations, then wait for it to finish
++	 */
++	spin_unlock(&boot_lock);
++
++	return pen_release != -1 ? -ENOSYS : 0;
++}
++
++/*
++ * Initialise the CPU possible map early - this describes the CPUs
++ * which may be present or become present in the system.
++ */
++void __init smp_init_cpus(void)
++{
++	void __iomem *scu_base = scu_base_addr();
++	unsigned int i, ncores;
++
++	ncores = scu_base ? scu_get_core_count(scu_base) : 1;
++
++	/* sanity check */
++	if (ncores > nr_cpu_ids) {
++		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
++			ncores, nr_cpu_ids);
++		ncores = nr_cpu_ids;
++	}
++
++	for (i = 0; i < ncores; i++)
++		set_cpu_possible(i, true);
++
++	set_smp_cross_call(gic_raise_softirq);
++
++#ifdef CONFIG_ACP
++	/* Always enable SCU if we are using ACP */
++	scu_enable(scu_base);
++#endif
++}
++
++void __init platform_smp_prepare_cpus(unsigned int max_cpus)
++{
++	scu_enable(scu_base_addr());
++
++	/*
++	 * Write the address of secondary startup into the
++	 * system-wide flags register. The BootMonitor waits
++	 * until it receives a soft interrupt, and then the
++	 * secondary CPU branches to this address.
++	 */
++#define SYS_FLAGSS_OFFSET	0xfd0
++	__raw_writel(virt_to_phys(platform_secondary_startup),
++		     PLATFORM_GIC_DIST_VA_BASE + SYS_FLAGSS_OFFSET);
++}
+diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
+index 7edef912..ccab06e8 100644
+--- a/arch/arm/mm/Kconfig
++++ b/arch/arm/mm/Kconfig
+@@ -142,6 +142,65 @@ config CPU_ARM922T
+ 	  Say Y if you want support for the ARM922T processor.
+ 	  Otherwise, say N.
+ 
++# FA626TE
++config CPU_FA626TE
++	bool  "Support FA626TE processor" if ARCH_FARADAY || ARCH_GM || ARCH_GM_DUO
++	select CPU_32v5
++	select CPU_ABRT_EV5T
++	select CPU_PABRT_LEGACY
++	select CPU_CACHE_FA
++	select CPU_CACHE_VIPT
++	select CPU_CP15_MMU
++	select CPU_COPY_FA if MMU
++	select CPU_TLB_FA if MMU
++
++# Faraday FMP626
++config CPU_FMP626
++	bool "Support FMP626 processor" if ARCH_FARADAY
++	select CPU_32v5
++	select CPU_ABRT_EV5T
++	select CPU_PABRT_LEGACY
++	select CPU_CACHE_VIPT
++	select CPU_CP15_MMU
++	select CPU_COPY_FA if MMU
++	select CPU_TLB_FA if MMU
++
++# FA726TE
++config CPU_FA726TE
++	bool "Support FA726TE processor" if ARCH_FARADAY || ARCH_GM || ARCH_GM_DUO
++	select CPU_32v5
++	select CPU_ABRT_EV5T
++	select CPU_PABRT_LEGACY
++	select CPU_CACHE_VIPT
++	select CPU_CP15_MMU
++	select CPU_COPY_V4WB if MMU
++	select CPU_TLB_V4WBI if MMU
++	help
++	  Say Y if you want support for the FA726TE processor.
++	  Otherwise, say N.
++
++# ARM Cortex-A9
++config CPU_CA9
++	bool "Support ARM Cortex-A9 processor" if ARCH_FARADAY || ARCH_GM || ARCH_GM_SMP
++	select CPU_V7
++	select ARM_ERRATA_764369 if SMP
++	select MIGHT_HAVE_CACHE_L2X0
++
++	help
++	  Say Y if you want support for the ARM Cortex-A9 processor.
++	  Otherwise, say N.
++
++# ARM Cortex-A7
++config CPU_CA7
++	bool "Support ARM Cortex-A7 processor" if ARCH_FARADAY || ARCH_GM || ARCH_GM_SMP
++	select CPU_V7
++	select ARM_ERRATA_764369 if SMP
++	select MIGHT_HAVE_CACHE_L2X0
++
++	help
++	  Say Y if you want support for the ARM Cortex-A7 processor.
++	  Otherwise, say N.
++
+ # ARM925T
+ config CPU_ARM925T
+  	bool "Support ARM925T processor" if ARCH_OMAP1
+@@ -163,7 +222,7 @@ config CPU_ARM925T
+ 
+ # ARM926T
+ config CPU_ARM926T
+-	bool "Support ARM926T processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
++	bool "Support ARM926T processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_FARADAY || ARCH_GM || ARCH_GM_DUO
+ 	select CPU_32v5
+ 	select CPU_ABRT_EV5TJ
+ 	select CPU_PABRT_LEGACY
+@@ -181,6 +240,7 @@ config CPU_ARM926T
+ 
+ # FA526
+ config CPU_FA526
++	bool  "Support FA526 processor" if ARCH_FARADAY
+ 	bool
+ 	select CPU_32v4
+ 	select CPU_ABRT_EV4
+@@ -451,8 +511,9 @@ config CPU_32v4T
+ 
+ config CPU_32v5
+ 	bool
+-	select TLS_REG_EMUL if SMP || !MMU
+-	select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
++	select TLS_REG_EMUL if (SMP || !MMU ) && !CPU_FMP626
++	select NEEDS_SYSCALL_FOR_CMPXCHG if SMP && !CPU_FMP626
++
+ 	select CPU_USE_DOMAINS if MMU
+ 
+ config CPU_32v6
+@@ -649,7 +710,7 @@ config ARCH_DMA_ADDR_T_64BIT
+ 
+ config ARM_THUMB
+ 	bool "Support Thumb user binaries"
+-	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || CPU_V7 || CPU_FEROCEON
++	depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_V6 || CPU_V6K || CPU_V7 || CPU_FEROCEON || CPU_FA626TE || CPU_FA726TE || CPU_FMP626
+ 	default y
+ 	help
+ 	  Say Y if you want to include kernel support for running user space
+@@ -758,7 +819,7 @@ config CPU_DCACHE_SIZE
+ 
+ config CPU_DCACHE_WRITETHROUGH
+ 	bool "Force write through D-cache"
+-	depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FA526) && !CPU_DCACHE_DISABLE
++	depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FA526 || CPU_FA626TE || CPU_FMP626 || CPU_FA726TE) && !CPU_DCACHE_DISABLE
+ 	default y if CPU_ARM925T
+ 	help
+ 	  Say Y here to use the data cache in writethrough mode. Unless you
+@@ -766,17 +827,26 @@ config CPU_DCACHE_WRITETHROUGH
+ 
+ config CPU_CACHE_ROUND_ROBIN
+ 	bool "Round robin I and D cache replacement algorithm"
+-	depends on (CPU_ARM926T || CPU_ARM946E || CPU_ARM1020) && (!CPU_ICACHE_DISABLE || !CPU_DCACHE_DISABLE)
++	depends on (CPU_ARM926T || CPU_FA726TE || CPU_ARM946E || CPU_ARM1020) && (!CPU_ICACHE_DISABLE || !CPU_DCACHE_DISABLE)
+ 	help
+ 	  Say Y here to use the predictable round-robin cache replacement
+ 	  policy.  Unless you specifically require this or are unsure, say N.
+ 
+ config CPU_BPREDICT_DISABLE
+ 	bool "Disable branch prediction"
+-	depends on CPU_ARM1020 || CPU_V6 || CPU_V6K || CPU_MOHAWK || CPU_XSC3 || CPU_V7 || CPU_FA526
++	depends on CPU_ARM1020 || CPU_V6 || CPU_V6K || CPU_MOHAWK || CPU_XSC3 || CPU_V7 || CPU_FA526 || CPU_FA626TE
+ 	help
+ 	  Say Y here to disable branch prediction.  If unsure, say N.
+ 
++config CPU_FA526_IDLE_FIXUP
++	bool "Bug fix for idle on old revisions of FA526"
++	default y
++	depends on CPU_FA526 && PLATFORM_A320
++	help
++	  On old revisions of FA526, when cpu is awaken from idle (wait for
++	  interrupt) instruction, program counter still points to the idle
++	  instruction. Thus it will never be awaken.
++
+ config TLS_REG_EMUL
+ 	bool
+ 	help
+@@ -856,6 +926,23 @@ config CACHE_L2X0
+ 	help
+ 	  This option enables the L2x0 PrimeCell.
+ 
++config MIGHT_HAVE_CACHE_FTL2CC031
++	bool
++	help
++	  This option should be selected by machines which have a
++	  FTL2CC031 cache controller, but where its use is optional.
++
++	  The only effect of this option is to make CACHE_FTL2CC031
++	  and related options available to the user for configuration.
++
++config CACHE_FTL2CC031
++	bool "Enable GM FTL2CC031 L2 cache controller" if ARCH_GM
++	default MIGHT_HAVE_CACHE_FTL2CC031
++	select OUTER_CACHE
++	select OUTER_CACHE_SYNC
++	help
++	  This option enables the GM Level2 cache controller.
++
+ config CACHE_PL310
+ 	bool
+ 	depends on CACHE_L2X0
+diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
+index bca7e619..a411d4b0 100644
+--- a/arch/arm/mm/Makefile
++++ b/arch/arm/mm/Makefile
+@@ -79,6 +79,9 @@ obj-$(CONFIG_CPU_ARM926T)	+= proc-arm926.o
+ obj-$(CONFIG_CPU_ARM940T)	+= proc-arm940.o
+ obj-$(CONFIG_CPU_ARM946E)	+= proc-arm946.o
+ obj-$(CONFIG_CPU_FA526)		+= proc-fa526.o
++obj-$(CONFIG_CPU_FA626TE)	+= proc-fa626te.o
++obj-$(CONFIG_CPU_FMP626)	+= proc-fmp626.o
++obj-$(CONFIG_CPU_FA726TE)	+= proc-fa726te.o
+ obj-$(CONFIG_CPU_ARM1020)	+= proc-arm1020.o
+ obj-$(CONFIG_CPU_ARM1020E)	+= proc-arm1020e.o
+ obj-$(CONFIG_CPU_ARM1022)	+= proc-arm1022.o
+@@ -92,6 +95,7 @@ obj-$(CONFIG_CPU_FEROCEON)	+= proc-feroceon.o
+ obj-$(CONFIG_CPU_V6)		+= proc-v6.o
+ obj-$(CONFIG_CPU_V6K)		+= proc-v6.o
+ obj-$(CONFIG_CPU_V7)		+= proc-v7.o
++obj-$(CONFIG_PLATFORM_GM8210)	+= proc-fa726te.o cache-fa.o proc-fa626te.o copypage-fa.o tlb-fa.o copypage-v4wb.o tlb-v4wbi.o
+ 
+ AFLAGS_proc-v6.o	:=-Wa,-march=armv6
+ AFLAGS_proc-v7.o	:=-Wa,-march=armv7-a
+@@ -100,3 +104,4 @@ obj-$(CONFIG_CACHE_FEROCEON_L2)	+= cache-feroceon-l2.o
+ obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
+ obj-$(CONFIG_CACHE_XSC3L2)	+= cache-xsc3l2.o
+ obj-$(CONFIG_CACHE_TAUROS2)	+= cache-tauros2.o
++obj-$(CONFIG_CACHE_FTL2CC031)	+= cache-ftl2cc031.o
+diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S
+index a0908d46..4a09a443 100644
+--- a/arch/arm/mm/abort-ev5t.S
++++ b/arch/arm/mm/abort-ev5t.S
+@@ -17,6 +17,9 @@
+  */
+ 	.align	5
+ ENTRY(v5t_early_abort)
++#ifdef CONFIG_CPU_FMP626
++	cdp	p13, 0, c0, c0, c0, 2		@ Clear exclusive monitor
++#endif
+ 	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+ 	do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3
+diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S
+index ff1f7cc1..80741992 100644
+--- a/arch/arm/mm/abort-ev6.S
++++ b/arch/arm/mm/abort-ev6.S
+@@ -26,18 +26,23 @@ ENTRY(v6_early_abort)
+ 	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+ /*
+- * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR (erratum 326103).
+- * The test below covers all the write situations, including Java bytecodes
++ * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR.
+  */
+-	bic	r1, r1, #1 << 11		@ clear bit 11 of FSR
++#ifdef CONFIG_ARM_ERRATA_326103
++	ldr	ip, =0x4107b36
++	mrc	p15, 0, r3, c0, c0, 0		@ get processor id
++	teq	ip, r3, lsr #4			@ r0 ARM1136?
++	bne	do_DataAbort
+ 	tst	r5, #PSR_J_BIT			@ Java?
++	tsteq	r5, #PSR_T_BIT			@ Thumb?
+ 	bne	do_DataAbort
+-	do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3
+-	ldreq	r3, [r4]			@ read aborted ARM instruction
++	bic	r1, r1, #1 << 11		@ clear bit 11 of FSR
++	ldr	r3, [r4]			@ read aborted ARM instruction
+ #ifdef CONFIG_CPU_ENDIAN_BE8
+-	reveq	r3, r3
++	rev	r3, r3
+ #endif
+ 	do_ldrd_abort tmp=ip, insn=r3
+ 	tst	r3, #1 << 20			@ L = 0 -> write
+ 	orreq	r1, r1, #1 << 11		@ yes.
++#endif
+ 	b	do_DataAbort
+diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
+index caf14dc0..89011b84 100644
+--- a/arch/arm/mm/alignment.c
++++ b/arch/arm/mm/alignment.c
+@@ -26,7 +26,7 @@
+ #include <asm/unaligned.h>
+ 
+ #include "fault.h"
+-
++#include <linux/kallsyms.h>
+ /*
+  * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
+  * /proc/sys/debug/alignment, modified and integrated into
+@@ -760,6 +760,12 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ 
+ 	instrptr = instruction_pointer(regs);
+ 
++#if 0 //(defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO))
++        printk(KERN_DEBUG "Warning, unalignment program (0x%x) with load/store"
++              " at 0x%x is captured, fsr(0x%x) ", (u32)instrptr, (u32)addr, fsr & 0xF);
++        print_symbol(KERN_DEBUG "from (%s)\n", instrptr);
++#endif
++
+ 	fs = get_fs();
+ 	set_fs(KERNEL_DS);
+ 	if (thumb_mode(regs)) {
+diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S
+index 07201637..746a870d 100644
+--- a/arch/arm/mm/cache-fa.S
++++ b/arch/arm/mm/cache-fa.S
+@@ -23,7 +23,7 @@
+ /*
+  * The size of one data cache line.
+  */
+-#define CACHE_DLINESIZE	16
++#define CACHE_DLINESIZE	32
+ 
+ /*
+  * The total size of the data cache.
+diff --git a/arch/arm/mm/cache-ftl2cc031.c b/arch/arm/mm/cache-ftl2cc031.c
+new file mode 100644
+index 00000000..e3f180ff
+--- /dev/null
++++ b/arch/arm/mm/cache-ftl2cc031.c
+@@ -0,0 +1,359 @@
++/*
++ * arch/arm/mm/cache-ftl2cc031.c - FTL2CC031 cache controller support
++ *
++ * Copyright (C) 2010-2012 Faraday Corp. Limited
++ *
++ * 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.
++ *
++ * 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 <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/interrupt.h>
++#include <asm/cacheflush.h>
++#include <asm/hardware/cache-ftl2cc031.h>
++#include <mach/platform/board.h>
++
++#define CACHE_LINE_SIZE		32
++#define MAX_LINE_COUNT		1024	//b[9:0]
++
++static void __iomem *l2x0_base;
++static DEFINE_RAW_SPINLOCK(l2x0_lock);
++static uint32_t l2x0_way_mask;	/* Bitmask of active ways */
++static uint32_t l2x0_size;
++
++static irqreturn_t l2cache_handle_irq(int irq, void *dev_id);
++
++static inline void flib_cache_wait(void __iomem *reg, unsigned long mask)
++{
++	/* wait for cache operation by line or way to complete */
++	while (readl_relaxed(reg) & mask)
++		cpu_relax();
++}
++
++static inline void flib_cache_sync(void)
++{
++	void __iomem *base = l2x0_base;
++	writel_relaxed(L2X0_CACHE_SYNC, base + L2X0_CACHE_MAINTENANCE);
++	flib_cache_wait(base + L2X0_CACHE_MAINTENANCE, L2X0_CACHE_SYNC);
++}
++
++static inline void fa_l2x0_clean_PA(unsigned long addr, unsigned long line_cnt)
++{
++	void __iomem *base = l2x0_base;
++	if (line_cnt == 0)
++		return;
++
++	writel_relaxed(line_cnt-1, base + L2X0_CACHE_MAINTENAN_CNT);
++	writel_relaxed(addr, base + L2X0_CACHE_MAINTENAN_PA);
++	writel_relaxed(L2X0_CLEAN_PA, base + L2X0_CACHE_MAINTENANCE);
++	flib_cache_wait(base + L2X0_CACHE_MAINTENANCE, L2X0_CLEAN_PA);
++}
++
++static inline void fa_l2x0_inv_PA(unsigned long addr, unsigned long line_cnt)
++{
++	void __iomem *base = l2x0_base;
++	if (line_cnt == 0)
++		return;
++
++	writel_relaxed(line_cnt-1, base + L2X0_CACHE_MAINTENAN_CNT);
++	writel_relaxed(addr, base + L2X0_CACHE_MAINTENAN_PA);
++	writel_relaxed(L2X0_INV_PA, base + L2X0_CACHE_MAINTENANCE);
++	flib_cache_wait(base + L2X0_CACHE_MAINTENANCE, L2X0_INV_PA);
++}
++
++#define fa_l2x0_set_debug	NULL
++
++static inline void fa_l2x0_flush_PA(unsigned long addr, unsigned long line_cnt)
++{
++	void __iomem *base = l2x0_base;
++	if (line_cnt == 0)
++		return;
++
++	writel_relaxed(line_cnt-1, base + L2X0_CACHE_MAINTENAN_CNT);
++	writel_relaxed(addr, base + L2X0_CACHE_MAINTENAN_PA);
++	writel_relaxed(L2X0_CLEAN_INV_PA, base + L2X0_CACHE_MAINTENANCE);
++	flib_cache_wait(base + L2X0_CACHE_MAINTENANCE, L2X0_CLEAN_INV_PA);
++}
++
++///////////////////////////////////////////////////////////////////
++static void fa_l2x0_cache_sync(void)
++{
++	unsigned long flags;
++
++	raw_spin_lock_irqsave(&l2x0_lock, flags);
++	flib_cache_sync();
++	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
++}
++
++
++static void __fa_l2x0_flush_all(void)
++{
++	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_WAY_IDX);
++	writel_relaxed(L2X0_CLEAN_INV_WAY, l2x0_base + L2X0_CACHE_MAINTENANCE);
++	flib_cache_wait(l2x0_base + L2X0_CACHE_MAINTENANCE, L2X0_CLEAN_INV_WAY);
++	//flib_cache_sync();
++}
++
++static void fa_l2x0_flush_all(void)
++{
++	unsigned long flags;
++
++	/* clean and invalid all ways */
++	raw_spin_lock_irqsave(&l2x0_lock, flags);
++	__fa_l2x0_flush_all();
++	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
++}
++
++static void fa_l2x0_clean_all(void)
++{
++	unsigned long flags;
++
++	/* clean all ways */
++	raw_spin_lock_irqsave(&l2x0_lock, flags);
++	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_WAY_IDX);
++	writel_relaxed(L2X0_CLEAN_WAY, l2x0_base + L2X0_CACHE_MAINTENANCE);
++	flib_cache_wait(l2x0_base + L2X0_CACHE_MAINTENANCE, L2X0_CLEAN_WAY);
++	flib_cache_sync();
++	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
++}
++
++static void fa_l2x0_inv_all(void)
++{
++	unsigned long flags;
++
++	/* invalidate all ways */
++	raw_spin_lock_irqsave(&l2x0_lock, flags);
++	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_WAY_IDX);
++	writel_relaxed(L2X0_INV_WAY, l2x0_base + L2X0_CACHE_MAINTENANCE);
++	flib_cache_wait(l2x0_base + L2X0_CACHE_MAINTENANCE, L2X0_INV_WAY);
++	//flib_cache_sync();
++	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
++}
++
++static void fa_l2x0_inv_range(unsigned long start, unsigned long end)
++{
++	unsigned long flags;
++	unsigned long cnt;
++
++//	printk("Faraday FTL2CC031 l2x0_invalid_range()\n");
++
++	raw_spin_lock_irqsave(&l2x0_lock, flags);
++	if (start & (CACHE_LINE_SIZE - 1)) {
++		start &= ~(CACHE_LINE_SIZE - 1);
++		fa_l2x0_flush_PA(start, 1);
++		start += CACHE_LINE_SIZE;
++	}
++
++	if (end & (CACHE_LINE_SIZE - 1)) {
++		end &= ~(CACHE_LINE_SIZE - 1);
++		fa_l2x0_flush_PA(end, 1);
++	}
++
++	cnt = (end + CACHE_LINE_SIZE -1 -start)/CACHE_LINE_SIZE;
++	if (cnt <= MAX_LINE_COUNT)
++		fa_l2x0_inv_PA(start, cnt);
++	else {
++		do {
++			fa_l2x0_inv_PA(start, MAX_LINE_COUNT);
++			start += (MAX_LINE_COUNT*CACHE_LINE_SIZE);
++			cnt -= MAX_LINE_COUNT;
++			if (cnt <= MAX_LINE_COUNT) {
++				fa_l2x0_inv_PA(start, cnt);
++				cnt = 0;
++			}
++		} while (cnt > 0);
++	}
++
++	//flib_cache_sync();
++	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
++}
++
++static void fa_l2x0_clean_range(unsigned long start, unsigned long end)
++{
++	unsigned long flags;
++	unsigned long cnt;
++
++//	printk("Faraday FTL2CC031 l2x0_clean_range()\n");
++
++	if ((end - start) >= l2x0_size) {
++		fa_l2x0_clean_all();
++		return;
++	}
++
++	raw_spin_lock_irqsave(&l2x0_lock, flags);
++	start &= ~(CACHE_LINE_SIZE - 1);
++	cnt = (end + CACHE_LINE_SIZE -1 -start)/CACHE_LINE_SIZE;
++	if (cnt <= MAX_LINE_COUNT)
++		fa_l2x0_clean_PA(start, cnt);
++	else {
++		do {
++			fa_l2x0_clean_PA(start, MAX_LINE_COUNT);
++			start += (MAX_LINE_COUNT*CACHE_LINE_SIZE);
++			cnt -= MAX_LINE_COUNT;
++			if (cnt <= MAX_LINE_COUNT) {
++				fa_l2x0_clean_PA(start, cnt);
++				cnt = 0;
++			}
++		} while (cnt > 0);
++	}
++
++	//flib_cache_sync();
++	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
++}
++
++static void fa_l2x0_flush_range(unsigned long start, unsigned long end)
++{
++	unsigned long flags;
++	unsigned long cnt;
++
++//	printk("Faraday FTL2CC031 l2x0_flush_range()\n");
++
++	if ((end - start) >= l2x0_size) {
++		fa_l2x0_flush_all();
++		return;
++	}
++
++	raw_spin_lock_irqsave(&l2x0_lock, flags);
++	start &= ~(CACHE_LINE_SIZE - 1);
++	cnt = (end + CACHE_LINE_SIZE -1 -start)/CACHE_LINE_SIZE;
++	if (cnt <= MAX_LINE_COUNT)
++		fa_l2x0_flush_PA(start, cnt);
++	else {
++		do {
++			fa_l2x0_flush_PA(start, MAX_LINE_COUNT);
++			start += (MAX_LINE_COUNT*CACHE_LINE_SIZE);
++			cnt -= MAX_LINE_COUNT;
++			if (cnt <= MAX_LINE_COUNT) {
++				fa_l2x0_flush_PA(start, cnt);
++				cnt = 0;
++			}
++		} while (cnt > 0);
++	}
++
++	//flib_cache_sync();
++	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
++}
++
++static void fa_l2x0_disable(void)
++{
++        unsigned long flags;
++
++        raw_spin_lock_irqsave(&l2x0_lock, flags);
++        __fa_l2x0_flush_all();
++        writel_relaxed(0, l2x0_base + L2X0_CTRL);
++        dsb();
++        raw_spin_unlock_irqrestore(&l2x0_lock, flags);
++}
++
++static void fa_l2x0_unlock(void)
++{
++	writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D);
++	writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I);
++}
++
++void __init ftl2cc031_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
++{
++	__u32 aux;
++	__u32 way_size = 0;
++	int ways, ret;
++
++	l2x0_base = base;
++
++	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
++	aux &= ~aux_mask;
++	aux |= aux_val;
++
++	if (aux & AUX_WAYNUM_16)
++		ways = 16;
++	else
++		ways = 8;
++
++	l2x0_way_mask = (1 << ways) -1;
++
++	/*
++	 * L2 cache Size = Way size * Number of ways
++	 */
++	way_size = (aux & AUX_WAYSIZE_MASK) >> 16;
++	way_size = 1 << (way_size + 4);
++	l2x0_size = ways * way_size * SZ_1K;
++
++	/*
++	 * Check if L2CC controller is already enabled.
++	 * If you are booting from non-secure mode
++	 * accessing the below registers will fault.
++	 */
++	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & CTRL_L2CC_EN)) {
++		/* Make sure that I&D is not locked down when starting */
++		fa_l2x0_unlock();
++
++		/* L2CC controller is disabled */
++		writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
++
++		/* Tag RAM initialization */
++		writel_relaxed(CTRL_TAG_INIT, l2x0_base + L2X0_CTRL);
++		/* wait for the operation to complete */
++		while (readl_relaxed(l2x0_base + L2X0_CTRL) & CTRL_TAG_INIT)
++			;
++		/* enable L2CC */
++		writel_relaxed(CTRL_L2CC_EN, l2x0_base + L2X0_CTRL);
++
++        /* when l2 cache is enabled, the controller will invalidate all ways */
++		//fa_l2x0_inv_all();
++	}
++
++    /* outer_cache is an extern variable in outercache.h of arch/arm/include/asm */
++	outer_cache.inv_range = fa_l2x0_inv_range;
++	outer_cache.clean_range = fa_l2x0_clean_range;
++	outer_cache.flush_range = fa_l2x0_flush_range;
++	outer_cache.sync = fa_l2x0_cache_sync;
++	outer_cache.flush_all = fa_l2x0_flush_all;
++	outer_cache.inv_all = fa_l2x0_inv_all;
++	outer_cache.disable = fa_l2x0_disable;
++	outer_cache.set_debug = fa_l2x0_set_debug;
++
++	printk(KERN_INFO "Faraday FTL2CC031 cache controller enabled\n");
++	printk(KERN_INFO "%d ways, AUX_CTRL 0x%08x, Cache size: %d B\n",
++			ways, aux, l2x0_size);
++
++    ret = request_irq(L2CACHE_FTL2CC031_IRQ, l2cache_handle_irq, 0, "l2_cache", NULL);
++    if (ret < 0)
++        panic("%s, request irq %d fail! \n", __func__, L2CACHE_FTL2CC031_IRQ);
++
++    writel_relaxed(0x3, l2x0_base + L2X0_INTR_MASK);    /* Tag parity error/Data parity error */
++}
++
++/*
++ * Interrupt handler while error happen
++ */
++static irqreturn_t l2cache_handle_irq(int irq, void *dev_id)
++{
++    volatile u32 value;
++
++    value = readl_relaxed(l2x0_base + L2X0_RAW_INTR_SRC);
++    writel_relaxed(value, l2x0_base + L2X0_INTR_CLEAR);
++
++    while (value & 0x3) {   /* Tag parity error/Data parity error */
++        if (value & 0x1)
++            printk("L2 cache tag ram error! \n");
++        if (value & 0x2)
++            printk("L2 cache data ram error! \n");
++    }
++
++    return IRQ_HANDLED;
++}
+diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
+index b1e192ba..db7bcc07 100644
+--- a/arch/arm/mm/cache-l2x0.c
++++ b/arch/arm/mm/cache-l2x0.c
+@@ -32,6 +32,7 @@ static void __iomem *l2x0_base;
+ static DEFINE_RAW_SPINLOCK(l2x0_lock);
+ static uint32_t l2x0_way_mask;	/* Bitmask of active ways */
+ static uint32_t l2x0_size;
++static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
+ 
+ struct l2x0_regs l2x0_saved_regs;
+ 
+@@ -61,12 +62,7 @@ static inline void cache_sync(void)
+ {
+ 	void __iomem *base = l2x0_base;
+ 
+-#ifdef CONFIG_PL310_ERRATA_753970
+-	/* write to an unmmapped register */
+-	writel_relaxed(0, base + L2X0_DUMMY_REG);
+-#else
+-	writel_relaxed(0, base + L2X0_CACHE_SYNC);
+-#endif
++	writel_relaxed(0, base + sync_reg_offset);
+ 	cache_wait(base + L2X0_CACHE_SYNC, 1);
+ }
+ 
+@@ -85,10 +81,13 @@ static inline void l2x0_inv_line(unsigned long addr)
+ }
+ 
+ #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915)
++static inline void debug_writel(unsigned long val)
++{
++	if (outer_cache.set_debug)
++		outer_cache.set_debug(val);
++}
+ 
+-#define debug_writel(val)	outer_cache.set_debug(val)
+-
+-static void l2x0_set_debug(unsigned long val)
++static void pl310_set_debug(unsigned long val)
+ {
+ 	writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL);
+ }
+@@ -98,7 +97,7 @@ static inline void debug_writel(unsigned long val)
+ {
+ }
+ 
+-#define l2x0_set_debug	NULL
++#define pl310_set_debug	NULL
+ #endif
+ 
+ #ifdef CONFIG_PL310_ERRATA_588369
+@@ -331,6 +330,11 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
+ 		else
+ 			ways = 8;
+ 		type = "L310";
++#ifdef CONFIG_PL310_ERRATA_753970
++		/* Unmapped register. */
++		sync_reg_offset = L2X0_DUMMY_REG;
++#endif
++		outer_cache.set_debug = pl310_set_debug;
+ 		break;
+ 	case L2X0_CACHE_ID_PART_L210:
+ 		ways = (aux >> 13) & 0xf;
+@@ -379,7 +383,6 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
+ 	outer_cache.flush_all = l2x0_flush_all;
+ 	outer_cache.inv_all = l2x0_inv_all;
+ 	outer_cache.disable = l2x0_disable;
+-	outer_cache.set_debug = l2x0_set_debug;
+ 
+ 	printk(KERN_INFO "%s cache controller enabled\n", type);
+ 	printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
+diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
+index ee9bb363..806cc4f6 100644
+--- a/arch/arm/mm/context.c
++++ b/arch/arm/mm/context.c
+@@ -18,30 +18,39 @@
+ 
+ static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
+ unsigned int cpu_last_asid = ASID_FIRST_VERSION;
+-#ifdef CONFIG_SMP
+-DEFINE_PER_CPU(struct mm_struct *, current_mm);
+-#endif
+ 
+ #ifdef CONFIG_ARM_LPAE
+-#define cpu_set_asid(asid) {						\
+-	unsigned long ttbl, ttbh;					\
+-	asm volatile(							\
+-	"	mrrc	p15, 0, %0, %1, c2		@ read TTBR0\n"	\
+-	"	mov	%1, %2, lsl #(48 - 32)		@ set ASID\n"	\
+-	"	mcrr	p15, 0, %0, %1, c2		@ set TTBR0\n"	\
+-	: "=&r" (ttbl), "=&r" (ttbh)					\
+-	: "r" (asid & ~ASID_MASK));					\
++void cpu_set_reserved_ttbr0(void)
++{
++	unsigned long ttbl = __pa(swapper_pg_dir);
++	unsigned long ttbh = 0;
++
++	/*
++	 * Set TTBR0 to swapper_pg_dir which contains only global entries. The
++	 * ASID is set to 0.
++	 */
++	asm volatile(
++	"	mcrr	p15, 0, %0, %1, c2		@ set TTBR0\n"
++	:
++	: "r" (ttbl), "r" (ttbh));
++	isb();
+ }
+ #else
+-#define cpu_set_asid(asid) \
+-	asm("	mcr	p15, 0, %0, c13, c0, 1\n" : : "r" (asid))
++void cpu_set_reserved_ttbr0(void)
++{
++	u32 ttb;
++	/* Copy TTBR1 into TTBR0 */
++	asm volatile(
++	"	mrc	p15, 0, %0, c2, c0, 1		@ read TTBR1\n"
++	"	mcr	p15, 0, %0, c2, c0, 0		@ set TTBR0\n"
++	: "=r" (ttb));
++	isb();
++}
+ #endif
+ 
+ /*
+  * We fork()ed a process, and we need a new context for the child
+- * to run in.  We reserve version 0 for initial tasks so we will
+- * always allocate an ASID. The ASID 0 is reserved for the TTBR
+- * register changing sequence.
++ * to run in.
+  */
+ void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+ {
+@@ -51,9 +60,7 @@ void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+ 
+ static void flush_context(void)
+ {
+-	/* set the reserved ASID before flushing the TLB */
+-	cpu_set_asid(0);
+-	isb();
++	cpu_set_reserved_ttbr0();
+ 	local_flush_tlb_all();
+ 	if (icache_is_vivt_asid_tagged()) {
+ 		__flush_icache_all();
+@@ -98,14 +105,7 @@ static void reset_context(void *info)
+ {
+ 	unsigned int asid;
+ 	unsigned int cpu = smp_processor_id();
+-	struct mm_struct *mm = per_cpu(current_mm, cpu);
+-
+-	/*
+-	 * Check if a current_mm was set on this CPU as it might still
+-	 * be in the early booting stages and using the reserved ASID.
+-	 */
+-	if (!mm)
+-		return;
++	struct mm_struct *mm = current->active_mm;
+ 
+ 	smp_rmb();
+ 	asid = cpu_last_asid + cpu + 1;
+@@ -114,8 +114,7 @@ static void reset_context(void *info)
+ 	set_mm_context(mm, asid);
+ 
+ 	/* set the new ASID */
+-	cpu_set_asid(mm->context.id);
+-	isb();
++	cpu_switch_mm(mm->pgd, mm);
+ }
+ 
+ #else
+diff --git a/arch/arm/mm/copypage-fa.c b/arch/arm/mm/copypage-fa.c
+index d2852e16..dac102ff 100644
+--- a/arch/arm/mm/copypage-fa.c
++++ b/arch/arm/mm/copypage-fa.c
+@@ -46,6 +46,7 @@ void fa_copy_user_highpage(struct page *to, struct page *from,
+ 
+ 	kto = kmap_atomic(to, KM_USER0);
+ 	kfrom = kmap_atomic(from, KM_USER1);
++	flush_cache_page(vma, vaddr, page_to_pfn(from));
+ 	fa_copy_user_page(kto, kfrom);
+ 	kunmap_atomic(kfrom, KM_USER1);
+ 	kunmap_atomic(kto, KM_USER0);
+diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
+index bb7eac38..d9aacf09 100644
+--- a/arch/arm/mm/fault.c
++++ b/arch/arm/mm/fault.c
+@@ -444,8 +444,16 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
+ 
+ 	if (pud_none(*pud_k))
+ 		goto bad_area;
+-	if (!pud_present(*pud))
++	if (!pud_present(*pud)) {
+ 		set_pud(pud, *pud_k);
++		/*
++		 * There is a small window during free_pgtables() where the
++		 * user *pud entry is 0 but the TLB has not been invalidated
++		 * and we get a level 2 (pmd) translation fault caused by the
++		 * intermediate TLB caching of the old level 1 (pud) entry.
++		 */
++		flush_tlb_kernel_page(addr);
++	}
+ 
+ 	pmd = pmd_offset(pud, addr);
+ 	pmd_k = pmd_offset(pud_k, addr);
+@@ -468,8 +476,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
+ #endif
+ 	if (pmd_none(pmd_k[index]))
+ 		goto bad_area;
++	if (!pmd_present(pmd[index]))
++		copy_pmd(pmd, pmd_k);
+ 
+-	copy_pmd(pmd, pmd_k);
+ 	return 0;
+ 
+ bad_area:
+diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
+index 1a8d4aa8..47212e07 100644
+--- a/arch/arm/mm/flush.c
++++ b/arch/arm/mm/flush.c
+@@ -11,6 +11,7 @@
+ #include <linux/mm.h>
+ #include <linux/pagemap.h>
+ #include <linux/highmem.h>
++#include <linux/spinlock.h>
+ 
+ #include <asm/cacheflush.h>
+ #include <asm/cachetype.h>
+@@ -25,19 +26,40 @@
+ 
+ #define ALIAS_FLUSH_START	0xffff4000
+ 
++static DEFINE_RAW_SPINLOCK(flush_lock);
++
++/* Beware that this function is not to be called for SMP setups. */
+ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
+ {
+ 	unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
++	unsigned long end = to + PAGE_SIZE;
+ 	const int zero = 0;
+-
++    static int cpu_id = 0;
++    
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 4) & 0xFFF;
++    
++	preempt_disable();
+ 	set_pte_ext(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL), 0);
+ 	flush_tlb_kernel_page(to);
+ 
+-	asm(	"mcrr	p15, 0, %1, %0, c14\n"
+-	"	mcr	p15, 0, %2, c7, c10, 4"
+-	    :
+-	    : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
+-	    : "cc");
++    if (cpu_id == 0x626) {
++    	for (; to < end; to += L1_CACHE_BYTES) {
++    		/* clean and invalidate D-cache entry */
++    		asm("mcr	p15, 0, %0, c7, c14, 1\n\t"
++    			:
++    			: "r" (to)
++    			: "cc");
++    	}
++    } else {    
++    	asm(	"mcrr	p15, 0, %1, %0, c14\n"
++    	"	mcr	p15, 0, %2, c7, c10, 4"
++    	    :
++    	    : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES), "r" (zero)
++    	    : "cc");
++    }
++
++	preempt_enable();
+ }
+ 
+ static void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned long len)
+@@ -46,10 +68,14 @@ static void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned
+ 	unsigned long offset = vaddr & (PAGE_SIZE - 1);
+ 	unsigned long to;
+ 
++	raw_spin_lock(&flush_lock);
++
+ 	set_pte_ext(TOP_PTE(ALIAS_FLUSH_START) + colour, pfn_pte(pfn, PAGE_KERNEL), 0);
+ 	to = ALIAS_FLUSH_START + (colour << PAGE_SHIFT) + offset;
+ 	flush_tlb_kernel_page(to);
+ 	flush_icache_range(to, to + len);
++
++	raw_spin_unlock(&flush_lock);
+ }
+ 
+ void flush_cache_mm(struct mm_struct *mm)
+diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
+index 5dc7d127..eaea234d 100644
+--- a/arch/arm/mm/init.c
++++ b/arch/arm/mm/init.c
+@@ -637,7 +637,7 @@ void __init mem_init(void)
+ 	}
+ 	printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
+ 
+-	printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
++	printk(KERN_INFO "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
+ 		nr_free_pages() << (PAGE_SHIFT-10),
+ 		free_pages << (PAGE_SHIFT-10),
+ 		reserved_pages << (PAGE_SHIFT-10),
+@@ -647,7 +647,7 @@ void __init mem_init(void)
+ #define MLM(b, t) b, t, ((t) - (b)) >> 20
+ #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
+ 
+-	printk(KERN_NOTICE "Virtual kernel memory layout:\n"
++	printk(KERN_INFO "Virtual kernel memory layout:\n"
+ 			"    vector  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+ #ifdef CONFIG_HAVE_TCM
+ 			"    DTCM    : 0x%08lx - 0x%08lx   (%4ld kB)\n"
+@@ -712,7 +712,41 @@ void __init mem_init(void)
+ 		 */
+ 		sysctl_overcommit_memory = OVERCOMMIT_ALWAYS;
+ 	}
++
++#if (defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP)) 
++    {
++        extern void fmem_early_init(void);
++        /* put here in order to get clean pages */
++        fmem_early_init();
++    }
++#endif	
++}
++
++#if ((defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP)) && defined(CONFIG_MEMORY_HOTPLUG))
++int arch_add_memory(int nid, u64 start, u64 size)
++{
++#if 0 /* Harry, copy from powerPC. This function should be implemented if 
++       * we supported hardware hotplug function.
++       */
++	struct pglist_data *pgdata;
++	struct zone *zone;
++	unsigned long start_pfn = start >> PAGE_SHIFT;
++	unsigned long nr_pages = size >> PAGE_SHIFT;
++
++	pgdata = NODE_DATA(nid);
++
++	start = (unsigned long)__va(start);
++	if (create_section_mapping(start, start + size))
++		return -EINVAL;
++
++	/* this should work for most non-highmem platforms */
++	zone = pgdata->node_zones;
++
++	return __add_pages(nid, zone, start_pfn, nr_pages);
++#endif
++    return -1;	
+ }
++#endif
+ 
+ void free_initmem(void)
+ {
+diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
+index 80632e8d..9911884d 100644
+--- a/arch/arm/mm/ioremap.c
++++ b/arch/arm/mm/ioremap.c
+@@ -238,9 +238,19 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
+ 	/*
+ 	 * Don't allow RAM to be mapped - this causes problems with ARMv6+
+ 	 */
+-	if (WARN_ON(pfn_valid(pfn)))
++#if defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP) /* Harry */
++    if (pfn_valid(pfn) && (cpu_architecture() >= CPU_ARCH_ARMv6)) {
++        printk("BUG: Your driver calls ioremap() on system memory. This leads to architecturally\n"
++                "unpredictable behavior on ARMv6+, please fix your driver.\n");
++        return NULL;
++    }
++#else    
++	if (WARN_ON(pfn_valid(pfn))) {
++        printk("BUG: Your driver calls ioremap() on system memory. This leads to architecturally\n"
++               "unpredictable behavior on ARMv6+, please fix your driver.\n");
+ 		return NULL;
+-
++    }
++#endif
+ 	area = get_vm_area_caller(size, VM_IOREMAP, caller);
+  	if (!area)
+  		return NULL;
+diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
+index 94c5a0c9..21c20e33 100644
+--- a/arch/arm/mm/mmu.c
++++ b/arch/arm/mm/mmu.c
+@@ -414,12 +414,6 @@ static void __init build_mem_type_table(void)
+ 	cp = &cache_policies[cachepolicy];
+ 	vecs_pgprot = kern_pgprot = user_pgprot = cp->pte;
+ 
+-	/*
+-	 * Only use write-through for non-SMP systems
+-	 */
+-	if (!is_smp() && cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH)
+-		vecs_pgprot = cache_policies[CPOLICY_WRITETHROUGH].pte;
+-
+ 	/*
+ 	 * Enable CPU-specific coherency if supported.
+ 	 * (Only available on XSC3 at the moment.)
+diff --git a/arch/arm/mm/proc-fa526.S b/arch/arm/mm/proc-fa526.S
+index 272558a1..1c150e11 100644
+--- a/arch/arm/mm/proc-fa526.S
++++ b/arch/arm/mm/proc-fa526.S
+@@ -82,7 +82,12 @@ ENDPROC(cpu_fa526_reset)
+  */
+ 	.align	4
+ ENTRY(cpu_fa526_do_idle)
++	mrs	r0, cpsr
++	bic	r0, r0, #0x80			@ enable irq
++	msr	cpsr_c, r0
+ 	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
++	orr	r0, r0, #0x80			@ disable irq
++	msr	cpsr_c, r0
+ 	mov	pc, lr
+ 
+ 
+diff --git a/arch/arm/mm/proc-fa626te.S b/arch/arm/mm/proc-fa626te.S
+new file mode 100644
+index 00000000..8a6f1d66
+--- /dev/null
++++ b/arch/arm/mm/proc-fa626te.S
+@@ -0,0 +1,213 @@
++/*
++ *  linux/arch/arm/mm/proc-fa626te.S: MMU functions for FA626TE
++ *
++ *  Written by : Luke Lee
++ *  Copyright (C) 2005 Faraday Corp.
++ *  Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
++ *
++ * 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.
++ *
++ *
++ * These are the low level assembler for performing cache and TLB
++ * functions on the fa626te.
++ */
++#include <linux/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/hwcap.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/ptrace.h>
++#include <asm/system.h>
++
++#include "proc-macros.S"
++
++#define CACHE_DLINESIZE	32
++
++	.text
++/*
++ * cpu_fa626te_proc_init()
++ */
++ENTRY(cpu_fa626te_proc_init)
++	mov	pc, lr
++
++/*
++ * cpu_fa626te_proc_fin()
++ */
++ENTRY(cpu_fa626te_proc_fin)
++	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
++	bic	r0, r0, #0x1000			@ ...i............
++	bic	r0, r0, #0x000e			@ ............wca.
++	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
++	nop
++	nop
++	mov	pc, lr
++
++/*
++ * cpu_fa626te_reset(loc)
++ *
++ * Perform a soft reset of the system.  Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++	.align	4
++	.pushsection    .idmap.text, "ax"
++ENTRY(cpu_fa626te_reset)
++/* TODO: Use CP8 if possible... */
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
++	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
++#ifdef CONFIG_MMU
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++#endif
++	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
++	bic	ip, ip, #0x000f			@ ............wcam
++	bic	ip, ip, #0x1100			@ ...i...s........
++	bic	ip, ip, #0x0800			@ BTB off
++	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
++	nop
++	nop
++	mov	pc, r0
++ENDPROC(cpu_fa626te_reset)
++	.popsection
++
++/*
++ * cpu_fa626te_do_idle()
++ */
++	.align	4
++ENTRY(cpu_fa626te_do_idle)
++	mrs	r0, cpsr
++	bic	r0, r0, #0x80			@ enable irq
++	msr	cpsr_c, r0
++	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
++	orr	r0, r0, #0x80			@ disable irq
++	msr	cpsr_c, r0
++	mov	pc, lr
++
++
++ENTRY(cpu_fa626te_dcache_clean_area)
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	subs	r1, r1, #CACHE_DLINESIZE
++	bhi	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_fa626te_switch_mm(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++	.align	4
++ENTRY(cpu_fa626te_switch_mm)
++#ifdef CONFIG_MMU
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c5, 6		@ invalidate BTB since mm changed
++	mcr	p15, 0, ip, c7, c10, 4		@ data write barrier
++	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate UTLB
++#endif
++	mov	pc, lr
++
++/*
++ * cpu_fa626te_set_pte_ext(ptep, pte, ext)
++ *
++ * Set a PTE and flush it out
++ */
++	.align	4
++ENTRY(cpu_fa626te_set_pte_ext)
++#ifdef CONFIG_MMU
++	armv3_set_pte_ext
++	mov	r0, r0
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++#endif
++	mov	pc, lr
++
++	__CPUINIT
++
++	.type	__fa626te_setup, #function
++__fa626te_setup:
++	/* On return of this routine, r0 must carry correct flags for CFG register */
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c7		@ invalidate I,D caches on v4
++	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
++#ifdef CONFIG_MMU
++	mcr	p15, 0, r0, c8, c7		@ invalidate I,D TLBs on v4
++#endif
++	mcr	p15, 0, r0, c7, c5, 5		@ invalidate IScratchpad RAM
++
++	mcr	p15, 0, r0, c7, c5, 6		@ invalidate BTB All
++	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
++	mcr	p15, 0, r0, c7, c5, 4		@ prefetch flush
++
++	mov	r0, #0x1f			@ Domains 0, 1 = manager, 2 = client
++	mcr	p15, 0, r0, c3, c0		@ load domain access register
++
++	adr	r5, fa626te_crval
++	ldmia	r5, {r5, r6}
++	mrc	p15, 0, r0, c1, c0		@ get control register v4
++	bic	r0, r0, r5
++	orr	r0, r0, r6
++	mov	pc, lr
++	.size	__fa626te_setup, . - __fa626te_setup
++
++	/*
++	 * .RVI ZFRS BLDP WCAM
++	 * ..11 1001 .111 1101
++	 *
++	 */
++	.type	fa626te_crval, #object
++fa626te_crval:
++	crval	clear=0x3f7f, mmuset=0x397D, ucset=0x3174
++
++	__INITDATA
++
++	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
++	define_processor_functions fa626te, dabort=v5t_early_abort, pabort=legacy_pabort
++
++	.section ".rodata"
++
++	string	cpu_arch_name, "armv5te"
++	string	cpu_elf_name, "v5"
++	string	cpu_fa626te_name, "FA6"
++
++	.align
++
++	.section ".proc.info.init", #alloc, #execinstr
++
++	.type	__fa626te_proc_info,#object
++__fa626te_proc_info:
++	.long	0x66056260
++	.long	0xff0ffff0
++	.long   PMD_TYPE_SECT | \
++		PMD_SECT_BUFFERABLE | \
++		PMD_SECT_CACHEABLE | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	.long   PMD_TYPE_SECT | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	b	__fa626te_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
++	.long	cpu_fa626te_name
++	.long	fa626te_processor_functions
++	.long	fa_tlb_fns
++	.long	fa_user_fns
++	.long	fa_cache_fns
++	.size	__fa626te_proc_info, . - __fa626te_proc_info
+diff --git a/arch/arm/mm/proc-fa726te.S b/arch/arm/mm/proc-fa726te.S
+new file mode 100644
+index 00000000..541dded7
+--- /dev/null
++++ b/arch/arm/mm/proc-fa726te.S
+@@ -0,0 +1,500 @@
++/*
++ *  linux/arch/arm/mm/proc-fa726te.S: MMU functions for FA726TE
++ *
++ *  Copyright (C) 1999-2001 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *  hacked for non-paged-MM by Hyok S. Choi, 2003.
++ *
++ * 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
++ *
++ *
++ * These are the low level assembler for performing cache and TLB
++ * functions on the fa726te.
++ *
++ *  CONFIG_CPU_ARM926_CPU_IDLE -> nohlt
++ */
++#include <linux/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/hwcap.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/ptrace.h>
++#include "proc-macros.S"
++
++/*
++ * This is the maximum size of an area which will be invalidated
++ * using the single invalidate entry instructions.  Anything larger
++ * than this, and we go for the whole cache.
++ *
++ * This value should be chosen such that we choose the cheapest
++ * alternative.
++ */
++#define CACHE_DLIMIT	16384
++
++/*
++ * the cache line size of the I and D cache
++ */
++#define CACHE_DLINESIZE	32
++
++	.text
++/*
++ * cpu_fa726te_proc_init()
++ */
++ENTRY(cpu_fa726te_proc_init)
++	mov	pc, lr
++
++/*
++ * cpu_fa726te_proc_fin()
++ */
++ENTRY(cpu_fa726te_proc_fin)
++	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
++	bic	r0, r0, #0x1000			@ ...i............
++	bic	r0, r0, #0x000e			@ ............wca.
++	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
++	mov pc, lr
++
++/*
++ * cpu_fa726te_reset(loc)
++ *
++ * Perform a soft reset of the system.  Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++	.align	5
++	.pushsection    .idmap.text, "ax"
++ENTRY(cpu_fa726te_reset)
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
++	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
++#ifdef CONFIG_MMU
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++#endif
++	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
++	bic	ip, ip, #0x000f			@ ............wcam
++	bic	ip, ip, #0x1100			@ ...i...s........
++	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
++	mov	pc, r0
++ENDPROC(cpu_fa726te_reset)
++	.popsection
++
++/*
++ * cpu_fa726te_do_idle()
++ *
++ * Called with IRQs disabled
++ */
++	.align	10
++ENTRY(cpu_fa726te_do_idle)
++	mov	r0, #0
++	mrc	p15, 0, r1, c1, c0, 0		@ Read control register
++	mcr	p15, 0, r0, c7, c10, 4		@ Drain write buffer
++	bic	r2, r1, #1 << 12
++	mrs	r3, cpsr			@ Disable FIQs while Icache
++	orr	ip, r3, #PSR_F_BIT		@ is disabled
++	msr	cpsr_c, ip
++	mcr	p15, 0, r2, c1, c0, 0		@ Disable I cache
++	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
++	mcr	p15, 0, r1, c1, c0, 0		@ Restore ICache enable
++	msr	cpsr_c, r3			@ Restore FIQ state
++	mov	pc, lr
++
++/*
++ * flush_icache_all()
++ *
++ * Unconditionally clean and invalidate the entire icache.
++ */
++ENTRY(fa726te_flush_icache_all)
++	mov r0, #0
++	mcr p15, 0, r0, c7, c5, 0		@ invalidate I cache
++	mov pc, lr
++ENDPROC(fa726te_flush_icache_all)
++
++/*
++ *	flush_user_cache_all()
++ *
++ *	Clean and invalidate all cache entries in a particular
++ *	address space.
++ */
++ENTRY(fa726te_flush_user_cache_all)
++	/* FALLTHROUGH */
++
++/*
++ *	flush_kern_cache_all()
++ *
++ *	Clean and invalidate the entire cache.
++ */
++ENTRY(fa726te_flush_kern_cache_all)
++	mov	r2, #VM_EXEC
++	mov	ip, #0
++__flush_whole_cache:
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
++#else
++1:	mrc	p15, 0, r15, c7, c10, 3 	@ test,clean,invalidate
++	bne	1b
++#endif
++	tst	r2, #VM_EXEC
++	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache
++	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	flush_user_cache_range(start, end, flags)
++ *
++ *	Clean and invalidate a range of cache entries in the
++ *	specified address range.
++ *
++ *	- start	- start address (inclusive)
++ *	- end	- end address (exclusive)
++ *	- flags	- vm_flags describing address space
++ */
++ENTRY(fa726te_flush_user_cache_range)
++	mov	ip, #0
++	sub	r3, r1, r0			@ calculate total size
++	cmp	r3, #CACHE_DLIMIT
++	bgt	__flush_whole_cache
++1:	tst	r2, #VM_EXEC
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++#else
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++#endif
++	cmp	r0, r1
++	blo	1b
++	tst	r2, #VM_EXEC
++	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	coherent_kern_range(start, end)
++ *
++ *	Ensure coherency between the Icache and the Dcache in the
++ *	region described by start, end.  If you have non-snooping
++ *	Harvard caches, you need to implement this function.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(fa726te_coherent_kern_range)
++	/* FALLTHROUGH */
++
++/*
++ *	coherent_user_range(start, end)
++ *
++ *	Ensure coherency between the Icache and the Dcache in the
++ *	region described by start, end.  If you have non-snooping
++ *	Harvard caches, you need to implement this function.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(fa726te_coherent_user_range)
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	flush_kern_dcache_area(void *addr, size_t size)
++ *
++ *	Ensure no D cache aliasing occurs, either with itself or
++ *	the I cache
++ *
++ *	- addr	- kernel address
++ *	- size	- region size
++ */
++ENTRY(fa726te_flush_kern_dcache_area)
++	add	r1, r0, r1
++1:	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_inv_range(start, end)
++ *
++ *	Invalidate (discard) the specified virtual address range.
++ *	May not write back any entries.  If 'start' or 'end'
++ *	are not cache line aligned, those lines must be written
++ *	back.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ *
++ * (same as v4wb)
++ */
++fa726te_dma_inv_range:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	tst	r0, #CACHE_DLINESIZE - 1
++	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
++	tst	r1, #CACHE_DLINESIZE - 1
++	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
++#endif
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_clean_range(start, end)
++ *
++ *	Clean the specified virtual address range.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ *
++ * (same as v4wb)
++ */
++fa726te_dma_clean_range:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_flush_range(start, end)
++ *
++ *	Clean and invalidate the specified virtual address range.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(fa726te_dma_flush_range)
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
++#else
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++#endif
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_map_area(start, size, dir)
++ *	- start	- kernel virtual start address
++ *	- size	- size of region
++ *	- dir	- DMA direction
++ */
++ENTRY(fa726te_dma_map_area)
++	add	r1, r1, r0
++	cmp	r2, #DMA_TO_DEVICE
++	beq	fa726te_dma_clean_range
++	bcs	fa726te_dma_inv_range
++	b	fa726te_dma_flush_range
++ENDPROC(fa726te_dma_map_area)
++
++/*
++ *	dma_unmap_area(start, size, dir)
++ *	- start	- kernel virtual start address
++ *	- size	- size of region
++ *	- dir	- DMA direction
++ */
++ENTRY(fa726te_dma_unmap_area)
++	mov	pc, lr
++ENDPROC(fa726te_dma_unmap_area)
++
++	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
++	define_cache_functions fa726te
++
++ENTRY(cpu_fa726te_dcache_clean_area)
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	subs	r1, r1, #CACHE_DLINESIZE
++	bhi	1b
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_fa726te_switch_mm(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++	.align	5
++ENTRY(cpu_fa726te_switch_mm)
++#ifdef CONFIG_MMU
++	mov	ip, #0
++	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++#endif
++	mov	pc, lr
++
++/*
++ * cpu_fa726te_set_pte_ext(ptep, pte, ext)
++ *
++ * Set a PTE and flush it out
++ */
++	.align	5
++ENTRY(cpu_fa726te_set_pte_ext)
++#ifdef CONFIG_MMU
++	armv3_set_pte_ext
++	mov	r0, r0
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++#endif
++	mov	pc, lr
++
++/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
++.globl cpu_fa726te_suspend_size
++.equ   cpu_fa726te_suspend_size, 4 * 3
++#ifdef CONFIG_PM_SLEEP
++ENTRY(cpu_fa726te_do_suspend)
++	stmfd   sp!, {r4 - r7, lr}
++	mrc p15, 0, r4, c13, c0, 0  @ PID
++	mrc p15, 0, r5, c3, c0, 0   @ Domain ID
++	mrc p15, 0, r6, c2, c0, 0   @ TTB address
++	mrc p15, 0, r7, c1, c0, 0   @ Control register
++	stmia   r0, {r4 - r7}
++	ldmfd   sp!, {r4 - r7, pc}
++ENDPROC(cpu_fa726te_do_suspend)
++
++ENTRY(cpu_fa726te_do_resume)
++	mov ip, #0
++	mcr p15, 0, ip, c8, c7, 0   @ invalidate I+D TLBs
++	mcr p15, 0, ip, c7, c7, 0   @ invalidate I+D caches
++	ldmia   r0, {r4 - r7}
++	mcr p15, 0, r4, c13, c0, 0  @ PID
++	mcr p15, 0, r5, c3, c0, 0   @ Domain ID
++	mcr p15, 0, r6, c2, c0, 0   @ TTB address
++	mov r0, r7          @ control register
++	mov r2, r6, lsr #14     @ get TTB0 base
++	mov r2, r2, lsl #14
++	ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
++			 PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
++	b	cpu_resume_mmu
++
++ENDPROC(cpu_fa726te_do_resume)
++#else
++#define cpu_fa726te_do_suspend	0
++#define cpu_fa726te_do_resume	0
++#endif
++
++	__CPUINIT
++
++	.type	__fa726te_setup, #function
++__fa726te_setup:
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c7		@ invalidate I,D caches on v4
++	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
++#ifdef CONFIG_MMU
++	mcr	p15, 0, r0, c8, c7		@ invalidate I,D TLBs on v4
++#endif
++
++
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mov	r0, #4				@ disable write-back on caches explicitly
++	mcr	p15, 7, r0, c15, c0, 0
++#endif
++
++	adr	r5, fa726te_crval
++	ldmia	r5, {r5, r6}
++	mrc	p15, 0, r0, c1, c0		@ get control register v4
++	bic	r0, r0, r5
++	orr	r0, r0, r6
++#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
++	orr	r0, r0, #0x4000			@ .1.. .... .... ....
++#endif
++	mov	pc, lr
++	.size	__fa726te_setup, . - __fa726te_setup
++
++	/*
++	 *  R
++	 * .RVI ZFRS BLDP WCAM
++	 * .011 0001 ..11 0101
++	 *
++	 */
++	.type	fa726te_crval, #object
++fa726te_crval:
++	crval	clear=0x00007f3f, mmuset=0x00003135, ucset=0x00001134
++
++	__INITDATA
++
++	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
++	define_processor_functions fa726te, dabort=v5t_early_abort, pabort=legacy_pabort, suspend=1
++
++	.section ".rodata"
++
++	string cpu_arch_name, "armv5te"
++	string cpu_elf_name, "v5"
++	string cpu_fa726te_name, "FA7"
++
++	.align
++
++	.section ".proc.info.init", #alloc, #execinstr
++
++	.type	__fa726te_proc_info,#object
++__fa726te_proc_info:
++	.long	0x66057260			@ FA726TE (v5TE)
++	.long	0xff0ffff0
++	.long   PMD_TYPE_SECT | \
++		PMD_SECT_BUFFERABLE | \
++		PMD_SECT_CACHEABLE | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	.long   PMD_TYPE_SECT | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	b	__fa726te_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_EDSP
++	.long	cpu_fa726te_name
++	.long	fa726te_processor_functions
++	.long	v4wbi_tlb_fns
++	.long	v4wb_user_fns
++	.long	fa726te_cache_fns
++	.size	__fa726te_proc_info, . - __fa726te_proc_info
+diff --git a/arch/arm/mm/proc-fmp626.S b/arch/arm/mm/proc-fmp626.S
+new file mode 100644
+index 00000000..3d3af27d
+--- /dev/null
++++ b/arch/arm/mm/proc-fmp626.S
+@@ -0,0 +1,477 @@
++/*
++ *  linux/arch/arm/mm/proc-fmp626.S: MMU functions for Faraday FMP626
++ *
++ * 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
++ *
++ *
++ * These are the low level assembler for performing cache and TLB
++ * functions on the fmp626.
++ */
++#include <linux/linkage.h>
++#include <linux/init.h>
++#include <asm/assembler.h>
++#include <asm/hwcap.h>
++#include <asm/pgtable-hwdef.h>
++#include <asm/pgtable.h>
++#include <asm/page.h>
++#include <asm/ptrace.h>
++#include "proc-macros.S"
++
++/*
++ * This is the maximum size of an area which will be invalidated
++ * using the single invalidate entry instructions.  Anything larger
++ * than this, and we go for the whole cache.
++ *
++ * This value should be chosen such that we choose the cheapest
++ * alternative.
++ */
++#define CACHE_DLIMIT	16384
++
++/*
++ * the cache line size of the I and D cache
++ */
++#define CACHE_DLINESIZE	32
++
++#define TTB_S		(1 << 1)
++#define TTB_RGN_NC	(0 << 3)
++#define TTB_RGN_WBWA	(1 << 3)
++#define TTB_RGN_WT	(2 << 3)
++#define TTB_RGN_WB	(3 << 3)
++
++#ifndef CONFIG_SMP
++#define TTB_FLAGS	TTB_RGN_WBWA
++#else
++#define TTB_FLAGS	TTB_RGN_WBWA|TTB_S
++#endif
++
++	.text
++/*
++ * cpu_fmp626_proc_init()
++ */
++ENTRY(cpu_fmp626_proc_init)
++	mov	pc, lr
++
++/*
++ * cpu_fmp626_proc_fin()
++ */
++ENTRY(cpu_fmp626_proc_fin)
++	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
++	bic	r0, r0, #0x1000			@ ...i............
++	bic	r0, r0, #0x000e			@ ............wca.
++	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
++	mov	pc, lr
++
++/*
++ * cpu_fmp626_reset(loc)
++ *
++ * Perform a soft reset of the system.  Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++	.align	5
++	.pushsection	.idmap.text, "ax"
++ENTRY(cpu_fmp626_reset)
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
++	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
++#ifdef CONFIG_MMU
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++#endif
++	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
++	bic	ip, ip, #0x000f			@ ............wcam
++	bic	ip, ip, #0x1100			@ ...i...s........
++	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
++	nop
++	nop
++	mov	pc, r0
++ENDPROC(cpu_fmp626_reset)
++	.popsection
++
++/*
++ * cpu_fmp626_do_idle()
++ *
++ * Called with IRQs disabled
++ */
++	.align	10
++ENTRY(cpu_fmp626_do_idle)
++	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
++	mov	pc, lr
++
++/*
++ *	flush_icache_all()
++ *
++ *	Flush the whole I-cache.
++ */
++ENTRY(fmp626_flush_icache_all)
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I-cache all
++	mov	pc,lr
++
++/*
++ *	flush_user_cache_all()
++ *
++ *	Clean and invalidate all cache entries in a particular
++ *	address space.
++ */
++ENTRY(fmp626_flush_user_cache_all)
++	/* FALLTHROUGH */
++
++/*
++ *	flush_kern_cache_all()
++ *
++ *	Clean and invalidate the entire cache.
++ */
++ENTRY(fmp626_flush_kern_cache_all)
++	mov	r2, #VM_EXEC
++	mov	ip, #0
++__flush_whole_cache:
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache all
++#else
++	mcr	p15, 0, ip, c7, c14, 0		@ clean and invalidate D cache all
++#endif
++	tst	r2, #VM_EXEC
++	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache all
++	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	flush_user_cache_range(start, end, flags)
++ *
++ *	Clean and invalidate a range of cache entries in the
++ *	specified address range.
++ *
++ *	- start	- start address (inclusive)
++ *	- end	- end address (exclusive)
++ *	- flags	- vm_flags describing address space
++ */
++ENTRY(fmp626_flush_user_cache_range)
++	mov	ip, #0
++	sub	r3, r1, r0			@ calculate total size
++	cmp	r3, #CACHE_DLIMIT
++	bgt	__flush_whole_cache
++1:	tst	r2, #VM_EXEC
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++#else
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++#endif
++	cmp	r0, r1
++	blo	1b
++	tst	r2, #VM_EXEC
++	mcrne	p15, 0, ip, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	coherent_kern_range(start, end)
++ *
++ *	Ensure coherency between the Icache and the Dcache in the
++ *	region described by start, end.  If you have non-snooping
++ *	Harvard caches, you need to implement this function.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(fmp626_coherent_kern_range)
++	/* FALLTHROUGH */
++
++/*
++ *	coherent_user_range(start, end)
++ *
++ *	Ensure coherency between the Icache and the Dcache in the
++ *	region described by start, end.  If you have non-snooping
++ *	Harvard caches, you need to implement this function.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(fmp626_coherent_user_range)
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	flush_kern_dcache_area(void *addr, size_t size)
++ *
++ *	Ensure no D cache aliasing occurs, either with itself or
++ *	the I cache
++ *
++ *	- addr	- kernel address
++ *	- size	- size of region
++ */
++ENTRY(fmp626_flush_kern_dcache_area)
++	add	r1, r0, r1
++1:	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_inv_range(start, end)
++ *
++ *	Invalidate (discard) the specified virtual address range.
++ *	May not write back any entries.  If 'start' or 'end'
++ *	are not cache line aligned, those lines must be written
++ *	back.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ *
++ * (same as v4wb)
++ */
++fmp626_dma_inv_range:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	tst	r0, #CACHE_DLINESIZE - 1
++	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
++	tst	r1, #CACHE_DLINESIZE - 1
++	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
++#endif
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_clean_range(start, end)
++ *
++ *	Clean the specified virtual address range.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ *
++ * (same as v4wb)
++ */
++fmp626_dma_clean_range:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_flush_range(start, end)
++ *
++ *	Clean and invalidate the specified virtual address range.
++ *
++ *	- start	- virtual start address
++ *	- end	- virtual end address
++ */
++ENTRY(fmp626_dma_flush_range)
++	bic	r0, r0, #CACHE_DLINESIZE - 1
++1:
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c14, 1		@ clean+invalidate D entry
++#else
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	add	r0, r0, #CACHE_DLINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ *	dma_map_area(start, size, dir)
++ *	- start	- kernel virtual start address
++ *	- size	- size of region
++ *	- dir	- DMA direction
++ */
++ENTRY(fmp626_dma_map_area)
++	add	r1, r1, r0
++	cmp	r2, #DMA_TO_DEVICE
++	beq	fmp626_dma_clean_range
++	bcs	fmp626_dma_inv_range
++	b	fmp626_dma_flush_range
++ENDPROC(fmp626_dma_map_area)
++
++/*
++ *	dma_unmap_area(start, size, dir)
++ *	- start	- kernel virtual start address
++ *	- size	- size of region
++ *	- dir	- DMA direction
++ */
++ENTRY(fmp626_dma_unmap_area)
++	mov	pc, lr
++ENDPROC(fmp626_dma_unmap_area)
++
++	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
++	define_cache_functions fmp626
++
++ENTRY(cpu_fmp626_dcache_clean_area)
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #CACHE_DLINESIZE
++	subs	r1, r1, #CACHE_DLINESIZE
++	bhi	1b
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_fmp626_switch_mm(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++	.align	5
++ENTRY(cpu_fmp626_switch_mm)
++#ifdef CONFIG_MMU
++	mov	ip, #0
++	orr	r0, r0, #TTB_FLAGS
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
++#else
++	mcr	p15, 0, ip, c7, c14, 0		@ clean and invalidate whole D cache
++#endif
++	mcr	p15, 0, ip, c7, c5, 0		@ invalidate I cache
++	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
++	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++#endif
++	mov	pc, lr
++
++/*
++ *	cpu_fmp626_set_pte_ext(ptep, pte, ext)
++ *
++ *	Set a PTE and flush it out
++ *
++ *	- ptep  - pointer to level 2 translation table entry
++ *		  (hardware version is stored at -1024 bytes)
++ *	- pte   - PTE value to store
++ *	- ext	- value for extended PTE bits (not used)
++ *
++ *	Memory types and attributes:
++ *	C B	type		attribute
++ *	0 0	strong ordered	noncacheable, nonbufferable, shared
++ *	0 1	device		noncacheable, bufferable, shared
++ *	1 0	normal		write-back cacheable, bufferable, non-shared
++ *	1 1	normal		write-back cacheable, bufferable, shared
++ */
++	.align	5
++ENTRY(cpu_fmp626_set_pte_ext)
++#ifdef CONFIG_MMU
++	armv3_set_pte_ext
++	mov	r0, r0
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++#endif
++	mov	pc, lr
++
++	__CPUINIT
++
++/*
++ * Returns:
++ *	r5, r6 corrupted
++ *	r0 = control register value
++ */
++	.type	__fmp626_setup, #function
++__fmp626_setup:
++#ifdef CONFIG_SMP
++	mrc	p15, 0, r0, c1, c0, 1		@ Enable SMP/nAMP mode
++	orr	r0, r0, #0x20
++	mcr	p15, 0, r0, c1, c0, 1
++#endif
++
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c7		@ invalidate I,D caches on v4
++	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
++#ifdef CONFIG_MMU
++	mcr	p15, 0, r0, c8, c7		@ invalidate I,D TLBs on v4
++#endif
++
++	adr	r5, fmp626_crval
++	ldmia	r5, {r5, r6}
++	mrc	p15, 0, r0, c1, c0		@ get control register v4
++	bic	r0, r0, r5
++	orr	r0, r0, r6
++	mov	pc, lr
++	.size	__fmp626_setup, . - __fmp626_setup
++
++	/*
++	 * L
++	 * 4.VI ZFRS BLDP WCAM
++	 * ..11 1.01 .111 1101
++	 *
++	 */
++	.type	fmp626_crval, #object
++fmp626_crval:
++	crval	clear=0x00003b7f, mmuset=0x0000397d, ucset=0x00001134
++
++	__INITDATA
++
++	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
++	define_processor_functions fmp626, dabort=v5t_early_abort, pabort=legacy_pabort
++
++	.section ".rodata"
++
++	string cpu_arch_name, "armv5te"
++	string cpu_elf_name, "v5"
++	string cpu_fmp626_name, "FMP626"
++
++	.align
++
++	.section ".proc.info.init", #alloc, #execinstr
++
++	.type	__fmp626_proc_info,#object
++__fmp626_proc_info:
++	.long	0x66056268			@ Faraday ARMv5TE, FMP626
++	.long	0xff0ffff8
++	.long   PMD_TYPE_SECT | \
++		PMD_SECT_BUFFERABLE | \
++		PMD_SECT_CACHEABLE | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	.long   PMD_TYPE_SECT | \
++		PMD_BIT4 | \
++		PMD_SECT_AP_WRITE | \
++		PMD_SECT_AP_READ
++	b	__fmp626_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_TLS
++	.long	cpu_fmp626_name
++	.long	fmp626_processor_functions
++	.long	fa_tlb_fns
++	.long	fa_user_fns
++	.long	fmp626_cache_fns
++	.size	__fmp626_proc_info, . - __fmp626_proc_info
+diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
+index 5900cd52..2f702fd3 100644
+--- a/arch/arm/mm/proc-v6.S
++++ b/arch/arm/mm/proc-v6.S
+@@ -136,8 +136,10 @@ ENTRY(cpu_v6_set_pte_ext)
+ ENTRY(cpu_v6_do_suspend)
+ 	stmfd	sp!, {r4 - r9, lr}
+ 	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
++#ifdef CONFIG_MMU
+ 	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
+ 	mrc	p15, 0, r6, c2, c0, 1	@ Translation table base 1
++#endif
+ 	mrc	p15, 0, r7, c1, c0, 1	@ auxiliary control register
+ 	mrc	p15, 0, r8, c1, c0, 2	@ co-processor access control
+ 	mrc	p15, 0, r9, c1, c0, 0	@ control register
+@@ -154,14 +156,16 @@ ENTRY(cpu_v6_do_resume)
+ 	mcr	p15, 0, ip, c13, c0, 1	@ set reserved context ID
+ 	ldmia	r0, {r4 - r9}
+ 	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
++#ifdef CONFIG_MMU
+ 	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
+ 	ALT_SMP(orr	r1, r1, #TTB_FLAGS_SMP)
+ 	ALT_UP(orr	r1, r1, #TTB_FLAGS_UP)
+ 	mcr	p15, 0, r1, c2, c0, 0	@ Translation table base 0
+ 	mcr	p15, 0, r6, c2, c0, 1	@ Translation table base 1
++	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
++#endif
+ 	mcr	p15, 0, r7, c1, c0, 1	@ auxiliary control register
+ 	mcr	p15, 0, r8, c1, c0, 2	@ co-processor access control
+-	mcr	p15, 0, ip, c2, c0, 2	@ TTB control register
+ 	mcr	p15, 0, ip, c7, c5, 4	@ ISB
+ 	mov	r0, r9			@ control register
+ 	b	cpu_resume_mmu
+diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
+index 3a4b3e7b..e3f2ba94 100644
+--- a/arch/arm/mm/proc-v7-2level.S
++++ b/arch/arm/mm/proc-v7-2level.S
+@@ -46,18 +46,13 @@ ENTRY(cpu_v7_switch_mm)
+ #ifdef CONFIG_ARM_ERRATA_430973
+ 	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
+ #endif
+-#ifdef CONFIG_ARM_ERRATA_754322
+-	dsb
+-#endif
+-	mcr	p15, 0, r2, c13, c0, 1		@ set reserved context ID
+-	isb
+-1:	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
+-	isb
+ #ifdef CONFIG_ARM_ERRATA_754322
+ 	dsb
+ #endif
+ 	mcr	p15, 0, r1, c13, c0, 1		@ set context ID
+ 	isb
++	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
++	isb
+ #endif
+ 	mov	pc, lr
+ ENDPROC(cpu_v7_switch_mm)
+@@ -106,7 +101,9 @@ ENTRY(cpu_v7_set_pte_ext)
+  ARM(	str	r3, [r0, #2048]! )
+  THUMB(	add	r0, r0, #2048 )
+  THUMB(	str	r3, [r0] )
+-	mcr	p15, 0, r0, c7, c10, 1		@ flush_pte
++	mrc	p15, 0, r3, c0, c1, 7		@ read ID_MMFR3
++	tst	r3, #0xf << 20			@ check the coherent walk bits
++	mcreq	p15, 0, r0, c7, c10, 1		@ clean D-cache to PoU
+ #endif
+ 	mov	pc, lr
+ ENDPROC(cpu_v7_set_pte_ext)
+diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
+index 8de0f1dd..6b306057 100644
+--- a/arch/arm/mm/proc-v7-3level.S
++++ b/arch/arm/mm/proc-v7-3level.S
+@@ -70,7 +70,9 @@ ENTRY(cpu_v7_set_pte_ext)
+ 	tst	r3, #1 << (55 - 32)		@ L_PTE_DIRTY
+ 	orreq	r2, #L_PTE_RDONLY
+ 1:	strd	r2, r3, [r0]
+-	mcr	p15, 0, r0, c7, c10, 1		@ flush_pte
++	mrc	p15, 0, r3, c0, c1, 7		@ read ID_MMFR3
++	tst	r3, #0xf << 20			@ check the coherent walk bits
++	mcreq	p15, 0, r0, c7, c10, 1		@ clean D-cache to PoU
+ #endif
+ 	mov	pc, lr
+ ENDPROC(cpu_v7_set_pte_ext)
+diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
+index f1c8486f..c32e5cfc 100644
+--- a/arch/arm/mm/proc-v7.S
++++ b/arch/arm/mm/proc-v7.S
+@@ -98,9 +98,11 @@ ENTRY(cpu_v7_do_suspend)
+ 	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+ 	mrc	p15, 0, r5, c13, c0, 3	@ User r/o thread ID
+ 	stmia	r0!, {r4 - r5}
++#ifdef CONFIG_MMU
+ 	mrc	p15, 0, r6, c3, c0, 0	@ Domain ID
+ 	mrc	p15, 0, r7, c2, c0, 1	@ TTB 1
+ 	mrc	p15, 0, r11, c2, c0, 2	@ TTB control register
++#endif
+ 	mrc	p15, 0, r8, c1, c0, 0	@ Control register
+ 	mrc	p15, 0, r9, c1, c0, 1	@ Auxiliary control register
+ 	mrc	p15, 0, r10, c1, c0, 2	@ Co-processor access control
+@@ -110,13 +112,14 @@ ENDPROC(cpu_v7_do_suspend)
+ 
+ ENTRY(cpu_v7_do_resume)
+ 	mov	ip, #0
+-	mcr	p15, 0, ip, c8, c7, 0	@ invalidate TLBs
+ 	mcr	p15, 0, ip, c7, c5, 0	@ invalidate I cache
+ 	mcr	p15, 0, ip, c13, c0, 1	@ set reserved context ID
+ 	ldmia	r0!, {r4 - r5}
+ 	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+ 	mcr	p15, 0, r5, c13, c0, 3	@ User r/o thread ID
+ 	ldmia	r0, {r6 - r11}
++#ifdef CONFIG_MMU
++	mcr	p15, 0, ip, c8, c7, 0	@ invalidate TLBs
+ 	mcr	p15, 0, r6, c3, c0, 0	@ Domain ID
+ #ifndef CONFIG_ARM_LPAE
+ 	ALT_SMP(orr	r1, r1, #TTB_FLAGS_SMP)
+@@ -125,14 +128,15 @@ ENTRY(cpu_v7_do_resume)
+ 	mcr	p15, 0, r1, c2, c0, 0	@ TTB 0
+ 	mcr	p15, 0, r7, c2, c0, 1	@ TTB 1
+ 	mcr	p15, 0, r11, c2, c0, 2	@ TTB control register
+-	mrc	p15, 0, r4, c1, c0, 1	@ Read Auxiliary control register
+-	teq	r4, r9			@ Is it already set?
+-	mcrne	p15, 0, r9, c1, c0, 1	@ No, so write it
+-	mcr	p15, 0, r10, c1, c0, 2	@ Co-processor access control
+ 	ldr	r4, =PRRR		@ PRRR
+ 	ldr	r5, =NMRR		@ NMRR
+ 	mcr	p15, 0, r4, c10, c2, 0	@ write PRRR
+ 	mcr	p15, 0, r5, c10, c2, 1	@ write NMRR
++#endif	/* CONFIG_MMU */
++	mrc	p15, 0, r4, c1, c0, 1	@ Read Auxiliary control register
++	teq	r4, r9			@ Is it already set?
++	mcrne	p15, 0, r9, c1, c0, 1	@ No, so write it
++	mcr	p15, 0, r10, c1, c0, 2	@ Co-processor access control
+ 	isb
+ 	dsb
+ 	mov	r0, r8			@ control register
+@@ -254,6 +258,18 @@ __v7_setup:
+ 	ldr	r6, =NMRR			@ NMRR
+ 	mcr	p15, 0, r5, c10, c2, 0		@ write PRRR
+ 	mcr	p15, 0, r6, c10, c2, 1		@ write NMRR
++#endif
++#ifndef CONFIG_ARM_THUMBEE
++	mrc	p15, 0, r0, c0, c1, 0		@ read ID_PFR0 for ThumbEE
++	and	r0, r0, #(0xf << 12)		@ ThumbEE enabled field
++	teq	r0, #(1 << 12)			@ check if ThumbEE is present
++	bne	1f
++	mov	r5, #0
++	mcr	p14, 6, r5, c1, c0, 0		@ Initialize TEEHBR to 0
++	mrc	p14, 6, r0, c0, c0, 0		@ load TEECR
++	orr	r0, r0, #1			@ set the 1st bit in order to
++	mcr	p14, 6, r0, c0, c0, 0		@ stop userspace TEEHBR access
++1:
+ #endif
+ 	adr	r5, v7_crval
+ 	ldmia	r5, {r5, r6}
+diff --git a/arch/arm/mm/tlb-fa.S b/arch/arm/mm/tlb-fa.S
+index d3ddcf9a..284370b1 100644
+--- a/arch/arm/mm/tlb-fa.S
++++ b/arch/arm/mm/tlb-fa.S
+@@ -34,10 +34,12 @@
+  */
+ 	.align	4
+ ENTRY(fa_flush_user_tlb_range)
++#ifndef CONFIG_SMP
+ 	vma_vm_mm ip, r2
+ 	act_mm	r3				@ get current->active_mm
+ 	eors	r3, ip, r3			@ == mm ?
+ 	movne	pc, lr				@ no, we dont do anything
++#endif
+ 	mov	r3, #0
+ 	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
+ 	bic	r0, r0, #0x0ff
+diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
+index 4e0a3716..43eb79f6 100644
+--- a/arch/arm/oprofile/common.c
++++ b/arch/arm/oprofile/common.c
+@@ -40,6 +40,8 @@ char *op_name_from_perf_id(void)
+ 		return "arm/armv7";
+ 	case ARM_PERF_PMU_ID_CA9:
+ 		return "arm/armv7-ca9";
++	case ARM_PERF_PMU_ID_FMP626:
++		return "arm/fmp626";
+ 	default:
+ 		return NULL;
+ 	}
+diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
+index f9c9f33f..f0b01b3a 100644
+--- a/arch/arm/tools/mach-types
++++ b/arch/arm/tools/mach-types
+@@ -153,6 +153,8 @@ anubis			MACH_ANUBIS		ANUBIS			734
+ akita			MACH_AKITA		AKITA			744
+ e330			MACH_E330		E330			753
+ nokia770		MACH_NOKIA770		NOKIA770		755
++GM			    MACH_GM		        GM			758
++faraday			MACH_FARADAY		FARADAY			759
+ carmeva			MACH_CARMEVA		CARMEVA			769
+ edb9315a		MACH_EDB9315A		EDB9315A		772
+ stargate2		MACH_STARGATE2		STARGATE2		774
+diff --git a/arch/microblaze/boot/dts/system.dts b/arch/microblaze/boot/dts/system.dts
+deleted file mode 120000
+index 7cb65789..00000000
+--- a/arch/microblaze/boot/dts/system.dts
++++ /dev/null
+@@ -1 +0,0 @@
+-../../platform/generic/system.dts
+\ No newline at end of file
+diff --git a/arch/microblaze/boot/dts/system.dts b/arch/microblaze/boot/dts/system.dts
+new file mode 100644
+index 00000000..7cb65789
+--- /dev/null
++++ b/arch/microblaze/boot/dts/system.dts
+@@ -0,0 +1 @@
++../../platform/generic/system.dts
+\ No newline at end of file
+diff --git a/build b/build
+new file mode 100644
+index 00000000..3c449819
+--- /dev/null
++++ b/build
+@@ -0,0 +1,6 @@
++rm -f ./usr/initramfs_data.cpio.gz
++make
++sudo cp arch/arm/boot/zImage /tftpboot/mbootpImage
++sudo cp -f System.map /tftpboot/
++sudo cp -f vmlinux /tftpboot/
++sudo chown nobody:nobody /tftpboot/mbootpImage
+diff --git a/build_uImage_8136 b/build_uImage_8136
+new file mode 100644
+index 00000000..e71c3c56
+--- /dev/null
++++ b/build_uImage_8136
+@@ -0,0 +1,9 @@
++rm -f ./usr/initramfs_data.cpio.gz
++make
++cp -f arch/arm/boot/zImage /tftpboot/mbootpImage
++cp -f System.map /tftpboot/
++cp -f vmlinux /tftpboot/
++sudo chown nobody:nobody /tftpboot/mbootpImage
++./mkimage -A arm -O linux -T kernel -C none -a 2000000 -e 2000040 -n gm8136 -d arch/arm/boot/zImage arch/arm/boot/uImage
++cp -f arch/arm/boot/uImage /tftpboot/uImage_8136
++sudo chown nobody:nobody /tftpboot/uImage_8136
+diff --git a/build_uImage_813x b/build_uImage_813x
+new file mode 100644
+index 00000000..a7d4a760
+--- /dev/null
++++ b/build_uImage_813x
+@@ -0,0 +1,9 @@
++rm -f ./usr/initramfs_data.cpio.gz
++make
++cp -f arch/arm/boot/zImage /tftpboot/mbootpImage
++cp -f System.map /tftpboot/
++cp -f vmlinux /tftpboot/
++sudo chown nobody:nobody /tftpboot/mbootpImage
++./mkimage -A arm -O linux -T kernel -C none -a 2000000 -e 2000040 -n gm813x -d arch/arm/boot/zImage arch/arm/boot/uImage
++cp -f arch/arm/boot/uImage /tftpboot/uImage_813x
++sudo chown nobody:nobody /tftpboot/uImage_813x
+diff --git a/build_uImage_8210 b/build_uImage_8210
+new file mode 100644
+index 00000000..d2370ecc
+--- /dev/null
++++ b/build_uImage_8210
+@@ -0,0 +1,9 @@
++rm -f ./usr/initramfs_data.cpio.gz
++make
++cp -f arch/arm/boot/zImage /tftpboot/mbootpImage
++cp -f System.map /tftpboot/
++cp -f vmlinux /tftpboot/
++sudo chown nobody:nobody /tftpboot/mbootpImage
++./mkimage -A arm -O linux -T kernel -C none -a 2000000 -e 2000040 -n gm8210 -d arch/arm/boot/zImage arch/arm/boot/uImage
++cp -f arch/arm/boot/uImage /tftpboot/uImage_8210
++sudo chown nobody:nobody /tftpboot/uImage_8210
+diff --git a/build_uImage_8220 b/build_uImage_8220
+new file mode 100644
+index 00000000..05cbab3a
+--- /dev/null
++++ b/build_uImage_8220
+@@ -0,0 +1,11 @@
++rm -f ./usr/initramfs_data.cpio.gz
++make
++#cores=`grep 'processor' /proc/cpuinfo | sort -u | wc -l`
++#make -j$cores
++cp -f arch/arm/boot/zImage /tftpboot/mbootpImage
++cp -f System.map /tftpboot/
++cp -f vmlinux /tftpboot/
++sudo chown nobody:nobody /tftpboot/mbootpImage
++#./mkimage -A arm -O linux -T kernel -C none -a 2000000 -e 2000040 -n gm8220 -d arch/arm/boot/zImage arch/arm/boot/uImage
++#cp -f arch/arm/boot/uImage /tftpboot/uImage_8220
++#sudo chown nobody:nobody /tftpboot/uImage_8220
+diff --git a/build_uImage_828x b/build_uImage_828x
+new file mode 100644
+index 00000000..e89b780d
+--- /dev/null
++++ b/build_uImage_828x
+@@ -0,0 +1,9 @@
++rm -f ./usr/initramfs_data.cpio.gz
++make
++cp -f arch/arm/boot/zImage /tftpboot/mbootpImage
++cp -f System.map /tftpboot/
++cp -f vmlinux /tftpboot/
++sudo chown nobody:nobody /tftpboot/mbootpImage
++./mkimage -A arm -O linux -T kernel -C none -a 2000000 -e 2000040 -n gm828x -d arch/arm/boot/zImage arch/arm/boot/uImage
++cp -f arch/arm/boot/uImage /tftpboot/uImage_828x
++sudo chown nobody:nobody /tftpboot/uImage_828x
+diff --git a/cross_compiler_def b/cross_compiler_def
+new file mode 100644
+index 00000000..0f662c61
+--- /dev/null
++++ b/cross_compiler_def
+@@ -0,0 +1 @@
++CROSS_COMPILE=/usr/src/arm-linux-3.3/toolchain_gnueabi-4.4.0_ARMv5TE/usr/bin/arm-unknown-linux-uclibcgnueabi-
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index 6bdedd7c..40c95848 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -83,6 +83,25 @@ config SATA_AHCI_PLATFORM
+ 
+ 	  If unsure, say N.
+ 
++config EXTERNAL_CRYSTAL_CLOCK
++	bool "Select external crystal as clock source for SATA PHY"
++	default n
++	depends on SATA_AHCI_PLATFORM && PLATFORM_GM8210
++	help
++	  This option selects external crystal as the clock source for SATA PHY.
++
++	  If unsure, say N.
++
++config EP_SATA_ENABLE
++	bool "Manage GM SATA on EP"
++	default n
++	depends on SATA_AHCI_PLATFORM && PLATFORM_GM8210 && GM8210_EP_MODE
++	help
++	  This option is only valid on dual chip platform.
++
++	  Only one side can manage SATA controller at the same time, if you want to
++	  opterate SATA controller on slave chip, say Y here.
++
+ config SATA_FSL
+ 	tristate "Freescale 3.0Gbps SATA support"
+ 	depends on FSL_SOC
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 48be4e18..db2e91eb 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -22,10 +22,99 @@
+ #include <linux/libata.h>
+ #include <linux/ahci_platform.h>
+ #include "ahci.h"
++#include <linux/proc_fs.h>
++#include <asm/uaccess.h>
++#include <mach/platform/board.h>
++#ifdef CONFIG_PLATFORM_GM8210
++#include <mach/fmem.h>
++#include <mach/ftpmu010_pcie.h>
++#endif
++#ifdef CONFIG_PLATFORM_GM8287
++#include <mach/ftpmu010.h>
++#endif
++
++
++#define DRV_NAME	"FTSATA100_AHCI"
++#define DRV_VERSION	"0.15"
++
++#define SATA_PHY_CLK    30000000
++
++#define ENABLE_INTERNAL_RESISTER    // only valid on GM8287 series
++#define ENABLE_NCQ_CAP              // turn on NCQ capibility
++
++#define SATAPHY_CFG_ISATA       0x11
++#define SATAPHY_CFG_ESATA       0x22
++#define FTSATA100_SET_PHY_SATA0 0x33
++#define FTSATA100_SET_PHY_SATA1 0x44
++#define FTSATA100_SET_PHY_SATA2 0x55
++#define FTSATA100_SET_PHY_SATA3 0x66
++
++#define MAX_SATAC_NUM	4
++#define MAX_NAME_SZ		10
++
++#ifdef CONFIG_PLATFORM_GM8210
++static void __iomem *h2x_sata0_va_base;
++static void __iomem *h2x_sata1_va_base;
++static void __iomem *h2x_sata2_va_base;
++static void __iomem *h2x_sata3_va_base;
++static void __iomem *pcie_va_base;
++static void __iomem *i2c0_sataphy_va_base;
++static void __iomem *i2c1_sataphy_va_base;
++static void __iomem *i2c2_sataphy_va_base;
++static void __iomem *i2c3_sataphy_va_base;
++#endif
++#ifdef CONFIG_PLATFORM_GM8287
++static void __iomem *i2c3_sataphy_va_base;
++static void __iomem *i2c4_sataphy_va_base;
++#endif
++
++static u8 i2c_sladdr_r, i2c_sladdr_w;
++static u32 plat_id;
++
++struct proc_dir_entry *p_root = NULL;
++static struct proc_dir_entry *p_host[MAX_SATAC_NUM];
++static struct proc_dir_entry *p_phy_i2c_reg[MAX_SATAC_NUM];
++
++#ifdef CONFIG_PLATFORM_GM8210
++static fmem_pci_id_t pci_id;
++static fmem_cpu_id_t cpu_id;
++
++#ifdef CONFIG_EP_SATA_ENABLE
++static void __iomem *slave_8210_pmu_va_base;
++struct s_ftsata100_host {
++    spinlock_t      lock;
++    //struct device   *dev;
++    void __iomem    *mmio;
++    //unsigned int    n_ports;
++    //void            *private_data;
++    //unsigned long   flags;
++    unsigned int    id;
++} ftsata100_host[MAX_SATAC_NUM];
++#endif
++#endif
++
++static struct s_host_port {
++	unsigned int	id;
++	unsigned char	name[MAX_NAME_SZ];
++	void __iomem	*mmio_base;
++} host_port[MAX_SATAC_NUM];
++
++enum {
++	PLAT_8312_ID    = 0x831200,
++    PLAT_8287_ID    = 0x828710,
++	PLAT_END_ID     = 0xffffff
++};
++
++enum {
++	SPEED_GEN1	= 1,
++	SPEED_GEN2	= 2,
++	SPEED_GNE3	= 3
++};
+ 
+ enum ahci_type {
+ 	AHCI,		/* standard platform ahci */
+ 	IMX53_AHCI,	/* ahci on i.mx53 */
++	FTSATA100_AHCI,  /* ahci on FTSATA100 */
+ };
+ 
+ static struct platform_device_id ahci_devtype[] = {
+@@ -35,13 +124,15 @@ static struct platform_device_id ahci_devtype[] = {
+ 	}, {
+ 		.name = "imx53-ahci",
+ 		.driver_data = IMX53_AHCI,
++	}, {
++		.name = "ftsata100",
++		.driver_data = FTSATA100_AHCI,
+ 	}, {
+ 		/* sentinel */
+ 	}
+ };
+ MODULE_DEVICE_TABLE(platform, ahci_devtype);
+ 
+-
+ static const struct ata_port_info ahci_port_info[] = {
+ 	/* by features */
+ 	[AHCI] = {
+@@ -56,12 +147,648 @@ static const struct ata_port_info ahci_port_info[] = {
+ 		.udma_mask	= ATA_UDMA6,
+ 		.port_ops	= &ahci_pmp_retry_srst_ops,
+ 	},
++	[FTSATA100_AHCI] = {
++#ifdef ENABLE_NCQ_CAP
++		.private_data	= (void *)(AHCI_HFLAG_YES_NCQ),
++#else
++		.private_data   = (void *)(AHCI_HFLAG_NO_NCQ),
++#endif
++		.flags		= AHCI_FLAG_COMMON,
++		.pio_mask	= ATA_PIO4,
++		.udma_mask	= ATA_UDMA6,
++		.port_ops	= &ahci_pmp_retry_srst_ops,
++	},
+ };
+ 
+ static struct scsi_host_template ahci_platform_sht = {
+ 	AHCI_SHT("ahci_platform"),
+ };
+ 
++void ftsata100_dump_reg(struct ata_port *ap)
++{
++	struct ahci_host_priv *hpriv = ap->host->private_data;
++	void __iomem *mmio = hpriv->mmio;
++	struct ahci_port_priv *pp = ap->private_data;
++	struct ahci_sg *ftsata100_sg;
++	u32 *pfis, i, rec_n_sg;
++
++	printk(KERN_WARNING "ata%u: dump register contents\n", ap->print_id);
++	printk("   CAP(0x00)  = %#x\n", readl(mmio+0x00));
++	printk("    IS(0x08)  = %#x\n", readl(mmio+0x08));
++	printk("    PI(0x0C)  = %#x\n", readl(mmio+0x0c));
++	printk("TCOUNT(0xA0)  = %#x\n", readl(mmio+0xa0));
++	printk("   FEA(0xA4)  = %#x\n", readl(mmio+0xa4));
++	printk(" P0CLB(0x100) = %#x\n", readl(mmio+0x100));
++	printk("  P0FB(0x108) = %#x\n", readl(mmio+0x108));
++	printk("  P0IS(0x110) = %#x\n", readl(mmio+0x110));
++	printk("  P0IE(0x114) = %#x\n", readl(mmio+0x114));
++	printk(" P0CMD(0x118) = %#x\n", readl(mmio+0x118));
++	printk(" P0TFD(0x120) = %#x\n", readl(mmio+0x120));
++	printk("P0SSTS(0x128) = %#x\n", readl(mmio+0x128));
++	printk("P0SCTL(0x12C) = %#x\n", readl(mmio+0x12c));
++	printk("P0SERR(0x130) = %#x\n", readl(mmio+0x130));
++	printk("P0SACT(0x134) = %#x\n", readl(mmio+0x134));
++	printk("  P0CI(0x138) = %#x\n", readl(mmio+0x138));
++	printk(" P0FCR(0x170) = %#x\n", readl(mmio+0x170));
++	printk("P0BIST(0x174) = %#x\n", readl(mmio+0x174));
++	printk(" P0FSM(0x17C) = %#x\n", readl(mmio+0x17c));
++	printk("\n");
++
++	printk(KERN_WARNING "ata%u: dump command header 0\n", ap->print_id);
++	printk("DW0 = %#x\n", pp->cmd_slot[0].opts);
++	printk("DW1 = %#x\n", pp->cmd_slot[0].status);
++	printk("DW2 = %#x\n", pp->cmd_slot[0].tbl_addr);
++	printk("DW3 = %#x\n", pp->cmd_slot[0].tbl_addr_hi);
++	printk("\n");
++
++    rec_n_sg = (pp->cmd_slot[0].opts >> 16) & 0xFFFF;
++
++	printk(KERN_WARNING "ata%u: dump command table 0\n", ap->print_id);
++	pfis = (u32 *) pp->cmd_tbl;
++	printk("DW0 = %#x\n", *(pfis+0));
++	printk("DW1 = %#x\n", *(pfis+1));
++	printk("DW2 = %#x\n", *(pfis+2));
++	printk("DW3 = %#x\n", *(pfis+3));
++	printk("DW4 = %#x\n", *(pfis+4));
++	printk("\n");
++
++	printk(KERN_WARNING "ata%u: dump PRD table\n", ap->print_id);
++	ftsata100_sg = pp->cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
++	for (i=0; i<rec_n_sg; i++) {
++		printk("-- item %d --\n", i);
++		printk("DW0 = %#x\n", ftsata100_sg->addr);
++		printk("DW1 = %#x\n", ftsata100_sg->addr_hi);
++		printk("DW3 = %#x\n", ftsata100_sg->flags_size);
++		ftsata100_sg++;
++	}
++	printk("\n");
++
++}
++
++#define I2C_ALIEN                   0x2000  /* Arbitration lose */
++#define I2C_SAMIEN                  0x1000  /* slave address match */
++#define I2C_STOPIEN                 0x800   /* stop condition */
++#define I2C_BERRIEN                 0x400   /* non ACK response */
++#define I2C_DRIEN                   0x200   /* data receive */
++#define I2C_DTIEN                   0x100   /* data transmit */
++#define I2C_TBEN                    0x80    /* transfer byte enable */
++#define I2C_ACKNAK                  0x40    /* ack sent */
++#define I2C_STOP                    0x20    /* stop */
++#define I2C_START                   0x10    /* start */
++#define I2C_GCEN                    0x8     /* general call */
++#define I2C_SCLEN                   0x4     /* enable clock */
++#define I2C_I2CEN                   0x2     /* enable I2C */
++#define I2C_I2CRST                  0x1     /* reset I2C */
++#define I2C_ENABLE                  (I2C_ALIEN|I2C_SAMIEN|I2C_STOPIEN|I2C_BERRIEN|I2C_DRIEN|I2C_DTIEN|I2C_SCLEN|I2C_I2CEN)
++
++static inline s8 i2c_do_read(void __iomem *i2c_base, u8 *data, u32 ctrl)
++{
++    u32 i;
++
++    writel(ctrl, i2c_base + 0x00);
++
++    for (i = 0; i < 100; i++) {
++        if (readl(i2c_base + 0x04) & 0x20) {
++            *data = (u8) readl(i2c_base + 0x0C);
++            return 0;
++        }
++        udelay(10);
++    }
++    printk("%s: timeouted on rx data\n", __func__);
++    return -1; /* check status timeouted */
++}
++
++static inline s8 i2c_do_write(void __iomem *i2c_base, u8 data, u32 ctrl)
++{
++    u32 i;
++
++    writel(data, i2c_base + 0x0C);
++    writel(ctrl, i2c_base + 0x00);
++
++    for (i = 0; i < 100; i++) {
++        if (readl(i2c_base + 0x04) & 0x10)
++            return 0;
++        udelay(10);
++    }
++    printk("%s: timeouted on tx data\n", __func__);
++    return -1; /* check status timeouted */
++}
++
++static inline s8 i2c_read_byte(void __iomem *i2c_base, u8 addr, u8 idx, u8 *data)
++{
++    if (i2c_do_write(i2c_base, addr&0xFE, I2C_ENABLE|I2C_TBEN|I2C_START) < 0)
++        return -1;
++    if (i2c_do_write(i2c_base, idx, I2C_ENABLE|I2C_TBEN) < 0)
++        return -1;
++    if (i2c_do_write(i2c_base, addr, I2C_ENABLE|I2C_TBEN|I2C_START) < 0)
++        return -1;
++    if (i2c_do_read(i2c_base, data, I2C_ENABLE|I2C_TBEN|I2C_STOP|I2C_ACKNAK) < 0)
++        return -1;
++
++    return 0;
++}
++
++static inline s8 i2c_write_byte(void __iomem *i2c_base, u8 addr, u8 idx, u8 data)
++{
++    if (i2c_do_write(i2c_base, addr, I2C_ENABLE|I2C_TBEN|I2C_START) < 0)
++        return -1;
++    if (i2c_do_write(i2c_base, idx, I2C_ENABLE|I2C_TBEN) < 0)
++        return -1;
++    if (i2c_do_write(i2c_base, data, I2C_ENABLE|I2C_TBEN|I2C_STOP) < 0)
++        return -1;
++
++    return 0;
++}
++
++static int proc_read_phy_i2c_reg(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    unsigned int len = 0;
++
++    len += sprintf(page+len,
++            "Usage :\n"
++            "    echo reg_offset [data] > phy_i2c_reg\n"
++            "Parameter :\n"
++            "    reg_offset = minor address to access on phy (hex)\n"
++            "          data = data to write, if specified (hex)\n"
++            );
++
++    return len;
++}
++
++static int proc_write_phy_i2c_reg(struct file *file, const char *buffer,unsigned long count, void *data)
++{
++    unsigned int ret = 0, regoff = 0, val = 0;
++    unsigned char value[20];
++    struct s_host_port *pdev_info = (struct s_host_port *) data;
++    void __iomem *i2c_base;
++
++    if (copy_from_user(value, buffer, count))
++        return -EFAULT;
++
++    value[count] = '\0';
++    ret = sscanf(value, "%x %x\n", &regoff, &val);
++
++#ifdef CONFIG_PLATFORM_GM8210
++    switch (pdev_info->id) {
++        case 0:
++            i2c_base = i2c0_sataphy_va_base;
++            break;
++        case 1:
++            i2c_base = i2c1_sataphy_va_base;
++            break;
++        case 2:
++            i2c_base = i2c2_sataphy_va_base;
++            break;
++        case 3:
++            i2c_base = i2c3_sataphy_va_base;
++            break;
++        default:
++            BUG();
++    }
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8287
++    switch (pdev_info->id) {
++        case 0:
++            i2c_base = i2c3_sataphy_va_base;
++            break;
++        case 1:
++            i2c_base = i2c4_sataphy_va_base;
++            break;
++        default:
++            BUG();
++    }
++#endif
++
++    if (ret == 1) {
++        i2c_read_byte(i2c_base, i2c_sladdr_r, regoff, (u8 *) &val);
++        printk("%#x\n", val);
++    } else if (ret == 2) {
++        i2c_write_byte(i2c_base, i2c_sladdr_w, regoff, (u8) val);
++    }
++
++    return count;
++}
++
++static void ftsata100_proc_init(struct ata_port *ap)
++{
++    unsigned int id = ap->print_id - 1;
++
++    memset(&host_port[id], 0, sizeof(host_port[id]));
++
++    host_port[id].id = id;
++    snprintf(host_port[id].name, MAX_NAME_SZ, "%s%d", "host", id);
++    host_port[id].mmio_base = ahci_port_base(ap);
++
++    if (p_root == NULL) {
++        p_root = create_proc_entry("ftsata", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    }
++
++    p_host[id] = create_proc_entry(host_port[id].name, S_IFDIR | S_IRUGO | S_IXUGO, p_root);
++
++    p_phy_i2c_reg[id] = create_proc_entry("phy_i2c_reg", S_IRUGO | S_IWUGO, p_host[id]);
++    p_phy_i2c_reg[id]->read_proc = (read_proc_t *) proc_read_phy_i2c_reg;
++    p_phy_i2c_reg[id]->write_proc = (write_proc_t *) proc_write_phy_i2c_reg;
++    p_phy_i2c_reg[id]->data = (void *) &host_port[id];
++}
++
++static void ftsata100_proc_remove(struct ata_port *ap)
++{
++    unsigned int id = ap->print_id - 1;
++
++    if (p_host[id]) {
++        if (p_phy_i2c_reg[id])
++            remove_proc_entry(p_phy_i2c_reg[id]->name, p_host[id]);
++
++        remove_proc_entry(p_host[id]->name, p_root);
++        p_host[id] = NULL;
++    }
++
++    //if ((p_host[0]==NULL) && (p_host[1]==NULL))
++    //	remove_proc_entry(p_root->name, NULL);
++}
++
++static inline void ftsata100_phy_parameter_setting(u32 satac_id, u32 phy_cfg)
++{
++    void __iomem *i2c_base;
++    u32 c_id;
++	u8 t_idx, t_val;
++
++#ifdef CONFIG_PLATFORM_GM8210
++    switch (satac_id) {
++        case FTSATA100_SET_PHY_SATA0:
++            c_id = 0;
++            i2c_base = i2c0_sataphy_va_base;
++            break;
++        case FTSATA100_SET_PHY_SATA1:
++            c_id = 1;
++            i2c_base = i2c1_sataphy_va_base;
++            break;
++        case FTSATA100_SET_PHY_SATA2:
++            c_id = 2;
++            i2c_base = i2c2_sataphy_va_base;
++            break;
++        case FTSATA100_SET_PHY_SATA3:
++            c_id = 3;
++            i2c_base = i2c3_sataphy_va_base;
++            break;
++    }
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8287
++        switch (satac_id) {
++            case FTSATA100_SET_PHY_SATA0:
++                c_id = 0;
++                i2c_base = i2c3_sataphy_va_base;
++                break;
++            case FTSATA100_SET_PHY_SATA1:
++                c_id = 1;
++                i2c_base = i2c4_sataphy_va_base;
++                break;
++        }
++#endif
++
++	printk("GM SATA%u config %s PHY setting\n", c_id,
++            (phy_cfg == SATAPHY_CFG_ISATA ? "iSATA" : "eSATA"));
++
++    switch (plat_id) {
++        case PLAT_8312_ID:
++            switch (phy_cfg) {
++                case SATAPHY_CFG_ISATA:
++                    /* parameter 1 */
++                    t_idx = 0x03;
++                    t_val = 0x40;
++                    if (i2c_write_byte(i2c_base, i2c_sladdr_w, t_idx, t_val) < 0)
++                        goto get_exit;
++                    printk("GM SATA%u PHY program i2c register offset 0x%02x, value=0x%02x\n",
++                            c_id, t_idx, t_val);
++                    break;
++                case SATAPHY_CFG_ESATA:
++                    /* parameter 1 */
++                    t_idx = 0x03;
++                    t_val = 0x40;
++                    if (i2c_write_byte(i2c_base, i2c_sladdr_w, t_idx, t_val) < 0)
++                        goto get_exit;
++                    printk("GM SATA%u PHY program i2c register offset 0x%02x, value=0x%02x\n",
++                            c_id, t_idx, t_val);
++                    break;
++            }
++            break;
++        case PLAT_8287_ID:
++            switch (phy_cfg) {
++                case SATAPHY_CFG_ISATA:
++#ifdef ENABLE_INTERNAL_RESISTER
++                    /* config setting of internal resister */
++                    /* parameter 1 */
++                    t_idx = 0x07;
++                    t_val = 0x09;
++                    if (i2c_write_byte(i2c_base, i2c_sladdr_w, t_idx, t_val) < 0)
++                        goto get_exit;
++                    printk("GM SATA%u PHY program i2c register offset 0x%02x, value=0x%02x\n",
++                            c_id, t_idx, t_val);
++                    /* parameter 2 */
++                    t_idx = 0x19;
++                    t_val = 0x0C;
++                    if (i2c_write_byte(i2c_base, i2c_sladdr_w, t_idx, t_val) < 0)
++                        goto get_exit;
++                    printk("GM SATA%u PHY program i2c register offset 0x%02x, value=0x%02x\n",
++                            c_id, t_idx, t_val);
++                    /* parameter 3 */
++                    t_idx = 0x35;
++                    t_val = 0x10;
++                    if (i2c_write_byte(i2c_base, i2c_sladdr_w, t_idx, t_val) < 0)
++                        goto get_exit;
++                    printk("GM SATA%u PHY program i2c register offset 0x%02x, value=0x%02x\n",
++                            c_id, t_idx, t_val);
++                    /* parameter 4 */
++                    t_idx = 0x36;
++                    t_val = 0x80;
++                    if (i2c_write_byte(i2c_base, i2c_sladdr_w, t_idx, t_val) < 0)
++                        goto get_exit;
++                    printk("GM SATA%u PHY program i2c register offset 0x%02x, value=0x%02x\n",
++                            c_id, t_idx, t_val);
++#endif
++                    break;
++                case SATAPHY_CFG_ESATA:
++                    /* use default value */
++                    break;
++            }
++            break;
++        default:
++            printk("GM SATA >>> unknow platform id %#x\n", plat_id);
++            BUG();
++            break;
++    }
++
++get_exit:
++	return;
++}
++
++static inline void ftsata100_phy_config(void)
++{
++    u32 i2c_clock_off = 0, i2c_gsr = 0x02, i2c_tsr = 0x27, i2c_count;
++    u32 scl_clock = 120*1000;
++
++#ifdef CONFIG_PLATFORM_GM8210
++    i2c_clock_off = (readl(PCIPMU_FTPMU010_VA_BASE + 0x34) >> 19) & 0xF;
++
++    if (i2c_clock_off) {
++        /* turn on I2C clock */
++        writel((readl(PCIPMU_FTPMU010_VA_BASE + 0x34) & ~(0xF << 19)), PCIPMU_FTPMU010_VA_BASE + 0x34);
++        mdelay(5);
++        i2c_clock_off = 0;
++    }
++
++    /* config TGSR register of I2C_0 */
++    writel((i2c_gsr << 10) | i2c_tsr, i2c0_sataphy_va_base + 0x14);
++    /* config TGSR register of I2C_1 */
++    writel((i2c_gsr << 10) | i2c_tsr, i2c1_sataphy_va_base + 0x14);
++    /* config TGSR register of I2C_2 */
++    writel((i2c_gsr << 10) | i2c_tsr, i2c2_sataphy_va_base + 0x14);
++    /* config TGSR register of I2C_3 */
++    writel((i2c_gsr << 10) | i2c_tsr, i2c3_sataphy_va_base + 0x14);
++
++    /* compute I2C clock division */
++    i2c_count = (((50000000)/scl_clock)-i2c_gsr)/2-2;
++    //printk("--> i2c_count = %d\n", i2c_count);
++
++    /* config CDR register of I2C_0 */
++    writel(i2c_count, i2c0_sataphy_va_base + 0x08);
++    /* config CDR register of I2C_1 */
++    writel(i2c_count, i2c1_sataphy_va_base + 0x08);
++    /* config CDR register of I2C_2 */
++    writel(i2c_count, i2c2_sataphy_va_base + 0x08);
++    /* config CDR register of I2C_3 */
++    writel(i2c_count, i2c3_sataphy_va_base + 0x08);
++
++    ftsata100_phy_parameter_setting(FTSATA100_SET_PHY_SATA0, SATAPHY_CFG_ISATA);
++    ftsata100_phy_parameter_setting(FTSATA100_SET_PHY_SATA1, SATAPHY_CFG_ISATA);
++    ftsata100_phy_parameter_setting(FTSATA100_SET_PHY_SATA2, SATAPHY_CFG_ISATA);
++    ftsata100_phy_parameter_setting(FTSATA100_SET_PHY_SATA3, SATAPHY_CFG_ISATA);
++#endif //#ifdef CONFIG_PLATFORM_GM8210
++
++#ifdef CONFIG_PLATFORM_GM8287
++    i2c_clock_off = (readl(PMU_FTPMU010_VA_BASE + 0xBC) >> 14) & 0x3;
++
++    if (i2c_clock_off) {
++        /* turn on I2C clock */
++        writel((readl(PMU_FTPMU010_VA_BASE + 0xBC) & ~(0x3 << 14)), PMU_FTPMU010_VA_BASE + 0xBC);
++        mdelay(5);
++        i2c_clock_off = 0;
++    }
++
++    /* config TGSR register of I2C_3 */
++    writel((i2c_gsr << 10) | i2c_tsr, i2c3_sataphy_va_base + 0x14);
++    /* config TGSR register of I2C_4 */
++    writel((i2c_gsr << 10) | i2c_tsr, i2c4_sataphy_va_base + 0x14);
++
++    /* compute I2C clock division */
++    i2c_count = (((50000000)/scl_clock)-i2c_gsr)/2-2;
++    //printk("--> i2c_count = %d\n", i2c_count);
++
++    /* config CDR register of I2C_3 */
++    writel(i2c_count, i2c3_sataphy_va_base + 0x08);
++    /* config CDR register of I2C_4 */
++    writel(i2c_count, i2c4_sataphy_va_base + 0x08);
++
++    ftsata100_phy_parameter_setting(FTSATA100_SET_PHY_SATA0, SATAPHY_CFG_ISATA);
++    ftsata100_phy_parameter_setting(FTSATA100_SET_PHY_SATA1, SATAPHY_CFG_ISATA);
++#endif //#ifdef CONFIG_PLATFORM_GM8287
++
++#if 0
++    if (!i2c_clock_off) {
++        /* turn off I2C clock */
++        writel((readl(PMU_FTPMU010_0_VA_BASE + 0x3C) | (1 << 22)), PMU_FTPMU010_0_VA_BASE + 0x3C);
++        mdelay(5);
++    }
++#endif
++}
++
++int ftsata100_phy_reset(struct ata_link *link)
++{
++    u32 sstatus, scontrol;
++    int rc = -1;
++
++    sata_scr_read(link, SCR_STATUS, &sstatus);
++
++    /* if device is detected, but PHY communication not established, wait for a while */
++    if ((sstatus & 0xF) == 1) {
++        u32 i, max_tried = 3000;
++        struct ata_port *ap = link->ap;
++        //void __iomem *port_mmio = ahci_port_base(ap);
++        extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
++        extern int sata_set_spd(struct ata_link *link);
++
++        rc = 0;
++#if 1
++		// limit the highest allowable speed to 1.5 Gbps
++		printk("GM SATA%u limit highest allowable speed to 1.5 Gbps\n", ap->print_id - 1);
++        sata_scr_read(link, SCR_CONTROL, &scontrol);
++		scontrol |= 0x10;
++        sata_scr_write_flush(link, SCR_CONTROL, scontrol);
++#else
++        // down speed
++        if (sata_down_spd_limit(link, 0) == 0)
++            sata_set_spd(link);
++#endif
++
++        for (i = 0; i < max_tried; i++) {
++            sata_scr_read(link, SCR_CONTROL, &scontrol);
++            scontrol &= ~0x0F;
++            scontrol |= 0x04;
++            sata_scr_write_flush(link, SCR_CONTROL, scontrol);
++            ata_msleep(ap, 1);
++            sata_scr_read(link, SCR_CONTROL, &scontrol);
++            scontrol &= ~0x0F;
++            sata_scr_write_flush(link, SCR_CONTROL, scontrol);
++            ata_msleep(ap, 3);
++            if (ata_link_online(link)) {
++                link->sata_spd_limit = 1;
++                break;
++            }
++        }
++
++        printk(">>>>>> GM SATA%u: retry POR reset %d times%s\n",
++                ap->print_id-1, i, (i >= max_tried)?", all failed":"");
++    }
++
++    return rc;
++}
++EXPORT_SYMBOL_GPL(ftsata100_phy_reset);
++
++void ftsata100_clk_enable(void)
++{
++#ifdef CONFIG_PLATFORM_GM8210
++    u32 pllout_8312;
++#endif
++#ifdef CONFIG_PLATFORM_GM8287
++    u32 pll5out;
++#endif
++    u32 val, sataphy_clk, sataphy_pvalue;
++
++#ifdef CONFIG_PLATFORM_GM8210
++    pllout_8312 = PCIE_PLL1_CLK_IN;
++
++#ifdef CONFIG_EXTERNAL_CRYSTAL_CLOCK // select external crystal as reference clock input
++    /* set GM8312 SATA PHY clock source to external */
++    printk("GM SATAPHY clock source : SATA0==SATA1, SATA1==SATA2, SATA2==SATA3, SATA3==XTAL\n");
++    val = readl(PCIPMU_FTPMU010_VA_BASE + 0x80);
++    val &= ~(1 << 29);
++    writel(val, PCIPMU_FTPMU010_VA_BASE + 0x80);
++    sataphy_pvalue = 0; // unused variable
++    sataphy_clk = SATA_PHY_CLK;
++#else
++    /* in GM8312, SATA0/1/2/3 PHY clock source default seting is internal */
++    printk("GM SATAPHY clock source : SATA0==PLL, SATA1==SATA0, SATA2==SATA1, SATA3==SATA2\n");
++
++    /* SATA PHY clock pvalue */
++    sataphy_pvalue = (pllout_8312 / 2 / SATA_PHY_CLK) - 1;
++    val = readl(PCIPMU_FTPMU010_VA_BASE + 0x30);
++    val = (val & ~(0x1F << 18)) | (sataphy_pvalue << 18);
++    writel(val, PCIPMU_FTPMU010_VA_BASE + 0x30);
++    val = readl(PCIPMU_FTPMU010_VA_BASE + 0x30);
++    sataphy_pvalue = ( val >> 18) & 0x1F;
++    sataphy_clk = pllout_8312 / 2 / (sataphy_pvalue + 1);
++#endif
++
++    printk(KERN_INFO "GM SATAPHY Clock = %u MHz\n", sataphy_clk / 1000000); // default value in GM8312
++
++    // turn on AHBC clk
++    writel((readl(PCIPMU_FTPMU010_VA_BASE + 0x30) & ~(1 << 10)), PCIPMU_FTPMU010_VA_BASE + 0x30);
++    // turn on INTC clk
++    writel((readl(PCIPMU_FTPMU010_VA_BASE + 0x34) & ~(1 << 8)), PCIPMU_FTPMU010_VA_BASE + 0x34);
++    // turn on SATA HCLK
++    writel((readl(PCIPMU_FTPMU010_VA_BASE + 0x30) & ~0xF), PCIPMU_FTPMU010_VA_BASE + 0x30);
++    mdelay(5);
++    /* SATA PHY PORB & 30MHz */
++    writel((readl(PCIPMU_FTPMU010_VA_BASE + 0x80) & ~(1 << 7)) | 0x40404040, PCIPMU_FTPMU010_VA_BASE + 0x80);
++    mdelay(5);
++
++    /* change H2X write data queue control and prefetch number */
++    writel((readl(h2x_sata0_va_base) & ~(0x3 << 2)) | (0x1 << 2), h2x_sata0_va_base);
++    writel((readl(h2x_sata1_va_base) & ~(0x3 << 2)) | (0x1 << 2), h2x_sata1_va_base);
++    writel((readl(h2x_sata2_va_base) & ~(0x3 << 2)) | (0x1 << 2), h2x_sata2_va_base);
++    writel((readl(h2x_sata3_va_base) & ~(0x3 << 2)) | (0x1 << 2), h2x_sata3_va_base);
++#endif //#ifdef CONFIG_PLATFORM_GM8210
++
++#ifdef CONFIG_PLATFORM_GM8287
++    pll5out = PLL5_CLK_IN;
++
++    /* SATA0/1 PHY clock source default seting is external */
++    printk("GM SATAPHY clock source : SATA0==SATA1, SATA1==PLL\n");
++    val = readl(PMU_FTPMU010_VA_BASE + 0xD4);
++    val |= (1 << 2);
++    /* SATA PHY clock pvalue */
++    sataphy_pvalue = (pll5out / SATA_PHY_CLK) - 1;
++    val = (val & ~(0x3F << 13)) | (sataphy_pvalue << 13);
++    writel(val, PMU_FTPMU010_VA_BASE + 0xD4);
++    val = readl(PMU_FTPMU010_VA_BASE + 0xD4);
++    sataphy_pvalue = ( val >> 13) & 0x3F;
++    sataphy_clk = pll5out / (sataphy_pvalue + 1);
++
++    printk(KERN_INFO "GM SATAPHY Clock = %u MHz\n", sataphy_clk / 1000000);
++
++    val = readl(PMU_FTPMU010_VA_BASE + 0xD0);
++    val |= (1 << 2);
++    writel(val, PMU_FTPMU010_VA_BASE + 0xD0);
++
++    /* SATA PHY PORB & 30MHz */
++    writel(readl(PMU_FTPMU010_VA_BASE + 0xD0) | (1 << 3), PMU_FTPMU010_VA_BASE + 0xD0);
++    writel(readl(PMU_FTPMU010_VA_BASE + 0xD4) | (1 << 3), PMU_FTPMU010_VA_BASE + 0xD4);
++    mdelay(5);
++#endif //#ifdef CONFIG_PLATFORM_GM8287
++}
++
++#ifdef CONFIG_EP_SATA_ENABLE
++/*
++ * get hardware interrupt on 1st 8210, and then
++ * trigger relative software interrupt on 2nd 8210
++ */
++static irqreturn_t ftsata100_interrupt_translate(int irq, void *dev_instance)
++{
++    struct s_ftsata100_host *ft_host = dev_instance;
++    void __iomem *mmio, *port_mmio;
++    u32 irq_stat;
++    int sw_irq;
++
++    mmio = ft_host->mmio;
++    port_mmio = mmio + 0x100; // port no.0
++
++    irq_stat = readl(mmio + HOST_IRQ_STAT);
++    if (!irq_stat)
++        return IRQ_NONE;
++
++    switch (irq) {
++        case SATA_FTSATA100_0_IRQ:
++            sw_irq = CPU_INT_10;
++            break;
++        case SATA_FTSATA100_1_IRQ:
++            sw_irq = CPU_INT_11;
++            break;
++        case SATA_FTSATA100_2_IRQ:
++            sw_irq = CPU_INT_12;
++            break;
++        case SATA_FTSATA100_3_IRQ:
++            sw_irq = CPU_INT_13;
++            break;
++        default:
++            panic(">>>> %s : invalid platform device irq %d\n", __func__, irq);
++    }
++    //printk(">>>> GM SATA : new software interrupt %d\n", sw_irq);
++
++	spin_lock(&ft_host->lock);
++    /* turn IRQ off */
++    writel(0, port_mmio + PORT_IRQ_MASK);
++	writel(irq_stat, mmio + HOST_IRQ_STAT);
++	spin_unlock(&ft_host->lock);
++
++    /* trigger software interrupt on 2nd 8210 */
++    writel(1 << (sw_irq - CPU_INT_BASE), slave_8210_pmu_va_base + 0xA8);
++
++    return IRQ_HANDLED;
++}
++#endif
++
+ static int __init ahci_probe(struct platform_device *pdev)
+ {
+ 	struct device *dev = &pdev->dev;
+@@ -101,11 +828,40 @@ static int __init ahci_probe(struct platform_device *pdev)
+ 	hpriv->flags |= (unsigned long)pi.private_data;
+ 
+ 	hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
++
+ 	if (!hpriv->mmio) {
+ 		dev_err(dev, "can't map %pR\n", mem);
+ 		return -ENOMEM;
+ 	}
+ 
++#ifdef CONFIG_PLATFORM_GM8210
++#ifdef CONFIG_EP_SATA_ENABLE
++    if (pci_id != FMEM_PCI_HOST) {
++        int xlat_irq;
++
++        /* translate hardware irq to software irq on 2nd 8210 */
++        switch (irq) {
++            case SATA_FTSATA100_0_IRQ:
++                xlat_irq = CPU_INT_10;
++                break;
++            case SATA_FTSATA100_1_IRQ:
++                xlat_irq = CPU_INT_11;
++                break;
++            case SATA_FTSATA100_2_IRQ:
++                xlat_irq = CPU_INT_12;
++                break;
++            case SATA_FTSATA100_3_IRQ:
++                xlat_irq = CPU_INT_13;
++                break;
++            default:
++                panic(">>>> %s : invalid platform device irq %d\n", __func__, irq);
++        }
++
++        irq = xlat_irq;
++    }
++#endif
++#endif
++
+ 	/*
+ 	 * Some platforms might need to prepare for mmio region access,
+ 	 * which could be done in the following init call. So, the mmio
+@@ -181,6 +937,9 @@ static int __init ahci_probe(struct platform_device *pdev)
+ 	if (rc)
+ 		goto err0;
+ 
++    /* create host entry under /proc */
++    ftsata100_proc_init(host->ports[0]);
++
+ 	return 0;
+ err0:
+ 	if (pdata && pdata->exit)
+@@ -194,6 +953,9 @@ static int __devexit ahci_remove(struct platform_device *pdev)
+ 	struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ 	struct ata_host *host = dev_get_drvdata(dev);
+ 
++    /* remove host entry under /proc */
++    ftsata100_proc_remove(host->ports[0]);
++
+ 	ata_host_detach(host);
+ 
+ 	if (pdata && pdata->exit)
+@@ -288,12 +1050,137 @@ static struct platform_driver ahci_driver = {
+ 
+ static int __init ahci_init(void)
+ {
++	printk(DRV_NAME " driver version " DRV_VERSION "\n");
++
++#ifdef CONFIG_PLATFORM_GM8210
++    fmem_get_identifier(&pci_id, &cpu_id);
++#ifdef CONFIG_EP_SATA_ENABLE
++    if (cpu_id != FMEM_CPU_FA726)
++        return 0;
++
++    if (pci_id == FMEM_PCI_HOST) {
++        int rc = 0, i, irq;
++        resource_size_t mem, mem_size;
++
++        for (i = 0; i < 4; i++) {
++            struct s_ftsata100_host *ft_host = &ftsata100_host[i];
++
++            memset(ft_host, 0, sizeof(*ft_host));
++
++            spin_lock_init(&ft_host->lock);
++            switch (i) {
++                case 0:
++                    mem = SATA_FTSATA100_0_PA_BASE;
++                    mem_size = SATA_FTSATA100_0_PA_SIZE;
++                    irq = SATA_FTSATA100_0_IRQ;
++                    break;
++                case 1:
++                    mem = SATA_FTSATA100_1_PA_BASE;
++                    mem_size = SATA_FTSATA100_1_PA_SIZE;
++                    irq = SATA_FTSATA100_1_IRQ;
++                    break;
++                case 2:
++                    mem = SATA_FTSATA100_2_PA_BASE;
++                    mem_size = SATA_FTSATA100_2_PA_SIZE;
++                    irq = SATA_FTSATA100_2_IRQ;
++                    break;
++                case 3:
++                    mem = SATA_FTSATA100_3_PA_BASE;
++                    mem_size = SATA_FTSATA100_3_PA_SIZE;
++                    irq = SATA_FTSATA100_3_IRQ;
++                    break;
++            }
++            ft_host->mmio = ioremap(mem, mem_size);
++            ft_host->id = i;
++
++            rc = request_irq(irq, ftsata100_interrupt_translate, IRQF_SHARED, "ftsata100", ft_host);
++            if (rc)
++                panic("%s : can't request irq %d\n", __func__, irq);
++        }
++
++        slave_8210_pmu_va_base = ioremap(0xE1000000, PMU_FTPMU010_VA_SIZE);
++
++        return 0;
++    }
++#else
++    if ((pci_id != FMEM_PCI_HOST) || (cpu_id != FMEM_CPU_FA726))
++        return 0;
++#endif //#ifdef CONFIG_EP_SATA_ENABLE
++
++    h2x_sata0_va_base = ioremap(H2X_FTH2X030_SATA_0_PA_BASE, H2X_FTH2X030_SATA_0_PA_SIZE);
++    h2x_sata1_va_base = ioremap(H2X_FTH2X030_SATA_1_PA_BASE, H2X_FTH2X030_SATA_1_PA_SIZE);
++    h2x_sata2_va_base = ioremap(H2X_FTH2X030_SATA_2_PA_BASE, H2X_FTH2X030_SATA_2_PA_SIZE);
++    h2x_sata3_va_base = ioremap(H2X_FTH2X030_SATA_3_PA_BASE, H2X_FTH2X030_SATA_3_PA_SIZE);
++
++    pcie_va_base = ioremap(PCIE_PLDA_0_PA_BASE, PCIE_PLDA_0_PA_SIZE);
++
++    i2c0_sataphy_va_base = ioremap(I2C_PCIE_FTI2C010_0_PA_BASE, I2C_PCIE_FTI2C010_0_PA_SIZE);
++    i2c1_sataphy_va_base = ioremap(I2C_PCIE_FTI2C010_1_PA_BASE, I2C_PCIE_FTI2C010_1_PA_SIZE);
++    i2c2_sataphy_va_base = ioremap(I2C_PCIE_FTI2C010_2_PA_BASE, I2C_PCIE_FTI2C010_2_PA_SIZE);
++    i2c3_sataphy_va_base = ioremap(I2C_PCIE_FTI2C010_3_PA_BASE, I2C_PCIE_FTI2C010_3_PA_SIZE);
++
++    plat_id = PLAT_8312_ID;
++#endif //#ifdef CONFIG_PLATFORM_GM8210
++
++#ifdef CONFIG_PLATFORM_GM8287
++    i2c3_sataphy_va_base = ioremap(I2C_FTI2C010_3_PA_BASE, I2C_FTI2C010_3_PA_SIZE);
++    i2c4_sataphy_va_base = ioremap(I2C_FTI2C010_4_PA_BASE, I2C_FTI2C010_4_PA_SIZE);
++
++    plat_id = PLAT_8287_ID;
++#endif
++
++	i2c_sladdr_w = 0x00;
++	i2c_sladdr_r = i2c_sladdr_w | 0x01;
++
++    ftsata100_clk_enable();
++    ftsata100_phy_config();
++
+ 	return platform_driver_probe(&ahci_driver, ahci_probe);
+ }
+ module_init(ahci_init);
+ 
+ static void __exit ahci_exit(void)
+ {
++#ifdef CONFIG_PLATFORM_GM8210
++#ifdef CONFIG_EP_SATA_ENABLE
++    if (cpu_id != FMEM_CPU_FA726)
++        return;
++
++    if (pci_id == FMEM_PCI_HOST) {
++        int i;
++
++        for (i = 0; i < 4; i++) {
++            struct s_ftsata100_host *ft_host = &ftsata100_host[i];
++            iounmap(ft_host->mmio);
++        }
++
++        iounmap(slave_8210_pmu_va_base);
++
++        return;
++    }
++#else
++    if ((pci_id != FMEM_PCI_HOST) || (cpu_id != FMEM_CPU_FA726))
++        return;
++#endif
++
++    iounmap(h2x_sata0_va_base);
++    iounmap(h2x_sata1_va_base);
++    iounmap(h2x_sata2_va_base);
++    iounmap(h2x_sata3_va_base);
++
++    iounmap(pcie_va_base);
++
++    iounmap(i2c0_sataphy_va_base);
++    iounmap(i2c1_sataphy_va_base);
++    iounmap(i2c2_sataphy_va_base);
++    iounmap(i2c3_sataphy_va_base);
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8287
++    iounmap(i2c3_sataphy_va_base);
++    iounmap(i2c4_sataphy_va_base);
++#endif
++
+ 	platform_driver_unregister(&ahci_driver);
+ }
+ module_exit(ahci_exit);
+@@ -302,3 +1189,4 @@ MODULE_DESCRIPTION("AHCI SATA platform driver");
+ MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+ MODULE_LICENSE("GPL");
+ MODULE_ALIAS("platform:ahci");
++
+diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
+index a72bfd0e..7661dc50 100644
+--- a/drivers/ata/libahci.c
++++ b/drivers/ata/libahci.c
+@@ -45,6 +45,14 @@
+ #include <scsi/scsi_cmnd.h>
+ #include <linux/libata.h>
+ #include "ahci.h"
++#ifdef CONFIG_SATA_AHCI_PLATFORM // chris add
++#ifdef CONFIG_PLATFORM_GM8210
++#include <mach/ftpmu010_pcie.h>
++#endif
++#ifdef CONFIG_PLATFORM_GM8287
++#include <mach/ftpmu010.h>
++#endif
++#endif
+ 
+ static int ahci_skip_host_reset;
+ int ahci_ignore_sss;
+@@ -802,6 +810,25 @@ int ahci_reset_controller(struct ata_host *host)
+ 	 */
+ 	ahci_enable_ahci(mmio);
+ 
++#ifdef CONFIG_SATA_AHCI_PLATFORM // chris add
++#ifdef CONFIG_PLATFORM_GM8287
++    {
++        /*
++         * An additional step for SATA PHY used by GM8287,
++         * it must de-assert phyn_reset_n first, before set HBA Reset on controller.
++         */
++        void __iomem *port_mmio = mmio + 0x100;
++
++        tmp = readl(port_mmio + PORT_CMD);
++        tmp |= PORT_CMD_SPIN_UP;
++        writel(tmp, port_mmio + PORT_CMD);
++        readl(port_mmio + PORT_CMD); /* flush */
++
++        mdelay(500);
++    }
++#endif
++#endif
++
+ 	/* global controller reset */
+ 	if (!ahci_skip_host_reset) {
+ 		tmp = readl(mmio + HOST_CTL);
+@@ -825,6 +852,23 @@ int ahci_reset_controller(struct ata_host *host)
+ 			return -EIO;
+ 		}
+ 
++#ifdef CONFIG_SATA_AHCI_PLATFORM // chris add
++#ifdef CONFIG_PLATFORM_GM8210
++        tmp = PCIE_AHB_CLK_IN / 1000;
++#endif
++#ifdef CONFIG_PLATFORM_GM8287
++        tmp = AHB_CLK_IN / 1000;
++#endif
++        if (tmp > 0x3FFFF) {
++            writel(tmp/2, mmio + 0xA0);
++            tmp = readl(mmio + 0x14);
++            tmp = (tmp & 0x0000FFFF) | (2 << 16);
++            writel(tmp, mmio + 0x14);
++        } else {
++            writel(tmp, mmio + 0xA0);
++        }
++#endif
++
+ 		/* turn on AHCI mode */
+ 		ahci_enable_ahci(mmio);
+ 
+@@ -1440,6 +1484,9 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
+ 		dma_addr_t addr = sg_dma_address(sg);
+ 		u32 sg_len = sg_dma_len(sg);
+ 
++#ifdef CONFIG_EP_SATA_ENABLE
++        addr += 0xF0000000;
++#endif
+ 		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
+ 		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ 		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
+@@ -1568,6 +1615,65 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
+ 	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
+ 		irq_stat &= ~PORT_IRQ_IF_ERR;
+ 
++#ifdef CONFIG_SATA_AHCI_PLATFORM // for ATAPI
++    if (link->device->class == ATA_DEV_ATAPI) {
++        static int quick_drain = 0;
++
++        if (quick_drain) {
++            /* If interrupt is triggered on Task File Error Status
++             * after Protocol Error happened, it must ignore the
++             * result of error to fake passed.
++             */
++            ahci_stop_engine(ap);
++            ahci_start_engine(ap);
++            quick_drain = 0;
++            ata_qc_complete(active_qc);
++            return;
++        }
++
++        if (host_ehi->serror & SERR_PROTOCOL) {
++            /* There is a very strange behavior on cdrom drive.
++             * While host issues a packet command READ DISC INFORMATION(51h),
++             * the data FIS received during a PIO command and the size
++             * in the transfer counter field of the preceding PIO Setup
++             * FIS are mismatched. That is violation of the Serial ATA
++             * protocol and always returns result of error back.
++             * In order to solve this issue, it must ignore result of
++             * Protocol Error on host and skip remaining handling.
++             */
++            host_ehi->serror &= ~SERR_PROTOCOL;
++            ahci_stop_engine(ap);
++            ahci_start_engine(ap);
++            quick_drain = 1;
++            return;
++        }
++
++        if (irq_stat & PORT_IRQ_TF_ERR) {
++            if (active_qc && active_qc->scsicmd) {
++                /* The CD recorder, model name LG GH24NSC0, is always returned error
++                 * status for these commands, it is different from other devices.
++                 * It is necessary to ignore these errors to return back successful result.
++                 */
++                switch (active_qc->scsicmd->cmnd[0]) {
++                    case 0x28: // READ (10)
++                        active_qc->flags |= ATA_QCFLAG_RETRY;
++                        active_ehi->flags |= (ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET);
++                        break;
++                    case 0x52: // READ TRACK/RZONE INFORMATION
++                        ahci_stop_engine(ap);
++                        ahci_start_engine(ap);
++                        ata_qc_complete(active_qc);
++                        return;
++                    default:
++                        break;
++                }
++            }
++        }
++
++        irq_stat &= ~PORT_IRQ_IF_ERR;
++    }
++#endif
++
+ 	if (irq_stat & PORT_IRQ_TF_ERR) {
+ 		/* If qc is active, charge it; otherwise, the active
+ 		 * link.  There's no active qc on NCQ errors.  It will
+@@ -1644,6 +1750,14 @@ static void ahci_port_intr(struct ata_port *ap)
+ 	int rc;
+ 
+ 	status = readl(port_mmio + PORT_IRQ_STAT);
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++    if (unlikely(status & PORT_IRQ_ERROR)) {
++        if (ap->link.device->class == ATA_DEV_ATA) {
++            extern void ftsata100_dump_reg(struct ata_port *ap);
++            ftsata100_dump_reg(ap);
++        }
++    }
++#endif
+ 	writel(status, port_mmio + PORT_IRQ_STAT);
+ 
+ 	/* ignore BAD_PMP while resetting */
+@@ -1734,12 +1848,17 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance)
+ 	hpriv = host->private_data;
+ 	mmio = hpriv->mmio;
+ 
++#ifdef CONFIG_EP_SATA_ENABLE
++    irq_stat = hpriv->port_map;
++    irq_masked = hpriv->port_map;
++#else
+ 	/* sigh.  0xffffffff is a valid return from h/w */
+ 	irq_stat = readl(mmio + HOST_IRQ_STAT);
+ 	if (!irq_stat)
+ 		return IRQ_NONE;
+ 
+ 	irq_masked = irq_stat & hpriv->port_map;
++#endif
+ 
+ 	spin_lock(&host->lock);
+ 
+@@ -1753,6 +1872,14 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance)
+ 		if (ap) {
+ 			ahci_port_intr(ap);
+ 			VPRINTK("port %u\n", i);
++#ifdef CONFIG_EP_SATA_ENABLE
++            {
++                void __iomem *port_mmio = ahci_port_base(ap);
++                struct ahci_port_priv *pp = ap->private_data;
++
++                writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
++            }
++#endif
+ 		} else {
+ 			VPRINTK("port %u (no irq)\n", i);
+ 			if (ata_ratelimit())
+@@ -1763,6 +1890,9 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance)
+ 		handled = 1;
+ 	}
+ 
++#ifdef CONFIG_EP_SATA_ENABLE
++    ftpmu010_clear_intr(irq);
++#else
+ 	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
+ 	 * it should be cleared after all the port events are cleared;
+ 	 * otherwise, it will raise a spurious interrupt after each
+@@ -1773,6 +1903,7 @@ irqreturn_t ahci_interrupt(int irq, void *dev_instance)
+ 	 * pending event on a dummy port might cause screaming IRQ.
+ 	 */
+ 	writel(irq_stat, mmio + HOST_IRQ_STAT);
++#endif
+ 
+ 	spin_unlock(&host->lock);
+ 
+@@ -2067,6 +2198,10 @@ static int ahci_port_start(struct ata_port *ap)
+ 		return -ENOMEM;
+ 	memset(mem, 0, dma_sz);
+ 
++#ifdef CONFIG_EP_SATA_ENABLE
++    mem_dma += 0xF0000000;
++#endif
++
+ 	/*
+ 	 * First item in chunk of DMA memory: 32-slot command table,
+ 	 * 32 bytes each in size
+diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
+index c06e0ec1..22360b70 100644
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -3707,6 +3707,9 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
+ 	if (online)
+ 		*online = false;
+ 
++#ifdef CONFIG_SATA_AHCI_PLATFORM // chris add
++redo:
++#endif
+ 	if (sata_set_spd_needed(link)) {
+ 		/* SATA spec says nothing about how to reconfigure
+ 		 * spd.  To be on the safe side, turn off phy during
+@@ -3742,9 +3745,22 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
+ 	rc = sata_link_resume(link, timing, deadline);
+ 	if (rc)
+ 		goto out;
++
++#ifdef CONFIG_SATA_AHCI_PLATFORM // chris add
++    if (ata_phys_link_offline(link)) {
++        // double confirm link status
++        extern int ftsata100_phy_reset(struct ata_link *link);
++
++        if (ftsata100_phy_reset(link))
++            goto out;
++        else
++            goto redo;
++    }
++#else
+ 	/* if link is offline nothing more to do */
+ 	if (ata_phys_link_offline(link))
+ 		goto out;
++#endif
+ 
+ 	/* Link is online.  From this point, -ENODEV too is an error. */
+ 	if (online)
+@@ -5492,6 +5508,25 @@ int sata_link_init_spd(struct ata_link *link)
+ 	u8 spd;
+ 	int rc;
+ 
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++#ifndef CONFIG_EXTERNAL_CRYSTAL_CLOCK
++    {
++        u32 scontrol;
++
++        //printk("GM SATA%u limit highest allowable speed to 1.5 Gbps\n", link->ap->print_id - 1);
++        rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
++        if (rc)
++            return rc;
++
++		scontrol |= 0x10;
++
++        rc = sata_scr_write(link, SCR_CONTROL, scontrol);
++        if (rc)
++            return rc;
++    }
++#endif
++#endif
++
+ 	rc = sata_scr_read(link, SCR_CONTROL, &link->saved_scontrol);
+ 	if (rc)
+ 		return rc;
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index d0c41188..fc517286 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -85,6 +85,12 @@ config GPIO_GENERIC_PLATFORM
+ 	help
+ 	  Say yes here to support basic platform_device memory-mapped GPIO controllers.
+ 
++config GPIO_FTGPIO010
++	tristate "FTGPIO010 GPIO support"
++	depends on ARCH_GM || ARCH_GM_DUO || ARCH_GM_SMP # unconditional access to IO space.
++	help
++	  Say yes here to support GPIO functionality of GM Soc
++
+ config GPIO_IT8761E
+ 	tristate "IT8761E GPIO support"
+ 	depends on X86  # unconditional access to IO space.
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index fa10df60..74e52941 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -7,6 +7,7 @@ obj-$(CONFIG_GPIOLIB)		+= gpiolib.o devres.o
+ # Device drivers. Generally keep list sorted alphabetically
+ obj-$(CONFIG_GPIO_GENERIC)	+= gpio-generic.o
+ 
++obj-$(CONFIG_GPIO_FTGPIO010)	+= gpio-ftgpio010.o
+ obj-$(CONFIG_GPIO_74X164)	+= gpio-74x164.o
+ obj-$(CONFIG_GPIO_AB8500)	+= gpio-ab8500.o
+ obj-$(CONFIG_GPIO_ADP5520)	+= gpio-adp5520.o
+diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
+new file mode 100644
+index 00000000..815dcf81
+--- /dev/null
++++ b/drivers/gpio/gpio-ftgpio010.c
+@@ -0,0 +1,601 @@
++/*
++ * Copyright (C) 2010 GM Corp. (http://www.grain-media.com)
++ *
++ * Grain Media - GPIOlib support
++ *
++ * 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 <linux/string.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++
++#include <mach/platform/gpio.h>
++#include <mach/ftpmu010.h>
++
++#define GM_GPIO010_DEBUG	0
++#define GM_GPIO010_TEST		0
++
++#define GM_GPIO010_GPIODATAOUT		0x00
++#define GM_GPIO010_GPIODATAIN		0x04
++#define GM_GPIO010_PINDIR		0x08
++#define GM_GPIO010_PINBYPASS		0x0C
++#define GM_GPIO010_GPIODATASET		0x10
++#define GM_GPIO010_GPIODATACLEAR	0x14
++#define GM_GPIO010_PINPULLENABLE	0x18
++#define GM_GPIO010_PINPULLTYPE		0x1C
++#define GM_GPIO010_INTRENABLE		0x20
++#define GM_GPIO010_INTRRAWSTATE		0x24
++#define GM_GPIO010_INTRMASKEDSTATE	0x28
++#define GM_GPIO010_INTRMASK		0x2C
++#define GM_GPIO010_INTRCLEAR		0x30
++#define GM_GPIO010_INTRTRIGGER		0x34
++#define GM_GPIO010_INTRBOTH		0x38
++#define GM_GPIO010_INTRRISENEG		0x3C
++#define GM_GPIO010_BOUNCEENABLE		0x40
++#define GM_GPIO010_BOUNCEPERSCALE	0x44
++#define GM_GPIO010_REVISIONNUM		0x48
++
++struct gm_gpio_chip {
++	const char *name;
++	void __iomem *start_vaddr;
++	struct resource *res;
++	int irq;
++	struct gpio_chip gc;
++	struct platform_device *platform_dev;
++	int id;
++};
++
++/*
++ *  set pin as input
++ */
++static int gm_gpio_direction_input(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 pin_dir = 0;
++
++	if (unlikely(gc == NULL)) {
++		printk("%s fails: gc is NULL\n", __FUNCTION__);
++		return -1;
++	}
++	//set input
++	pin_dir =
++	    (ioread32(chip->start_vaddr + GM_GPIO010_PINDIR) & (~(1 << pin)));
++	iowrite32(pin_dir, chip->start_vaddr + GM_GPIO010_PINDIR);
++
++	return 0;
++}
++
++/*
++ *  set pin as output
++ */
++static int gm_gpio_direction_output(struct gpio_chip *gc, unsigned pin, int val)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 pin_dir = 0;
++	u32 pin_level = 0;
++
++	if (unlikely(gc == NULL)) {
++		printk("%s fails: gc is NULL\n", __FUNCTION__);
++		return -1;
++	}
++	//set output
++	pin_dir =
++	    (ioread32(chip->start_vaddr + GM_GPIO010_PINDIR) | (1 << pin));
++	iowrite32(pin_dir, chip->start_vaddr + GM_GPIO010_PINDIR);
++
++	//set pin level
++	pin_level = ioread32(chip->start_vaddr + GM_GPIO010_GPIODATAOUT);
++
++	if (val != 0) {
++		pin_level |= (1 << pin);
++	} else {
++		pin_level &= (~(1 << pin));
++	}
++
++	iowrite32(pin_level, chip->start_vaddr + GM_GPIO010_GPIODATAOUT);
++
++	return 0;
++}
++
++/*
++ *  return the level of pin
++ */
++static int gm_gpio_get_value(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 pin_dir = 0;
++	u32 pin_level = 0;
++
++	if (unlikely(gc == NULL)) {
++		printk("%s fails: gc is NULL\n", __FUNCTION__);
++		return -1;
++	}
++
++	pin_dir = ioread32(chip->start_vaddr + GM_GPIO010_PINDIR) & (1 << pin);
++
++	if (pin_dir != 0) {	//output
++		pin_level =
++		    ioread32(chip->start_vaddr +
++			     GM_GPIO010_GPIODATAOUT) & (1 << pin);
++	} else {		//input
++		pin_level =
++		    ioread32(chip->start_vaddr +
++			     GM_GPIO010_GPIODATAIN) & (1 << pin);
++
++	}
++
++	return pin_level;
++}
++
++/*
++ *  set output pin level
++ */
++static void gm_gpio_set_value(struct gpio_chip *gc, unsigned pin, int val)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 pin_dir = 0;
++	u32 pin_level = 0;
++
++	if (unlikely(gc == NULL)) {
++		printk("%s fails: gc is NULL\n", __FUNCTION__);
++		return;
++	}
++
++	pin_dir = ioread32(chip->start_vaddr + GM_GPIO010_PINDIR) & (1 << pin);
++
++	if (likely(pin_dir != 0)) {	//only set level when output
++		pin_level =
++		    ioread32(chip->start_vaddr + GM_GPIO010_GPIODATAOUT);
++		if (val != 0) {
++			pin_level |= (1 << pin);
++		} else {
++			pin_level &= (~(1 << pin));
++		}
++		iowrite32(pin_level,
++			  chip->start_vaddr + GM_GPIO010_GPIODATAOUT);
++	} else {
++		printk("%s fail: you should only set output pin.\n",
++		       __FUNCTION__);
++		return;
++	}
++}
++
++/*
++ *  return GPIO irq, in our platform, all gpio share the same irq number
++ */
++static int gm_gpio_to_irq(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++
++	if (unlikely(gc == NULL)) {
++		printk("%s fails: gc is NULL\n", __FUNCTION__);
++		return -1;
++	}
++
++	return chip->irq;
++}
++
++static int gm_int_clr(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 int_st = ioread32(chip->start_vaddr + GM_GPIO010_INTRCLEAR);
++
++	if (unlikely(gc == NULL)) {
++		printk("%s fails: gc is NULL\n", __FUNCTION__);
++		return -1;
++	}
++
++	int_st |= (1 << pin);
++	iowrite32(int_st, chip->start_vaddr + GM_GPIO010_INTRCLEAR);
++
++	return 0;
++}
++
++static int xgm_set_or_clr(void __iomem * address, const int pin,
++			  const u32 condition, const u32 compare)
++{
++	u32 tmp = ioread32(address);
++	u32 pin_offset = (1 << pin);
++
++	if (condition == compare) {
++		tmp |= pin_offset;
++	} else {
++		tmp &= ~pin_offset;
++	}
++
++	iowrite32(tmp, address);
++
++	return 0;
++}
++
++static int gm_int_setup(struct gpio_chip *gc, unsigned pin,
++			const struct gpio_interrupt_mode *mode)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++
++	xgm_set_or_clr(chip->start_vaddr + GM_GPIO010_INTRTRIGGER,
++		       pin, mode->trigger_method, GPIO_INT_TRIGGER_LEVEL);
++
++	xgm_set_or_clr(chip->start_vaddr + GM_GPIO010_INTRBOTH,
++		       pin, mode->trigger_edge_nr, GPIO_INT_BOTH_EDGE);
++
++	xgm_set_or_clr(chip->start_vaddr + GM_GPIO010_INTRRISENEG,
++		       pin, mode->trigger_rise_neg, GPIO_INT_FALLING);
++	return 0;
++}
++
++static int gm_int_enable(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 int_enable = ioread32(chip->start_vaddr + GM_GPIO010_INTRENABLE);
++
++	int_enable |= (1 << pin);
++	iowrite32(int_enable, chip->start_vaddr + GM_GPIO010_INTRENABLE);
++
++	return 0;
++}
++
++static int gm_int_disable(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 int_enable = ioread32(chip->start_vaddr + GM_GPIO010_INTRENABLE);
++
++	int_enable &= (~(1 << pin));
++	iowrite32(int_enable, chip->start_vaddr + GM_GPIO010_INTRENABLE);
++
++	return 0;
++}
++
++static int gm_int_check(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 int_status = ioread32(chip->start_vaddr + GM_GPIO010_INTRRAWSTATE);
++	int ret = 0;
++
++	if (int_status & (1 << pin))
++		ret = 1;
++	return ret;
++}
++
++static int gm_int_mask(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 int_enable = ioread32(chip->start_vaddr + GM_GPIO010_INTRMASK);
++
++	int_enable |= (1 << pin);
++	iowrite32(int_enable, chip->start_vaddr + GM_GPIO010_INTRMASK);
++
++	return 0;
++}
++
++static int gm_int_unmask(struct gpio_chip *gc, unsigned pin)
++{
++	struct gm_gpio_chip *chip = container_of(gc, struct gm_gpio_chip, gc);
++	u32 int_enable = ioread32(chip->start_vaddr + GM_GPIO010_INTRMASK);
++
++	int_enable &= (~(1 << pin));
++	iowrite32(int_enable, chip->start_vaddr + GM_GPIO010_INTRMASK);
++
++	return 0;
++}
++
++/*
++ *  init chip->gc
++ */
++static void gm_gpio_setup(struct gm_gpio_chip *chip)
++{
++	struct gpio_chip *gc = NULL;
++
++	gc = &chip->gc;
++
++	gc->direction_input = gm_gpio_direction_input;
++	gc->direction_output = gm_gpio_direction_output;
++	gc->get = gm_gpio_get_value;
++	gc->set = gm_gpio_set_value;
++	gc->to_irq = gm_gpio_to_irq;
++	gc->int_clr = gm_int_clr;
++	gc->int_setup = gm_int_setup;
++	gc->int_enable = gm_int_enable;
++	gc->int_disable = gm_int_disable;
++	gc->int_mask = gm_int_mask;
++	gc->int_unmask = gm_int_unmask;
++	gc->int_check = gm_int_check;
++	gc->can_sleep = 0;
++	gc->base = chip->id * GM_GPIO_NR_PIN_PER_PORT;
++	gc->ngpio = GM_GPIO_NR_PIN_PER_PORT;
++	gc->label = chip->name;
++	gc->dev = &chip->platform_dev->dev;
++	gc->owner = THIS_MODULE;
++}
++
++#if GM_GPIO010_DEBUG
++static void dump_info(const struct gm_gpio_chip *chip)
++{
++	printk("\n************************************************\n");
++	printk("Dump GM GPIO related info\n");
++	printk("resource->start = %x\n", chip->res->start);
++	printk("resource->end = %x\n", chip->res->end);
++	printk("resource->name = %s\n", chip->res->name);
++	printk("chip->name = %s\n", chip->name);
++	printk("chip->start_vaddr = %x\n", (unsigned)chip->start_vaddr);
++	printk("chip->irq = %d\n", chip->irq);
++	printk("gc->can_sleep = %d\n", chip->gc.can_sleep);
++	printk("gc->base = %d\n", chip->gc.base);
++	printk("gc->ngpio = %d\n", chip->gc.ngpio);
++	printk("gc->label = %s\n", chip->gc.label);
++	printk("************************************************\n");
++}
++
++static void dump_GPIO010_reg(const struct gm_gpio_chip *chip)
++{
++	printk("GM_GPIO010_PINDIR 	== %x\n",
++	       ioread32(chip->start_vaddr + GM_GPIO010_PINDIR));
++	printk("GM_GPIO010_GPIODATAOUT == %x\n",
++	       ioread32(chip->start_vaddr + GM_GPIO010_GPIODATAOUT));
++	printk("GM_GPIO010_GPIODATAIN  == %x\n",
++	       ioread32(chip->start_vaddr + GM_GPIO010_GPIODATAIN));
++}
++#endif //end of GM_GPIO010_DEBUG
++
++#if GM_GPIO010_TEST
++static void test_dedicate_gpio_request(struct gpio_chip *gc)
++{
++	gpio_request(0, "gpio0");
++	gpio_request(1, "gpio1");
++	gpio_request(2, "gpio2");
++	gpio_request(3, "gpio3");
++}
++
++static void test_set_dedicate_gpio_high(void)
++{
++	gpio_direction_output(0, 1);
++	gpio_direction_output(1, 1);
++	gpio_direction_output(2, 1);
++	gpio_direction_output(3, 1);
++
++	if (gpio_get_value(0) == 0) {
++		printk("%s fail: gpio 0 fail\n", __FUNCTION__);
++	}
++
++	if (gpio_get_value(1) == 0) {
++		printk("%s fail: gpio 1 fail\n", __FUNCTION__);
++	}
++
++	if (gpio_get_value(2) == 0) {
++		printk("%s fail: gpio 2 fail\n", __FUNCTION__);
++	}
++
++	if (gpio_get_value(3) == 0) {
++		printk("%s fail: gpio 3 fail\n", __FUNCTION__);
++	}
++
++	printk("GPIO test output HIGH OK\n");
++}
++
++static void test_set_dedicate_gpio_low(void)
++{
++	gpio_direction_output(0, 0);
++	gpio_direction_output(1, 0);
++	gpio_direction_output(2, 0);
++	gpio_direction_output(3, 0);
++
++	if (gpio_get_value(0) == 1) {
++		printk("%s fail: gpio 0 fail\n", __FUNCTION__);
++	}
++
++	if (gpio_get_value(1) == 1) {
++		printk("%s fail: gpio 1 fail\n", __FUNCTION__);
++	}
++
++	if (gpio_get_value(2) == 1) {
++		printk("%s fail: gpio 2 fail\n", __FUNCTION__);
++	}
++
++	if (gpio_get_value(3) == 1) {
++		printk("%s fail: gpio 3 fail\n", __FUNCTION__);
++	}
++
++	printk("GPIO test output LOW OK\n");
++}
++
++static void test_set_dedicate_gpio_input(void)
++{
++	gpio_direction_input(0);
++	gpio_direction_input(1);
++	gpio_direction_input(2);
++	gpio_direction_input(3);
++
++	//test input setting should investigate the CKT
++}
++
++static irqreturn_t gm_test_gpio_isr(int irq, void *dev_id)
++{
++	if (gpio_interrupt_check(0))
++		printk("gpio isr\n");
++	gpio_interrupt_clear(0);
++
++	return IRQ_HANDLED;
++}
++
++struct fake_dev {
++	int foo;
++};
++
++static void test_gpio_interrupt(struct fake_dev *dev)
++{
++	struct gpio_interrupt_mode mode = {
++		.trigger_method = GPIO_INT_TRIGGER_EDGE,
++		.trigger_edge_nr = GPIO_INT_SINGLE_EDGE,
++		.trigger_rise_neg = GPIO_INT_FALLING
++	};
++
++	gpio_direction_input(0);
++	gpio_interrupt_enable(0);
++	gpio_interrupt_setup(0, &mode);
++
++	if (request_irq
++	    (gpio_to_irq(0), gm_test_gpio_isr, IRQF_SHARED, "gpio-0",
++	     dev) < 0) {
++		printk("%s fail: request_irq not OK!!\n", __FUNCTION__);
++	}
++}
++#endif //end of GM_GPIO010_TEST
++
++static int ftgpio010_probe(struct platform_device *pdev)
++{
++	struct gm_gpio_chip *chip = NULL;
++	struct resource *res = NULL;
++	int ret = -1;
++	int irq = -1;
++
++	chip = kzalloc(sizeof(struct gm_gpio_chip), GFP_KERNEL);
++	if (unlikely(chip == NULL)) {
++		printk("%s fail: could not allocate memory\n", __FUNCTION__);
++		ret = -ENOMEM;
++		goto err_alloc;
++	}
++	//get the gpio controller's memory I/O, this will be pyhsical address
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (unlikely(res == NULL)) {
++		printk("%s fail: can't get resource\n", __FUNCTION__);
++		return -ENXIO;
++	}
++
++	if (unlikely((irq = platform_get_irq(pdev, 0)) < 0)) {
++		printk("%s fail: can't get irq\n", __FUNCTION__);
++		return irq;
++	}
++
++	chip->irq = irq;
++
++	//optional, but this is better for future debug
++	chip->res =
++	    request_mem_region(res->start, (res->end - res->start + 1),
++			       dev_name(&pdev->dev));
++	if (unlikely(chip->res == NULL)) {
++		printk("%s fail: could not reserve memory region\n",
++		       __FUNCTION__);
++		ret = -ENOMEM;
++		goto err_req_mem;
++	}
++	//map pyhsical address to virtual address for program use easier
++	chip->start_vaddr =
++	    ioremap_nocache(res->start, (res->end - res->start + 1));
++	if (unlikely(chip->start_vaddr == NULL)) {
++		printk("%s fail: counld not do ioremap\n", __FUNCTION__);
++		ret = -ENOMEM;
++		goto err_ioremap;
++	}
++
++	chip->name = kstrdup(dev_name(&pdev->dev), GFP_KERNEL);
++	if (unlikely(chip->name == NULL)) {
++		printk("%s fail: kstrdup not work\n", __FUNCTION__);
++		ret = -ENOMEM;
++		goto err_kstrdup;
++	}
++
++	chip->platform_dev = pdev;
++	chip->id = pdev->id;
++
++	//bind related fields to gpio_chip
++	gm_gpio_setup(chip);
++
++	//bind to platform, for future remove easier
++	platform_set_drvdata(pdev, chip);
++
++	ret = gpiochip_add(&chip->gc);
++	if (ret) {
++		printk("%s fail: gpiochip_add not OK\n", __FUNCTION__);
++		goto err_gpioadd;
++	}
++
++	printk(KERN_INFO "probe %s OK, at 0x%p\n", chip->name, chip->start_vaddr);
++
++#if GM_GPIO010_DEBUG
++	dump_info(chip);
++#endif
++#if GM_GPIO010_TEST
++	test_dedicate_gpio_request(&chip->gc);
++	test_set_dedicate_gpio_high();
++#if GM_GPIO010_DEBUG
++	dump_GPIO010_reg(chip);
++#endif
++	test_set_dedicate_gpio_low();
++#if GM_GPIO010_DEBUG
++	dump_GPIO010_reg(chip);
++#endif
++	test_set_dedicate_gpio_input();
++#if GM_GPIO010_DEBUG
++	dump_GPIO010_reg(chip);
++#endif
++	{
++		struct fake_dev dev;
++		test_gpio_interrupt(&dev);
++	}
++#if GM_GPIO010_DEBUG
++	dump_GPIO010_reg(chip);
++#endif
++#endif //end of GM_GPIO010_TEST
++	return ret;
++
++//god... don't be here... @_@
++err_gpioadd:
++	kfree(chip->name);
++err_kstrdup:
++	iounmap(chip->start_vaddr);
++err_ioremap:
++	release_resource(res);
++err_req_mem:
++	kfree(chip);
++err_alloc:
++	return ret;
++}
++
++static int __devexit ftgpio010_remove(struct platform_device *pdev)
++{
++	struct gm_gpio_chip *chip = platform_get_drvdata(pdev);
++
++	platform_set_drvdata(pdev, NULL);
++	iounmap(chip->start_vaddr);
++	release_resource(chip->res);
++	kfree(chip->name);
++	kfree(chip);
++
++	return 0;
++}
++
++static struct platform_driver ftgpio010_driver = {
++	.probe = ftgpio010_probe,
++	.remove = __devexit_p(ftgpio010_remove),
++	.driver = {
++		   .name = "ftgpio010",
++		   .owner = THIS_MODULE,
++		   },
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftgpio010_init(void)
++{
++	return platform_driver_register(&ftgpio010_driver);
++}
++
++static void __exit ftgpio010_exit(void)
++{
++	platform_driver_unregister(&ftgpio010_driver);
++}
++
++module_init(ftgpio010_init);
++module_exit(ftgpio010_exit);
++
++MODULE_AUTHOR("Mars Cheng <mars_ch@faraday-tech.com>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index 17fdf4b6..1ddcfb81 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -1654,6 +1654,132 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
+ }
+ EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+ 
++/**
++* @brief clear the specific gpio interrupt, you should call this after handling every ISR triggered by the gpio
++*
++* @param gpio the gpio pin you want to clear
++*
++* @return 0 when OK, or non-zero value
++*/
++int gpio_interrupt_clear(unsigned gpio)
++{
++	struct gpio_chip	*chip;
++
++	might_sleep_if(extra_checks);
++	chip = gpio_to_chip(gpio);
++
++    return chip->int_clr ? chip->int_clr(chip, gpio - chip->base) : -1;
++}
++EXPORT_SYMBOL_GPL(gpio_interrupt_clear);
++
++/**
++* @brief setup interrupt mode to trigger
++*
++* @param gpio the gpio interrupt pin
++* @param mode describe the trigger condition
++*
++* @return 0 when OK, or non-zero value
++*/
++int gpio_interrupt_setup(unsigned gpio, struct gpio_interrupt_mode *mode)
++{
++	struct gpio_chip	*chip;
++
++	might_sleep_if(extra_checks);
++	chip = gpio_to_chip(gpio);
++
++    return chip->int_setup ? chip->int_setup(chip, gpio - chip->base, mode) : -1;
++}
++EXPORT_SYMBOL_GPL(gpio_interrupt_setup);
++
++/**
++* @brief enable gpio interrupt
++*
++* @param gpio the gpio pin to be enable
++*
++* @return 0 when OK, or non-zero value
++*/
++int gpio_interrupt_enable(unsigned gpio)
++{
++	struct gpio_chip	*chip;
++
++	might_sleep_if(extra_checks);
++	chip = gpio_to_chip(gpio);
++
++    return chip->int_enable ? chip->int_enable(chip, gpio - chip->base) : -1;
++}
++EXPORT_SYMBOL_GPL(gpio_interrupt_enable);
++
++/**
++* @brief disable gpio interrupt
++*
++* @param gpio the gpio pin to be disable
++*
++* @return 0 when OK, or non-zero value
++*/
++int gpio_interrupt_disable(unsigned gpio)
++{
++	struct gpio_chip	*chip;
++
++	might_sleep_if(extra_checks);
++	chip = gpio_to_chip(gpio);
++
++    return chip->int_disable ? chip->int_disable(chip, gpio - chip->base) : -1;
++}
++EXPORT_SYMBOL_GPL(gpio_interrupt_disable);
++
++/**
++* @brief mask gpio interrupt
++*
++* @param gpio the gpio pin to be masked
++*
++* @return 0 when OK, or non-zero value
++*/
++int gpio_interrupt_mask(unsigned gpio)
++{
++	struct gpio_chip	*chip;
++
++	might_sleep_if(extra_checks);
++	chip = gpio_to_chip(gpio);
++
++    return chip->int_mask ? chip->int_mask(chip, gpio - chip->base) : -1;
++}
++EXPORT_SYMBOL_GPL(gpio_interrupt_mask);
++
++/**
++* @brief unmask gpio interrupt
++*
++* @param gpio the gpio pin to be unmask
++*
++* @return 0 when OK, or non-zero value
++*/
++int gpio_interrupt_unmask(unsigned gpio)
++{
++	struct gpio_chip	*chip;
++
++	might_sleep_if(extra_checks);
++	chip = gpio_to_chip(gpio);
++
++    return chip->int_unmask ? chip->int_unmask(chip, gpio - chip->base) : -1;
++}
++EXPORT_SYMBOL_GPL(gpio_interrupt_unmask);
++
++/**
++* @brief check gpio interrupt
++*
++* @param gpio the gpio pin to be disable
++*
++* @return 1 when detecting intr., 0 when no intr., -1 means no callback function
++*/
++int gpio_interrupt_check(unsigned gpio)
++{
++	struct gpio_chip	*chip;
++
++	might_sleep_if(extra_checks);
++	chip = gpio_to_chip(gpio);
++
++    return chip->int_check ? chip->int_check(chip, gpio - chip->base) : -1;
++}
++EXPORT_SYMBOL_GPL(gpio_interrupt_check);
+ 
+ #ifdef CONFIG_DEBUG_FS
+ 
+diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
+index 5bf91dba..bb30e552 100644
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -73,6 +73,97 @@ static int hid_submit_out(struct hid_device *hid);
+ static int hid_submit_ctrl(struct hid_device *hid);
+ static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid);
+ 
++#ifdef CONFIG_GM_FOTG2XX
++#undef CONFIG_GM_FOTG2XX
++#endif
++
++#if defined(CONFIG_GM_FOTG2XX)
++/*
++ * Some kind of usb mouse low-speed devices are not designed under spec.
++ * In special condition, these devices will create SE1 packet and cause
++ * host controller stopping usb traffic transmition.
++ * This workaround solution is using the bus reset to reset device in period.
++ */
++#include <linux/usb/hcd.h>
++#include <linux/kthread.h>
++#define POLL_RESET_TIME (5 * HZ)
++#define STATE_STOP  0
++#define STATE_RUN   1
++
++static wait_queue_head_t hid_wdt_wqh;
++static int state = STATE_STOP;
++static struct task_struct *hid_wdt_task = NULL;
++static char hid_wdt_reset, hid_wdt_quit;
++static struct hid_device *hid_wdt_hdev = NULL;
++
++static int hid_wdt_thread(void *_data)
++{
++    struct hid_device *hid = (struct hid_device *) _data;
++	struct usbhid_device *usbhid = hid->driver_data;
++
++    if (state == STATE_STOP)
++        state = STATE_RUN;
++
++    wake_up(&hid_wdt_wqh); // to notify thread is running
++
++    while (state == STATE_RUN) {
++        struct usb_hcd *hcd = bus_to_hcd(hid_to_usb_dev(hid)->bus);
++
++        wait_event_timeout(hid_wdt_wqh, state == STATE_STOP, POLL_RESET_TIME);
++        if (state == STATE_STOP)
++            break;
++        if (!(*((volatile u32 *)((u32)hcd->regs | 0x30)) & (1 << 0))) {
++            printk("%s: device disconnect.\n", __func__);
++            break;
++        }
++        if (!hid_wdt_reset) {
++            hid_wdt_reset = 1;
++            continue;
++        }
++
++        /* reset device */
++		if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl))
++			schedule_work(&usbhid->reset_work);
++    }
++    hid_wdt_quit = 1;
++    wake_up(&hid_wdt_wqh); // to notify thread is quit
++    return 0;
++}
++
++static void hid_wdt_init(struct hid_device *hid)
++{
++    if (hid_wdt_task != NULL) // check if thread is already created
++        return;
++
++    init_waitqueue_head(&hid_wdt_wqh);
++    hid_wdt_reset = 1;
++    hid_wdt_quit = 0;
++
++    hid_wdt_task = kthread_run(hid_wdt_thread, hid, "hid_wdtd");
++    if (IS_ERR(hid_wdt_task)) {
++        printk("%s: create kthread failed\n", __func__);
++        hid_wdt_task = NULL;
++        return;
++    }
++    hid_wdt_hdev = hid;
++    wait_event(hid_wdt_wqh, state == STATE_RUN); // wait for thread is real running
++}
++
++static void hid_wdt_exit(struct hid_device *hid)
++{
++    if (hid_wdt_hdev != hid) // identify which hid device that thread hooked onto
++        return;
++
++    if (hid_wdt_task != NULL) {
++        state = STATE_STOP;
++        wake_up(&hid_wdt_wqh); // wake up thread to enter stop state
++        wait_event(hid_wdt_wqh, hid_wdt_quit); // wait for thread is real quit
++        hid_wdt_task = NULL;
++        hid_wdt_hdev = NULL;
++    }
++}
++#endif
++
+ /* Start up the input URB */
+ static int hid_start_in(struct hid_device *hid)
+ {
+@@ -258,6 +349,9 @@ static void hid_irq_in(struct urb *urb)
+ 
+ 	switch (urb->status) {
+ 	case 0:			/* success */
++#if defined(CONFIG_GM_FOTG2XX)
++        hid_wdt_reset = 0;
++#endif
+ 		usbhid_mark_busy(usbhid);
+ 		usbhid->retry_delay = 0;
+ 		hid_input_report(urb->context, HID_INPUT_REPORT,
+@@ -714,8 +808,16 @@ int usbhid_open(struct hid_device *hid)
+ 		usbhid->intf->needs_remote_wakeup = 1;
+ 		if (hid_start_in(hid))
+ 			hid_io_error(hid);
+- 
++
+ 		usb_autopm_put_interface(usbhid->intf);
++#if defined(CONFIG_GM_FOTG2XX)
++        {
++            struct usb_device *udev = hid_to_usb_dev(hid);
++
++            if ((udev->parent == udev->bus->root_hub) && (udev->speed == USB_SPEED_LOW))
++                hid_wdt_init(hid);
++        }
++#endif
+ 	}
+ 	mutex_unlock(&hid_open_mut);
+ 	return 0;
+@@ -734,6 +836,9 @@ void usbhid_close(struct hid_device *hid)
+ 	spin_lock_irq(&usbhid->lock);
+ 	if (!--hid->open) {
+ 		spin_unlock_irq(&usbhid->lock);
++#if defined(CONFIG_GM_FOTG2XX)
++        hid_wdt_exit(hid);
++#endif
+ 		hid_cancel_delayed_stuff(usbhid);
+ 		usb_kill_urb(usbhid->urbin);
+ 		usbhid->intf->needs_remote_wakeup = 0;
+diff --git a/drivers/i2c/busses/8210_uboot_nvp1918_clk_up.txt b/drivers/i2c/busses/8210_uboot_nvp1918_clk_up.txt
+new file mode 100644
+index 00000000..adfb6e9a
+--- /dev/null
++++ b/drivers/i2c/busses/8210_uboot_nvp1918_clk_up.txt
+@@ -0,0 +1,21 @@
++mm 99000028
++08007400
++.
++mm 9900005c
++7f000000
++.
++mm 99000078
++000c3549
++.
++mm 99000084
++00150000
++.
++mm 990000b0
++0fc3803c
++.
++mm 98e00000
++00000003
++00000003
++00000003
++.
++ 
+\ No newline at end of file
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index 3101dd59..73dc2460 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -464,6 +464,62 @@ config I2C_MV64XXX
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called i2c-mv64xxx.
+ 
++config I2C_GM_FTI2C010
++    bool "GM FTIIC010 I2C Controller"
++    default y
++    depends on ARCH_GM || ARCH_GM_DUO || ARCH_GM_SMP
++    help
++      If you say yes to this open, GM FTIIC010 contoller will be included.
++
++config I2C_INTERRUPT_MODE
++    bool "GM I2C uses interrupt mode"
++    default n
++    depends on I2C_GM_FTI2C010
++    help
++      If you say yes to this open, it will save CPU power but the I2C transaction latency will be longer.    
++
++config I2C0_IP
++    bool "GM I2C i2c0 enable"
++    default n
++    depends on I2C_GM_FTI2C010
++    help
++      If you say yes to this open, it will create the i2c0 i2c host.    
++
++config I2C1_IP
++    bool "GM I2C i2c1 enable"
++    default n
++    depends on I2C_GM_FTI2C010
++    help
++      If you say yes to this open, it will create the i2c1 i2c host.    
++
++config I2C2_IP
++    bool "GM I2C i2c2 enable"
++    default n
++    depends on I2C_GM_FTI2C010
++    help
++      If you say yes to this open, it will create the i2c2 i2c host.    
++
++config I2C3_IP
++    bool "GM I2C i2c3 enable"
++    default n
++    depends on I2C_GM_FTI2C010
++    help
++      If you say yes to this open, it will create the i2c3 i2c host.    
++
++config I2C4_IP
++    bool "GM I2C i2c4 enable"
++    default n
++    depends on I2C_GM_FTI2C010
++    help
++      If you say yes to this open, it will create the i2c4 i2c host.    
++
++config I2C5_IP
++    bool "GM I2C i2c5 enable"
++    default n
++    depends on I2C_GM_FTI2C010
++    help
++      If you say yes to this open, it will create the i2c5 i2c host. 
++
+ config I2C_MXS
+ 	tristate "Freescale i.MX28 I2C interface"
+ 	depends on SOC_IMX28
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index fba6da60..a4a01ec6 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -69,7 +69,11 @@ obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+ obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
+ obj-$(CONFIG_I2C_XILINX)	+= i2c-xiic.o
+ obj-$(CONFIG_I2C_EG20T)         += i2c-eg20t.o
+-
++ifeq ("y", $(filter "y", "$(CONFIG_PLATFORM_GM8139)" "$(CONFIG_PLATFORM_GM8136)"))
++obj-$(CONFIG_I2C_GM_FTI2C010)   += i2c-ftiic010-new-intr-mode.o
++else
++obj-$(CONFIG_I2C_GM_FTI2C010)   += i2c-ftiic010.o
++endif
+ # External I2C/SMBus adapter drivers
+ obj-$(CONFIG_I2C_DIOLAN_U2C)	+= i2c-diolan-u2c.o
+ obj-$(CONFIG_I2C_PARPORT)	+= i2c-parport.o
+diff --git a/drivers/i2c/busses/ftiic010.h b/drivers/i2c/busses/ftiic010.h
+new file mode 100644
+index 00000000..a583714f
+--- /dev/null
++++ b/drivers/i2c/busses/ftiic010.h
+@@ -0,0 +1,155 @@
++/*
++ * Faraday FTIIC010 I2C Controller
++ *
++ * (C) Copyright 2010 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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.
++ */
++
++#ifndef __FTIIC010_H
++#define __FTIIC010_H
++
++#define FTIIC010_OFFSET_CR	0x00
++#define FTIIC010_OFFSET_SR	0x04
++#define FTIIC010_OFFSET_CDR	0x08
++#define FTIIC010_OFFSET_DR	0x0c
++#define FTIIC010_OFFSET_SAR	0x10
++#define FTIIC010_OFFSET_TGSR	0x14
++#define FTIIC010_OFFSET_BMR	0x18
++#define FTIIC010_OFFSET_SMCR	0x1c
++#define FTIIC010_OFFSET_MAXTR	0x20
++#define FTIIC010_OFFSET_MINTR	0x24
++#define FTIIC010_OFFSET_METR	0x28
++#define FTIIC010_OFFSET_SETR	0x2c
++#define FTIIC010_OFFSET_REV	0x30
++#define FTIIC010_OFFSET_FEAT	0x34
++
++/*
++ * Control Register
++ */
++#define FTIIC010_CR_I2C_RST	(1 << 0)
++#define FTIIC010_CR_I2C_EN	(1 << 1)
++#define FTIIC010_CR_SCL_EN	(1 << 2)
++#define FTIIC010_CR_GC_EN	(1 << 3)
++#define FTIIC010_CR_START	(1 << 4)
++#define FTIIC010_CR_STOP	(1 << 5)
++#define FTIIC010_CR_NAK		(1 << 6)
++#define FTIIC010_CR_TB_EN	(1 << 7)
++#define FTIIC010_CR_DTI_EN	(1 << 8)
++#define FTIIC010_CR_DRI_EN	(1 << 9)
++#define FTIIC010_CR_BERRI_EN	(1 << 10)
++#define FTIIC010_CR_STOPI_EN	(1 << 11)
++#define FTIIC010_CR_SAMI_EN	(1 << 12)
++#define FTIIC010_CR_ALI_EN	(1 << 13)	/* arbitration lost */
++#define FTIIC010_CR_STARTI_EN	(1 << 14)
++#define FTIIC010_CR_SCL_LOW	(1 << 15)
++#define FTIIC010_CR_SDA_LOW	(1 << 16)
++#define FTIIC010_CR_TESTMODE	(1 << 17)
++
++/*
++ * Status Register
++ */
++#define FTIIC010_SR_RW		(1 << 0)
++#define FTIIC010_SR_ACK		(1 << 1)
++#define FTIIC010_SR_I2CBUSY	(1 << 2)
++#define FTIIC010_SR_BUSBUSY	(1 << 3)
++#define FTIIC010_SR_DT		(1 << 4)
++#define FTIIC010_SR_DR		(1 << 5)
++#define FTIIC010_SR_BERR	(1 << 6)
++#define FTIIC010_SR_STOP	(1 << 7)
++#define FTIIC010_SR_SAM		(1 << 8)
++#define FTIIC010_SR_GC		(1 << 9)
++#define FTIIC010_SR_AL		(1 << 10)
++#define FTIIC010_SR_START	(1 << 11)
++#define FTIIC010_SR_SEXT	(1 << 12)
++#define FTIIC010_SR_MEXT	(1 << 13)
++#define FTIIC010_SR_MINTIMEOUT	(1 << 14)
++#define FTIIC010_SR_MAXTIMEOUT	(1 << 15)
++#define FTIIC010_SR_ALERT	(1 << 16)
++#define FTIIC010_SR_SUSPEND	(1 << 17)
++#define FTIIC010_SR_RESUME	(1 << 18)
++#define FTIIC010_SR_ARA		(1 << 19)
++#define FTIIC010_SR_DDA		(1 << 20)
++#define FTIIC010_SR_SAL		(1 << 21)
++
++/*
++ * Clock Division Register
++ */
++#define FTIIC010_CDR_MASK	0x3ffff
++
++/*
++ * Data Register
++ */
++#define FTIIC010_DR_MASK	0xff
++
++/*
++ * Slave Address Register
++ */
++#define FTIIC010_SAR_MASK	0x3ff
++#define FTIIC010_SAR_EN10	(1 << 31)
++
++/*
++ * Set/Hold Time Glitch Suppression Setting Register
++ */
++#define FTIIC010_TGSR_TSR(x)	((x) & 0x3ff)	/* should not be zero */
++#define FTIIC010_TGSR_GSR(x)	(((x) & 0x7) << 10)
++
++/*
++ * Bus Monitor Register
++ */
++#define FTIIC010_BMR_SDA_IN	(1 << 0)
++#define FTIIC010_BMR_SCL_IN	(1 << 1)
++
++/*
++ * SM Control Register
++ */
++#define FTIIC010_SMCR_SEXT_EN	(1 << 0)
++#define FTIIC010_SMCR_MEXT_EN	(1 << 1)
++#define FTIIC010_SMCR_TOUT_EN	(1 << 2)
++#define FTIIC010_SMCR_ALERT_EN	(1 << 3)
++#define FTIIC010_SMCR_SUS_EN	(1 << 4)
++#define FTIIC010_SMCR_RSM_EN	(1 << 5)
++#define FTIIC010_SMCR_SAL_EN	(1 << 8)
++#define FTIIC010_SMCR_ALERT_LOW	(1 << 9)
++#define FTIIC010_SMCR_SUS_LOW	(1 << 10)
++#define FTIIC010_SMCR_SUSOUT_EN	(1 << 11)
++
++/*
++ * SM Maximum Timeout Register
++ */
++#define FTIIC010_MAXTR_MASK	0x3fffff
++
++/*
++ * SM Minimum Timeout Register
++ */
++#define FTIIC010_MINTR_MASK	0x3fffff
++
++/*
++ * SM Master Extend Time Register
++ */
++#define FTIIC010_METR_MASK	0xfffff
++
++/*
++ * SM Slave Extend Time Register
++ */
++#define FTIIC010_SETR_MASK	0x1fffff
++
++/*
++ * Feature Register
++ */
++#define FTIIC010_FEAT_SMBUS	(1 << 0)
++
++#endif /* __FTIIC010_H */
+diff --git a/drivers/i2c/busses/i2c-ftiic010-new-intr-mode.c b/drivers/i2c/busses/i2c-ftiic010-new-intr-mode.c
+new file mode 100644
+index 00000000..787efff0
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-ftiic010-new-intr-mode.c
+@@ -0,0 +1,647 @@
++/*
++ * Faraday FTIIC010 I2C Controller
++ *
++ * (C) Copyright 2010 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <mach/ftpmu010.h>
++#include "ftiic010.h"
++
++#define MAX_RETRY	1000
++#define SCL_SPEED	(100 * 1000)
++#define TIMEOUT     (HZ/10)    /* 100 ms */
++
++/* Default APB bus is APB0 for I2C, we don't use APB_CLK_IN anymore */
++#define PCLK	APB0_CLK_IN
++
++#define GSR	    0xF
++#define TSR	    0x27
++
++#define CONFIG_I2C_AUTO_RELEASE_HANGING
++#ifdef CONFIG_I2C_AUTO_RELEASE_HANGING
++#include <linux/kthread.h>
++#define I2C_HANGS_DETECT_THRESHOLD 20 ///< 20 (times) * 100ms (thread delay) = 2 seconds
++#endif ///< end of CONFIG_I2C_AUTO_RELEASE_HANGING
++
++struct ftiic010 {
++	struct resource *res;
++	void __iomem    *base;
++	int     irq;
++	struct i2c_adapter adapter;
++	int tx_ack;
++	int rx_ack;
++	wait_queue_head_t waitq;
++	struct i2c_msg *msg;
++	int tx_index;
++	int rx_index;
++	int last;
++};
++
++#ifdef CONFIG_I2C_AUTO_RELEASE_HANGING
++static int i2c_hangs_detect_count = 0;
++
++static void ftiic010_hw_init(struct ftiic010 *);
++
++static int i2c_hangs_detect_handler(void *data)
++{
++    struct ftiic010 *i2c = (struct ftiic010 *)data;
++    u32 sda, cr;
++    int i;
++
++    while(true) {
++        sda = ioread32(i2c->base + FTIIC010_OFFSET_BMR) & FTIIC010_BMR_SDA_IN;
++        if(sda == 1)
++            i2c_hangs_detect_count = 0;
++        else
++            i2c_hangs_detect_count++;
++
++        if(i2c_hangs_detect_count >= I2C_HANGS_DETECT_THRESHOLD) { ///< I2C bus is busy over 2s
++            i2c_hangs_detect_count = 0;
++            cr = ioread32(i2c->base + FTIIC010_OFFSET_CR);
++            for(i = 0 ; i < 10; i++) { ///< Force I2C host output 9 SCL clock pulse
++	            iowrite32(cr | FTIIC010_CR_SCL_LOW, i2c->base + FTIIC010_OFFSET_CR);
++                udelay(10);
++	            iowrite32((cr & ~(FTIIC010_CR_SCL_LOW)), i2c->base + FTIIC010_OFFSET_CR);
++                udelay(10);
++            }
++            ftiic010_hw_init(i2c);
++            if(printk_ratelimit())
++                dev_err(&i2c->adapter.dev, "I2C hangs detected! Release the I2C bus via I2C CR!\n");
++        }
++        msleep(100);
++    }
++    return 0;
++}
++static struct task_struct *i2c_hangs_detect_thread = NULL;
++
++#endif ///< end of CONFIG_I2C_AUTO_RELEASE_HANGING
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static void ftiic010_reset(struct ftiic010 *ftiic010)
++{
++	int cr = FTIIC010_CR_I2C_RST;
++
++	iowrite32(cr, ftiic010->base + FTIIC010_OFFSET_CR);
++
++	/* wait until reset bit cleared by hw */
++	while (ioread32(ftiic010->base + FTIIC010_OFFSET_CR) & FTIIC010_CR_I2C_RST);
++}
++
++void ftiic010_set_clock_speed(struct ftiic010 *ftiic010, int hz)
++{
++	int cdr;
++        
++    if(unlikely(hz < 50*1000)){
++	    dev_err(&ftiic010->adapter.dev, "Speed smaller than 50 KHz, set %d hz fail\n",hz);
++        return ;
++    }
++
++
++    if(unlikely(hz > 400*1000)){
++	    dev_err(&ftiic010->adapter.dev, "Speed greater than 400 KHz, set %d hz fail\n",hz);
++        return;
++    }
++
++	cdr = (PCLK / hz - GSR) / 2 - 2;
++	cdr &= FTIIC010_CDR_MASK;
++
++	dev_dbg(&ftiic010->adapter.dev, "  [CDR] = %08x\n", cdr);
++	iowrite32(cdr, ftiic010->base + FTIIC010_OFFSET_CDR);
++}
++
++static void ftiic010_set_tgsr(struct ftiic010 *ftiic010, int tsr, int gsr)
++{
++	int tgsr;
++
++	tgsr = FTIIC010_TGSR_TSR(tsr);
++	tgsr |= FTIIC010_TGSR_GSR(gsr);
++
++	dev_dbg(&ftiic010->adapter.dev, "  [TGSR] = %08x\n", tgsr);
++	iowrite32(tgsr, ftiic010->base + FTIIC010_OFFSET_TGSR);
++}
++
++static void ftiic010_hw_init(struct ftiic010 *ftiic010)
++{
++    ftiic010_reset(ftiic010);
++    ftiic010_set_tgsr(ftiic010, TSR, GSR);
++    ftiic010_set_clock_speed(ftiic010, SCL_SPEED);
++#ifdef CONFIG_I2C_AUTO_RELEASE_HANGING
++    if(!i2c_hangs_detect_thread) {
++        i2c_hangs_detect_thread = kthread_run(i2c_hangs_detect_handler, (void *)ftiic010, "i2c_hangs_detect_thread");
++        if (IS_ERR(i2c_hangs_detect_thread))
++            panic("%s: unable to create kernel thread: %ld\n", __func__, PTR_ERR(i2c_hangs_detect_thread));
++        else
++            printk("I2C hangs detection thread started!\n");
++    }
++#endif
++}
++
++static inline void ftiic010_set_cr(struct ftiic010 *ftiic010, int start,
++		int stop, int nak)
++{
++	unsigned int cr;
++
++	cr = FTIIC010_CR_I2C_EN
++	   | FTIIC010_CR_SCL_EN
++	   | FTIIC010_CR_TB_EN
++#ifdef CONFIG_I2C_INTERRUPT_MODE	   
++	   | FTIIC010_CR_DTI_EN
++	   | FTIIC010_CR_DRI_EN
++#endif	   
++	   | FTIIC010_CR_BERRI_EN
++	   | FTIIC010_CR_ALI_EN;
++
++	if (start)
++		cr |= FTIIC010_CR_START;
++
++	if (stop)
++		cr |= FTIIC010_CR_STOP;
++
++	if (nak)
++		cr |= FTIIC010_CR_NAK;
++            
++	iowrite32(cr, ftiic010->base + FTIIC010_OFFSET_CR);
++}
++
++static int ftiic010_tx_byte(struct ftiic010 *ftiic010, __u8 data, int start,
++		int stop)
++{   		
++	iowrite32(data, ftiic010->base + FTIIC010_OFFSET_DR);
++
++	ftiic010_set_cr(ftiic010, start, stop, 0);	
++
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	return 0;
++#else
++    {
++        int i = 0;
++
++        for (i = 0; i < MAX_RETRY; i++) 
++        {
++            unsigned int status;
++
++            status = ioread32(ftiic010->base + FTIIC010_OFFSET_SR);
++            if (status & FTIIC010_SR_DT)
++                return 0;
++
++            udelay(1);
++        }	
++        
++        ftiic010_hw_init(ftiic010);
++    }
++	return -EIO;
++#endif
++}
++
++static int ftiic010_rx_byte(struct ftiic010 *ftiic010, int stop, int nak)
++{       
++	ftiic010_set_cr(ftiic010, 0, stop, nak);
++
++#ifdef CONFIG_I2C_INTERRUPT_MODE	
++	return 0;
++#else
++    {
++        int i = 0;
++        for (i = 0; i < MAX_RETRY; i++) 
++        {
++            unsigned int status;
++
++            status = ioread32(ftiic010->base + FTIIC010_OFFSET_SR);
++            if (status & FTIIC010_SR_DR) 		
++                return ioread32(ftiic010->base + FTIIC010_OFFSET_DR) & FTIIC010_DR_MASK;
++
++            udelay(1);
++        }
++
++        dev_err(&ftiic010->adapter.dev, "I2C: Failed to receive!\n");
++        
++        ftiic010_hw_init(ftiic010);
++    }
++	return -EIO;
++#endif	
++}
++
++static int ftiic010_tx_msg(struct ftiic010 *ftiic010,
++		struct i2c_msg *msg, int last)
++{
++	__u8 data;	
++	int ret;
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	ftiic010->tx_ack = 0;
++	ftiic010->msg = msg;
++	ftiic010->tx_index = 0;
++	ftiic010->last = last;
++#else
++	int i, stop = 0;
++#endif
++	data = (msg->addr & 0x7f) << 1 | 0; /* write */
++	ret = ftiic010_tx_byte(ftiic010, data, 1, 0);
++	if(unlikely(ret < 0)){
++		return ret;
++	}
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	wait_event_timeout(ftiic010->waitq, ftiic010->tx_ack, TIMEOUT);
++
++	if (unlikely(!ftiic010->tx_ack)){
++		dev_err(&ftiic010->adapter.dev, "I2C TX data 0x%x timeout!\n", data);
++
++		ftiic010_hw_init(ftiic010);
++		return -EIO;
++	}
++	return 0;
++#else
++	for (i = 0; i < msg->len; i++) {
++		if (last && (i + 1 == msg->len))
++			stop = 1;
++        
++		ret = ftiic010_tx_byte(ftiic010, msg->buf[i], 0, stop);
++		if(unlikely(ret < 0)){
++			return ret;
++		}
++	}
++	
++	return 0;
++#endif
++}
++
++static int ftiic010_rx_msg(struct ftiic010 *ftiic010,
++		struct i2c_msg *msg, int last)
++{
++    __u8 data;
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++    int stop = 0;
++    int nak = 0;
++    unsigned int cr, status;
++#else
++    int ret;
++#endif
++    int i;
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++    ftiic010->tx_ack = 0;
++    ftiic010->msg = msg;
++    if(ftiic010->msg == NULL) {
++        ftiic010->msg = msg;    ///< Keep away from null pointer dereference
++        ftiic010->tx_index = 1; ///< No stop bit
++    }
++#endif
++	data = (msg->addr & 0x7f) << 1 | 1; /* read */
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++    ///< Change to use polling mode to send I2C read device address for byte-to-byte delay decreasing
++    iowrite32(data, ftiic010->base + FTIIC010_OFFSET_DR);
++    cr = FTIIC010_CR_I2C_EN | FTIIC010_CR_SCL_EN | FTIIC010_CR_TB_EN 
++       | FTIIC010_CR_BERRI_EN | FTIIC010_CR_ALI_EN | FTIIC010_CR_START;
++    iowrite32(cr, ftiic010->base + FTIIC010_OFFSET_CR);
++#else
++	ret = ftiic010_tx_byte(ftiic010, data, 1, 0);
++	if (unlikely(ret < 0)){
++		return ret;
++	}
++#endif
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++    ///< Polling wait to make sure if above "send I2C read device address" was completed
++    for(i = 0; i < MAX_RETRY; i++) {
++        status = ioread32(ftiic010->base + FTIIC010_OFFSET_SR);
++        if(status & FTIIC010_SR_DT)
++            ftiic010->tx_ack = 1;
++        udelay(1);
++    }
++    if(unlikely(!ftiic010->tx_ack)) {
++        dev_err(&ftiic010->adapter.dev, "I2C RX MSG set address timeout!\n");
++        ftiic010_hw_init(ftiic010);
++        return -EIO;
++    }
++    ftiic010->rx_ack = 0;
++    ftiic010->rx_index = 0;
++    ftiic010->last = last;
++    if (msg->len == 1){
++        if(last) {
++            stop = 1;
++        }
++        nak = 1;
++    }
++    ftiic010_rx_byte(ftiic010, stop, nak);
++    wait_event_timeout(ftiic010->waitq, ftiic010->rx_ack, TIMEOUT);
++    if(unlikely(!ftiic010->rx_ack)) {
++        dev_err(&ftiic010->adapter.dev, "I2C RX data 0x%x timeout!\n", data);
++        ftiic010_hw_init(ftiic010);
++        return -EIO;
++    }
++    return 0;
++#else
++	for (i = 0; i < msg->len; i++) {
++		int nak = 0;
++		int stop = 0;
++
++		if (i + 1 == msg->len){
++			if(last){
++				stop = 1;
++			}
++			nak = 1;
++		}
++
++		ret = ftiic010_rx_byte(ftiic010, stop, nak);
++		if (unlikely(ret < 0)){
++			return ret;
++		}
++	    
++		msg->buf[i] = ret;
++	}
++	
++	return 0;
++#endif
++}
++
++static int ftiic010_do_msg(struct ftiic010 *ftiic010,
++		struct i2c_msg *msg, int last)
++{
++	if (msg->flags & I2C_M_RD)
++		return ftiic010_rx_msg(ftiic010, msg, last);
++	else
++		return ftiic010_tx_msg(ftiic010, msg, last);
++}
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftiic010_interrupt(int irq, void *dev_id)
++{
++	struct ftiic010 *ftiic010 = dev_id;
++	struct i2c_adapter *adapter = &ftiic010->adapter;
++	int sr;
++
++	if(ftiic010->msg == NULL) {
++		// Workaround to prevent a null pointer accessing
++		// If two or more CPUs request this IRQ for I2C interrupt, e.g. CPU A&B
++		// When B issued a I2C transfer and caused an I2C interrupt
++		// A goes into this ISR and tries to access uninitialized structure
++		dev_dbg(&adapter->dev, "It seems that another (CPU) master caused an I2C interrupt, so let's ignore it! \n");
++		dev_dbg(&adapter->dev, "Please do not use I2C interrupt mode on a multi-CPU system! \n");
++		return IRQ_HANDLED; // Ingore this interrupt
++	}
++
++	sr = ioread32(ftiic010->base + FTIIC010_OFFSET_SR);
++	if (sr & FTIIC010_SR_DT) {
++		int stop = 0;
++		if (ftiic010->last && ((ftiic010->tx_index + 1) == ftiic010->msg->len))
++			stop = 1;
++		dev_dbg(&adapter->dev, "data transmitted\n");
++		if (ftiic010->tx_index < ftiic010->msg->len){
++			ftiic010_tx_byte(ftiic010, ftiic010->msg->buf[ftiic010->tx_index], 0, stop);
++			ftiic010->tx_index++;
++		}
++		else{
++			ftiic010->tx_ack = 1;
++			wake_up(&ftiic010->waitq);
++		}
++	}
++
++	if (sr & FTIIC010_SR_DR) {
++		int nak = 0;
++		int stop = 0;
++
++		dev_dbg(&adapter->dev, "data received\n");
++		if(ftiic010->msg->len > 0) { /* Workaround to prevent a illegal I2C accessing */
++			ftiic010->msg->buf[ftiic010->rx_index] = ioread32(ftiic010->base + FTIIC010_OFFSET_DR) & FTIIC010_DR_MASK;
++			ftiic010->rx_index++;
++		}
++		else {
++			dev_dbg(&adapter->dev, "Illegal I2C accessing, message buffer size <= 0! It will cause I2C sub-device abnormal, please reset it. \n");
++		}
++		if (ftiic010->rx_index < ftiic010->msg->len){
++			if ((ftiic010->rx_index + 1) == ftiic010->msg->len){
++				if(ftiic010->last){
++					stop = 1;
++				}
++				nak = 1;
++			}
++			ftiic010_rx_byte(ftiic010, stop, nak);
++		}
++		else{
++			ftiic010->rx_ack = 1;
++			wake_up(&ftiic010->waitq);
++		}
++	}
++
++	if (sr & FTIIC010_SR_BERR) {
++		dev_err(&adapter->dev, "NAK!\n");
++		ftiic010_hw_init(ftiic010);
++	}
++
++	if (sr & FTIIC010_SR_AL) {
++		dev_err(&adapter->dev, "arbitration lost!\n");
++		ftiic010_hw_init(ftiic010);
++	}
++
++	return IRQ_HANDLED;
++}
++#endif
++/******************************************************************************
++ * struct i2c_algorithm functions
++ *****************************************************************************/
++static int ftiic010_master_xfer(struct i2c_adapter *adapter,
++		struct i2c_msg *msgs, int num)
++{
++	struct ftiic010 *ftiic010 = i2c_get_adapdata(adapter);
++	int i;
++	
++	for (i = 0; i < num; i++) {
++		int ret, last = 0;
++
++		if (i == num - 1){
++			last = 1;
++        	}
++
++		ret = ftiic010_do_msg(ftiic010, &msgs[i], last);
++		if (unlikely(ret < 0)){
++			ftiic010_hw_init(ftiic010);
++	        	return ret;
++		}
++	}
++	return num;
++}
++
++static u32 ftiic010_functionality(struct i2c_adapter *adapter)
++{
++	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++static struct i2c_algorithm ftiic010_algorithm = {
++	.master_xfer	= ftiic010_master_xfer,
++	.functionality	= ftiic010_functionality,
++};
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftiic010_probe(struct platform_device *pdev)
++{
++	struct ftiic010 *ftiic010;
++	struct resource *res;
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	int irq;
++#endif
++	int ret;
++    
++    /* This function will be called several times and pass different pdev structure
++     */
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res)
++		return -ENXIO;
++
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	if ((irq = platform_get_irq(pdev, 0)) < 0)
++		return irq;
++#endif
++	ftiic010 = kzalloc(sizeof(*ftiic010), GFP_KERNEL);
++	if (!ftiic010) {
++		dev_err(&pdev->dev, "Could not allocate private data\n");
++		ret = -ENOMEM;
++		goto err_alloc;
++	}
++
++	init_waitqueue_head(&ftiic010->waitq);
++    
++    /* mark the region is occupied */
++	ftiic010->res = request_mem_region(res->start,
++			res->end - res->start, dev_name(&pdev->dev));
++	if (ftiic010->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		ret = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftiic010->base = ioremap(res->start, res->end - res->start);
++	if (ftiic010->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap\n");
++		ret = -ENOMEM;
++		goto err_ioremap;
++	}
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	ret = request_irq(irq, ftiic010_interrupt, IRQF_SHARED, pdev->name, ftiic010);
++	if (ret) {
++		dev_err(&pdev->dev, "Failed to request irq %d\n", irq);
++		goto err_req_irq;
++	}
++
++	ftiic010->irq = irq;
++#endif
++	/*
++	 * initialize i2c adapter
++	 */
++	ftiic010->adapter.owner 	= THIS_MODULE;
++	ftiic010->adapter.algo		= &ftiic010_algorithm;
++	ftiic010->adapter.timeout	= 1;
++	ftiic010->adapter.dev.parent	= &pdev->dev;
++	strcpy(ftiic010->adapter.name, "ftiic010 adapter");
++
++	i2c_set_adapdata(&ftiic010->adapter, ftiic010);
++
++//#define I2C_DYNAMIC_BUS_NUM
++#ifndef I2C_DYNAMIC_BUS_NUM
++        ftiic010->adapter.nr = pdev->id;
++        ret = i2c_add_numbered_adapter(&ftiic010->adapter);
++#else
++	ret = i2c_add_adapter(&ftiic010->adapter);
++#endif
++	if (ret) {
++		dev_err(&pdev->dev, "Failed to add i2c adapter\n");
++		goto err_add_adapter;
++	}
++
++	platform_set_drvdata(pdev, ftiic010);
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	dev_info(&pdev->dev, "irq %d, mapped at %p\n", irq, ftiic010->base);
++#endif
++	ftiic010_hw_init(ftiic010);
++
++	return 0;
++err_add_adapter:
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	free_irq(ftiic010->irq, ftiic010);
++err_req_irq:
++#endif
++	iounmap(ftiic010->base);
++err_ioremap:
++	release_resource(ftiic010->res);
++err_req_mem:
++	kfree(ftiic010);
++err_alloc:
++	return ret;
++};
++
++static int __devexit ftiic010_remove(struct platform_device *pdev)
++{
++	struct ftiic010 *ftiic010 = platform_get_drvdata(pdev);
++
++#ifdef CONFIG_I2C_AUTO_RELEASE_HANGING
++    if(!IS_ERR(i2c_hangs_detect_thread)) {
++        kthread_stop(i2c_hangs_detect_thread);
++    }
++#endif
++	platform_set_drvdata(pdev, NULL);
++	i2c_del_adapter(&ftiic010->adapter);
++	free_irq(ftiic010->irq, ftiic010);
++	iounmap(ftiic010->base);
++	release_resource(ftiic010->res);
++	kfree(ftiic010);
++	return 0;
++};
++
++
++static struct platform_driver ftiic010_driver = {
++	.probe		= ftiic010_probe,
++	.remove		= __devexit_p(ftiic010_remove),
++	.driver		= {
++		.name	= "ftiic010",
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftiic010_init(void)
++{       
++	return platform_driver_register(&ftiic010_driver);
++}
++
++static void __exit ftiic010_exit(void)
++{
++	platform_driver_unregister(&ftiic010_driver);
++}
++
++EXPORT_SYMBOL(ftiic010_set_clock_speed);
++
++module_init(ftiic010_init);
++module_exit(ftiic010_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTIIC010 I2C bus adapter");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/busses/i2c-ftiic010.c b/drivers/i2c/busses/i2c-ftiic010.c
+new file mode 100644
+index 00000000..b751f322
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-ftiic010.c
+@@ -0,0 +1,565 @@
++/*
++ * Faraday FTIIC010 I2C Controller
++ *
++ * (C) Copyright 2010 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <mach/ftpmu010.h>
++#include "ftiic010.h"
++
++#define MAX_RETRY	1000
++#define SCL_SPEED	(100 * 1000)
++#define TIMEOUT     (HZ/10)    /* 100 ms */
++
++/* Default APB bus is APB0 for I2C, we don't use APB_CLK_IN anymore */
++#define PCLK	APB0_CLK_IN
++
++#define GSR	    0xF
++#define TSR	    0x27
++
++#define CONFIG_I2C_AUTO_RELEASE_HANGING
++#ifdef CONFIG_I2C_AUTO_RELEASE_HANGING
++
++#ifdef CONFIG_PLATFORM_GM8210
++#include <mach/fmem.h>
++#endif
++
++#include <linux/kthread.h>
++
++#define I2C_HANGS_DETECT_THRESHOLD 20 ///< 20 (times) * 100ms (thread delay) = 2 seconds
++
++#endif ///< end of CONFIG_I2C_AUTO_RELEASE_HANGING
++
++struct ftiic010 {
++	struct resource *res;
++	void __iomem    *base;
++	int     irq;
++	struct i2c_adapter adapter;
++	int     ack;
++	wait_queue_head_t waitq;
++};
++
++#ifdef CONFIG_I2C_AUTO_RELEASE_HANGING
++static int i2c_hangs_detect_count = 0;
++
++static void ftiic010_hw_init(struct ftiic010 *);
++
++static int i2c_hangs_detect_handler(void *data)
++{
++    struct ftiic010 *i2c = (struct ftiic010 *)data;
++    u32 sda, cr;
++    int i;
++
++    while(true) {
++        sda = ioread32(i2c->base + FTIIC010_OFFSET_BMR) & FTIIC010_BMR_SDA_IN;
++        if(sda == 1)
++            i2c_hangs_detect_count = 0;
++        else
++            i2c_hangs_detect_count++;
++
++        if(i2c_hangs_detect_count >= I2C_HANGS_DETECT_THRESHOLD) { ///< I2C bus is busy over 2s
++                i2c_hangs_detect_count = 0;
++                cr = ioread32(i2c->base + FTIIC010_OFFSET_CR);
++                for(i = 0 ; i < 10; i++) { ///< Force I2C host output 9 SCL clock pulse
++	                iowrite32(cr | FTIIC010_CR_SCL_LOW, i2c->base + FTIIC010_OFFSET_CR);
++                    udelay(10);
++	                iowrite32((cr & ~(FTIIC010_CR_SCL_LOW)), i2c->base + FTIIC010_OFFSET_CR);
++                    udelay(10);
++                }
++                ftiic010_hw_init(i2c);
++                if(printk_ratelimit())
++                    dev_err(&i2c->adapter.dev, "I2C hangs detected! Release the I2C bus via I2C CR!\n");
++        }
++        msleep(100);
++    }
++    return 0;
++}
++static struct task_struct *i2c_hangs_detect_thread = NULL;
++
++#endif ///< end of CONFIG_I2C_AUTO_RELEASE_HANGING
++
++/******************************************************************************
++ * internal functions
++ *****************************************************************************/
++static void ftiic010_reset(struct ftiic010 *ftiic010)
++{
++	int cr = FTIIC010_CR_I2C_RST;
++
++	iowrite32(cr, ftiic010->base + FTIIC010_OFFSET_CR);
++
++	/* wait until reset bit cleared by hw */
++	while (ioread32(ftiic010->base + FTIIC010_OFFSET_CR) & FTIIC010_CR_I2C_RST);
++}
++
++void ftiic010_set_clock_speed(struct ftiic010 *ftiic010, int hz)
++{
++	int cdr;
++        
++    if(unlikely(hz < 50*1000)){
++	    dev_err(&ftiic010->adapter.dev, "Speed smaller than 50 KHz, set %d hz fail\n",hz);
++        return ;
++    }
++
++
++    if(unlikely(hz > 400*1000)){
++	    dev_err(&ftiic010->adapter.dev, "Speed greater than 400 KHz, set %d hz fail\n",hz);
++        return;
++    }
++
++	cdr = (PCLK / hz - GSR) / 2 - 2;
++	cdr &= FTIIC010_CDR_MASK;
++
++	dev_dbg(&ftiic010->adapter.dev, "  [CDR] = %08x\n", cdr);
++	iowrite32(cdr, ftiic010->base + FTIIC010_OFFSET_CDR);
++}
++
++static void ftiic010_set_tgsr(struct ftiic010 *ftiic010, int tsr, int gsr)
++{
++	int tgsr;
++
++	tgsr = FTIIC010_TGSR_TSR(tsr);
++	tgsr |= FTIIC010_TGSR_GSR(gsr);
++
++	dev_dbg(&ftiic010->adapter.dev, "  [TGSR] = %08x\n", tgsr);
++	iowrite32(tgsr, ftiic010->base + FTIIC010_OFFSET_TGSR);
++}
++
++static void ftiic010_hw_init(struct ftiic010 *ftiic010)
++{
++#ifdef CONFIG_I2C_AUTO_RELEASE_HANGING
++#ifdef CONFIG_PLATFORM_GM8210
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++#endif
++#endif ///< End of CONFIG_I2C_AUTO_RELEASE_HANGING
++    ftiic010_reset(ftiic010);
++    ftiic010_set_tgsr(ftiic010, TSR, GSR);
++    ftiic010_set_clock_speed(ftiic010, SCL_SPEED);
++#ifdef CONFIG_I2C_AUTO_RELEASE_HANGING
++#ifdef CONFIG_PLATFORM_GM8210
++    if((!i2c_hangs_detect_thread) && (cpu_id == FMEM_CPU_FA626)) {
++#else
++    if(!i2c_hangs_detect_thread) {
++#endif
++        i2c_hangs_detect_thread = kthread_run(i2c_hangs_detect_handler, (void *)ftiic010, "i2c_hangs_detect_thread");
++        if (IS_ERR(i2c_hangs_detect_thread))
++            panic("%s: unable to create kernel thread: %ld\n", __func__, PTR_ERR(i2c_hangs_detect_thread));
++        else
++            printk("I2C hangs detection thread started!\n");
++    }
++#endif ///< End of CONFIG_I2C_AUTO_RELEASE_HANGING
++}
++
++static inline void ftiic010_set_cr(struct ftiic010 *ftiic010, int start,
++		int stop, int nak)
++{
++	unsigned int cr;
++
++	cr = FTIIC010_CR_I2C_EN
++	   | FTIIC010_CR_SCL_EN
++	   | FTIIC010_CR_TB_EN
++#ifdef CONFIG_I2C_INTERRUPT_MODE	   
++	   | FTIIC010_CR_DTI_EN
++	   | FTIIC010_CR_DRI_EN
++#endif	   
++	   | FTIIC010_CR_BERRI_EN
++	   | FTIIC010_CR_ALI_EN;
++
++	if (start)
++		cr |= FTIIC010_CR_START;
++
++	if (stop)
++		cr |= FTIIC010_CR_STOP;
++
++	if (nak)
++		cr |= FTIIC010_CR_NAK;
++            
++	iowrite32(cr, ftiic010->base + FTIIC010_OFFSET_CR);
++}
++
++static int ftiic010_tx_byte(struct ftiic010 *ftiic010, __u8 data, int start,
++		int stop)
++{   		
++	iowrite32(data, ftiic010->base + FTIIC010_OFFSET_DR);
++
++	ftiic010->ack = 0;
++	ftiic010_set_cr(ftiic010, start, stop, 0);	
++
++#ifdef CONFIG_I2C_INTERRUPT_MODE
++	wait_event_timeout(ftiic010->waitq, ftiic010->ack, TIMEOUT);
++		
++	if (unlikely(!ftiic010->ack)) 
++	{
++	    dev_err(&ftiic010->adapter.dev, "I2C TX data 0x%x timeout!\n", data);
++	    
++	    ftiic010_hw_init(ftiic010);
++	    return -EIO;
++	}
++	
++	return 0;
++#else
++    {
++        int i = 0;
++
++        for (i = 0; i < MAX_RETRY; i++) 
++        {
++            unsigned int status;
++
++            status = ioread32(ftiic010->base + FTIIC010_OFFSET_SR);
++            if (status & FTIIC010_SR_DT)
++                return 0;
++
++            udelay(1);
++        }	
++        
++        ftiic010_hw_init(ftiic010);
++    }
++	return -EIO;
++#endif
++}
++
++static int ftiic010_rx_byte(struct ftiic010 *ftiic010, int stop, int nak)
++{       
++	ftiic010->ack = 0;
++	ftiic010_set_cr(ftiic010, 0, stop, nak);
++
++#ifdef CONFIG_I2C_INTERRUPT_MODE	
++	wait_event_timeout(ftiic010->waitq, ftiic010->ack, TIMEOUT);
++		
++	if (unlikely(!ftiic010->ack)) 
++	{
++	    
++	    ftiic010_hw_init(ftiic010);
++	    dev_err(&ftiic010->adapter.dev, "I2C RX timeout!\n");
++	    return -EIO;
++	}
++	
++	return ioread32(ftiic010->base + FTIIC010_OFFSET_DR) & FTIIC010_DR_MASK;
++#else
++    {
++        int i = 0;
++        for (i = 0; i < MAX_RETRY; i++) 
++        {
++            unsigned int status;
++
++            status = ioread32(ftiic010->base + FTIIC010_OFFSET_SR);
++            if (status & FTIIC010_SR_DR) 		
++                return ioread32(ftiic010->base + FTIIC010_OFFSET_DR) & FTIIC010_DR_MASK;
++
++            udelay(1);
++        }
++
++        dev_err(&ftiic010->adapter.dev, "I2C: Failed to receive!\n");
++        
++        ftiic010_hw_init(ftiic010);
++    }
++	return -EIO;
++#endif	
++}
++
++static int ftiic010_tx_msg(struct ftiic010 *ftiic010,
++		struct i2c_msg *msg, int last)
++{
++	__u8 data;	
++	int i, ret;
++
++	data = (msg->addr & 0x7f) << 1 | 0; /* write */
++	ret = ftiic010_tx_byte(ftiic010, data, 1, 0);
++	if(unlikely(ret < 0)){
++		return ret;
++	}
++
++	for (i = 0; i < msg->len; i++) {
++		int stop = 0;
++
++		if (last && (i + 1 == msg->len))
++			stop = 1;
++        
++		ret = ftiic010_tx_byte(ftiic010, msg->buf[i], 0, stop);
++		if(unlikely(ret < 0)){
++			return ret;
++		}
++	}
++	
++	return 0;
++}
++
++static int ftiic010_rx_msg(struct ftiic010 *ftiic010,
++		struct i2c_msg *msg, int last)
++{
++	__u8 data;
++	int i, ret;
++
++	data = (msg->addr & 0x7f) << 1 | 1; /* read */
++	ret = ftiic010_tx_byte(ftiic010, data, 1, 0);
++	if (unlikely(ret < 0)){
++		return ret;
++	}
++	    
++	for (i = 0; i < msg->len; i++) {
++		int nak = 0;
++		int stop = 0;
++
++		if (i + 1 == msg->len){
++			if(last){
++				stop = 1;
++			}
++			nak = 1;
++		}
++
++		ret = ftiic010_rx_byte(ftiic010, stop, nak);
++		if (unlikely(ret < 0)){
++			return ret;
++		}
++	    
++		msg->buf[i] = ret;
++	}
++	
++	return 0;
++}
++
++static int ftiic010_do_msg(struct ftiic010 *ftiic010,
++		struct i2c_msg *msg, int last)
++{
++	if (msg->flags & I2C_M_RD)
++		return ftiic010_rx_msg(ftiic010, msg, last);
++	else
++		return ftiic010_tx_msg(ftiic010, msg, last);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftiic010_interrupt(int irq, void *dev_id)
++{
++	struct ftiic010 *ftiic010 = dev_id;
++	struct i2c_adapter *adapter = &ftiic010->adapter;
++	int sr;
++
++	sr = ioread32(ftiic010->base + FTIIC010_OFFSET_SR);
++
++	if (sr & FTIIC010_SR_DT) {
++		dev_dbg(&adapter->dev, "data transmitted\n");		
++		ftiic010->ack = 1;
++		wake_up(&ftiic010->waitq);
++	}
++
++	if (sr & FTIIC010_SR_DR) {
++		dev_dbg(&adapter->dev, "data received\n");		
++		ftiic010->ack = 1;
++		wake_up(&ftiic010->waitq);
++	}
++
++	if (sr & FTIIC010_SR_BERR) {
++		dev_err(&adapter->dev, "NAK!\n");
++		ftiic010_hw_init(ftiic010);
++	}
++
++	if (sr & FTIIC010_SR_AL) {
++		dev_err(&adapter->dev, "arbitration lost!\n");
++		ftiic010_hw_init(ftiic010);
++	}
++
++	return IRQ_HANDLED;
++}
++
++/******************************************************************************
++ * struct i2c_algorithm functions
++ *****************************************************************************/
++static int ftiic010_master_xfer(struct i2c_adapter *adapter,
++		struct i2c_msg *msgs, int num)
++{
++	struct ftiic010 *ftiic010 = i2c_get_adapdata(adapter);
++	int i;
++	
++	for (i = 0; i < num; i++) {
++		int ret, last = 0;
++
++		if (i == num - 1){
++			last = 1;
++        	}
++
++		ret = ftiic010_do_msg(ftiic010, &msgs[i], last);
++		if (unlikely(ret < 0)){
++			ftiic010_hw_init(ftiic010);
++	        	return ret;
++		}
++	}
++	return num;
++}
++
++static u32 ftiic010_functionality(struct i2c_adapter *adapter)
++{
++	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++static struct i2c_algorithm ftiic010_algorithm = {
++	.master_xfer	= ftiic010_master_xfer,
++	.functionality	= ftiic010_functionality,
++};
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftiic010_probe(struct platform_device *pdev)
++{
++	struct ftiic010 *ftiic010;
++	struct resource *res;
++	int irq;
++	int ret;
++    
++    /* This function will be called several times and pass different pdev structure
++     */
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res)
++		return -ENXIO;
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0)
++		return irq;
++
++	ftiic010 = kzalloc(sizeof(*ftiic010), GFP_KERNEL);
++	if (!ftiic010) {
++		dev_err(&pdev->dev, "Could not allocate private data\n");
++		ret = -ENOMEM;
++		goto err_alloc;
++	}
++
++	init_waitqueue_head(&ftiic010->waitq);
++    
++    /* mark the region is occupied */
++	ftiic010->res = request_mem_region(res->start,
++			res->end - res->start, dev_name(&pdev->dev));
++	if (ftiic010->res == NULL) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		ret = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	ftiic010->base = ioremap(res->start, res->end - res->start);
++	if (ftiic010->base == NULL) {
++		dev_err(&pdev->dev, "Failed to ioremap\n");
++		ret = -ENOMEM;
++		goto err_ioremap;
++	}
++
++	ret = request_irq(irq, ftiic010_interrupt, IRQF_SHARED, pdev->name, ftiic010);
++	if (ret) {
++		dev_err(&pdev->dev, "Failed to request irq %d\n", irq);
++		goto err_req_irq;
++	}
++
++	ftiic010->irq = irq;
++
++	/*
++	 * initialize i2c adapter
++	 */
++	ftiic010->adapter.owner 	= THIS_MODULE;
++	ftiic010->adapter.algo		= &ftiic010_algorithm;
++	ftiic010->adapter.timeout	= 1;
++	ftiic010->adapter.dev.parent	= &pdev->dev;
++	strcpy(ftiic010->adapter.name, "ftiic010 adapter");
++
++	i2c_set_adapdata(&ftiic010->adapter, ftiic010);
++
++//#define I2C_DYNAMIC_BUS_NUM
++#ifndef I2C_DYNAMIC_BUS_NUM
++        ftiic010->adapter.nr = pdev->id; // "pdev->id" was defined in platform.c
++        ret = i2c_add_numbered_adapter(&ftiic010->adapter);
++#else
++	ret = i2c_add_adapter(&ftiic010->adapter);
++#endif
++	if (ret) {
++		dev_err(&pdev->dev, "Failed to add i2c adapter\n");
++		goto err_add_adapter;
++	}
++
++	platform_set_drvdata(pdev, ftiic010);
++
++	dev_info(&pdev->dev, "irq %d, mapped at %p\n", irq, ftiic010->base);
++
++	ftiic010_hw_init(ftiic010);
++
++	return 0;
++
++err_add_adapter:
++	free_irq(ftiic010->irq, ftiic010);
++err_req_irq:
++	iounmap(ftiic010->base);
++err_ioremap:
++	release_resource(ftiic010->res);
++err_req_mem:
++	kfree(ftiic010);
++err_alloc:
++	return ret;
++};
++
++static int __devexit ftiic010_remove(struct platform_device *pdev)
++{
++	struct ftiic010 *ftiic010 = platform_get_drvdata(pdev);
++
++	platform_set_drvdata(pdev, NULL);
++	i2c_del_adapter(&ftiic010->adapter);
++	free_irq(ftiic010->irq, ftiic010);
++	iounmap(ftiic010->base);
++	release_resource(ftiic010->res);
++	kfree(ftiic010);
++	return 0;
++};
++
++
++static struct platform_driver ftiic010_driver = {
++	.probe		= ftiic010_probe,
++	.remove		= __devexit_p(ftiic010_remove),
++	.driver		= {
++		.name	= "ftiic010",
++		.owner	= THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftiic010_init(void)
++{        
++	return platform_driver_register(&ftiic010_driver);
++}
++
++static void __exit ftiic010_exit(void)
++{
++	platform_driver_unregister(&ftiic010_driver);
++}
++
++EXPORT_SYMBOL(ftiic010_set_clock_speed);
++
++module_init(ftiic010_init);
++module_exit(ftiic010_exit);
++
++MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
++MODULE_DESCRIPTION("FTIIC010 I2C bus adapter");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
+index e9c18939..893bf8a5 100644
+--- a/drivers/i2c/i2c-core.c
++++ b/drivers/i2c/i2c-core.c
+@@ -1,4 +1,4 @@
+-/* i2c-core.c - a device driver for the iic-bus interface		     */
++/* i2c-core.c - a device driver for the iic-bus interface		     */
+ /* ------------------------------------------------------------------------- */
+ /*   Copyright (C) 1995-99 Simon G. Vogl
+ 
+@@ -52,6 +52,65 @@ static DEFINE_IDR(i2c_adapter_idr);
+ static struct device_type i2c_client_type;
+ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
+ 
++#if (defined(CONFIG_PLATFORM_GM8210) && defined(CONFIG_GM8312))
++#include <mach/platform/board.h>
++
++/* lock i2c bus */
++static inline void lock_i2c_bus(int adapter_nr)
++{
++    switch (adapter_nr) {
++      case 0:
++        board_bus_lock(BUS_LOCK_I2C);
++        break;
++      case 1:
++        board_bus_lock(BUS_LOCK_I2C1);
++        break;
++      case 2:
++        board_bus_lock(BUS_LOCK_I2C2);
++        break;
++      case 3:
++        board_bus_lock(BUS_LOCK_I2C3);
++        break;
++      case 4:
++        board_bus_lock(BUS_LOCK_I2C4);
++        break;
++      case 5:
++        board_bus_lock(BUS_LOCK_I2C5);
++        break;
++      default:
++        printk("%s, id: %d is not supported! \n", __func__, adapter_nr);
++        break;
++    }
++}
++
++/* unlock i2c bus */
++static inline void unlock_i2c_bus(int adapter_nr)
++{
++    switch (adapter_nr) {
++      case 0:
++        board_bus_unlock(BUS_LOCK_I2C);
++        break;
++      case 1:
++        board_bus_unlock(BUS_LOCK_I2C1);
++        break;
++      case 2:
++        board_bus_unlock(BUS_LOCK_I2C2);
++        break;
++      case 3:
++        board_bus_unlock(BUS_LOCK_I2C3);
++        break;
++      case 4:
++        board_bus_unlock(BUS_LOCK_I2C4);
++        break;
++      case 5:
++        board_bus_unlock(BUS_LOCK_I2C5);
++        break;
++      default:
++        printk("%s, id: %d is not supported! \n", __func__, adapter_nr);
++        break;
++    }
++}
++#endif /* CONFIG_PLATFORM_GM8210 */
+ /* ------------------------------------------------------------------------- */
+ 
+ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
+@@ -446,10 +505,14 @@ void i2c_lock_adapter(struct i2c_adapter *adapter)
+ {
+ 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+ 
+-	if (parent)
++	if (parent) {
+ 		i2c_lock_adapter(parent);
+-	else
++	} else {
+ 		rt_mutex_lock(&adapter->bus_lock);
++#if (defined(CONFIG_PLATFORM_GM8210) && defined(CONFIG_GM8312))
++        lock_i2c_bus(adapter->nr);
++#endif
++	}
+ }
+ EXPORT_SYMBOL_GPL(i2c_lock_adapter);
+ 
+@@ -461,10 +524,21 @@ static int i2c_trylock_adapter(struct i2c_adapter *adapter)
+ {
+ 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+ 
+-	if (parent)
++	if (parent) {
+ 		return i2c_trylock_adapter(parent);
+-	else
++	}
++	else {
++#if (defined(CONFIG_PLATFORM_GM8210) && defined(CONFIG_GM8312))
++        int ret = rt_mutex_trylock(&adapter->bus_lock);
++
++        if (ret)
++            lock_i2c_bus(adapter->nr);
++
++        return ret;
++#else
+ 		return rt_mutex_trylock(&adapter->bus_lock);
++#endif
++	}
+ }
+ 
+ /**
+@@ -475,10 +549,15 @@ void i2c_unlock_adapter(struct i2c_adapter *adapter)
+ {
+ 	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+ 
+-	if (parent)
++	if (parent) {
+ 		i2c_unlock_adapter(parent);
+-	else
++	}
++	else {
++#if (defined(CONFIG_PLATFORM_GM8210) && defined(CONFIG_GM8312))
++        unlock_i2c_bus(adapter->nr);
++#endif
+ 		rt_mutex_unlock(&adapter->bus_lock);
++	}
+ }
+ EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
+ 
+@@ -836,7 +915,32 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
+ 		return -EINVAL;
+ 	}
+ 
++#if (defined(CONFIG_PLATFORM_GM8210) && defined(CONFIG_GM8312))
++    switch(adap->nr) {
++      case 0:
++        board_bus_lock_init(BUS_LOCK_I2C);
++        break;
++      case 1:
++        board_bus_lock_init(BUS_LOCK_I2C1);
++        break;
++      case 2:
++        board_bus_lock_init(BUS_LOCK_I2C2);
++        break;
++      case 3:
++        board_bus_lock_init(BUS_LOCK_I2C3);
++        break;
++      case 4:
++        board_bus_lock_init(BUS_LOCK_I2C4);
++        break;
++      case 5:
++        board_bus_lock_init(BUS_LOCK_I2C5);
++        break;
++      default:
++        break;
++    }
++#endif /* CONFIG_PLATFORM_GM8210 */
+ 	rt_mutex_init(&adap->bus_lock);
++
+ 	mutex_init(&adap->userspace_clients_lock);
+ 	INIT_LIST_HEAD(&adap->userspace_clients);
+ 
+@@ -913,6 +1017,7 @@ retry:
+ 	}
+ 
+ 	adapter->nr = id;
++
+ 	return i2c_register_adapter(adapter);
+ }
+ EXPORT_SYMBOL(i2c_add_adapter);
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index c6a383d0..3d2b9203 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -43,6 +43,7 @@
+ 
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
++#include <mach/platform/board.h>
+ 
+ #include "queue.h"
+ 
+@@ -122,6 +123,7 @@ enum mmc_blk_status {
+ 	MMC_BLK_DATA_ERR,
+ 	MMC_BLK_ECC_ERR,
+ 	MMC_BLK_NOMEDIUM,
++	MMC_BLK_DRIVING_CHANGE,
+ };
+ 
+ module_param(perdev_minors, int, 0444);
+@@ -874,7 +876,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
+ {
+ 	struct mmc_blk_data *md = mq->data;
+ 	struct mmc_card *card = md->queue.card;
+-	unsigned int from, nr, arg;
++	unsigned int from = 0, nr = 0, arg = 0; /* for eliminate warning, eason */
+ 	int err = 0, type = MMC_BLK_SECDISCARD;
+ 
+ 	if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
+@@ -1058,7 +1060,8 @@ static int mmc_blk_err_check(struct mmc_card *card,
+ 				return MMC_BLK_ECC_ERR;
+ 			return MMC_BLK_DATA_ERR;
+ 		} else {
+-			return MMC_BLK_CMD_ERR;
++			//return MMC_BLK_CMD_ERR;
++			return MMC_BLK_DRIVING_CHANGE;
+ 		}
+ 	}
+ 
+@@ -1253,6 +1256,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+ 	struct mmc_queue_req *mq_rq;
+ 	struct request *req;
+ 	struct mmc_async_req *areq;
++	int d_strength, d_strength_retry = 0;
+ 
+ 	if (!rqc && !mq->mqrq_prev->req)
+ 		return 0;
+@@ -1302,6 +1306,33 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+ 			if (!mmc_blk_reset(md, card->host, type))
+ 				break;
+ 			goto cmd_abort;
++		case MMC_BLK_DRIVING_CHANGE:
++			if (d_strength_retry < 4) {
++                /* Change driving strength */
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++                /*  from Datasheet in T:\MTD\Service\GM8139
++                 *  sdc _dcsr[1:0]: Driving capability control
++                 *  0: 6mA, 1: 8mA, 2: 10mA, 3: 12mA
++                 */
++                printk("Try to change SDHC driving strength:\n");
++				printk("SCU 0x40 before: 0x%08x,", readl(PMU_FTPMU010_VA_BASE + 0x40));
++				d_strength = (readl(PMU_FTPMU010_VA_BASE + 0x40) & 0x0f0) >> 4;
++                if (d_strength_retry != d_strength) {
++                    d_strength = readl(PMU_FTPMU010_VA_BASE + 0x40);
++                    d_strength &= ~(0x3 << 4);
++                    d_strength |= (d_strength_retry << 4);
++                    writel(d_strength, PMU_FTPMU010_VA_BASE + 0x40);
++                }
++				printk("SCU 0x40 after: 0x%08x\n", readl(PMU_FTPMU010_VA_BASE + 0x40));
++#endif
++                d_strength_retry ++;
++				break;
++            } else {
++                ret = mmc_blk_cmd_err(md, card, brq, req, ret);
++                if (!mmc_blk_reset(md, card->host, type))
++                    break;
++                goto cmd_abort;
++            }
+ 		case MMC_BLK_RETRY:
+ 			if (retry++ < 5)
+ 				break;
+@@ -1899,4 +1930,3 @@ module_exit(mmc_blk_exit);
+ 
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
+-
+diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
+index 132378b8..d763165d 100644
+--- a/drivers/mmc/core/core.c
++++ b/drivers/mmc/core/core.c
+@@ -41,6 +41,15 @@
+ #include "sd_ops.h"
+ #include "sdio_ops.h"
+ 
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <mach/platform/board.h>
++
++#if defined(CONFIG_MMC_FTSDC021_VEND_TUNE)
++#include <mach/platform/platform_io.h>
++extern uint ftsdc021_pulse_latch;
++#endif
++
+ static struct workqueue_struct *workqueue;
+ 
+ /*
+@@ -2054,6 +2063,11 @@ EXPORT_SYMBOL(mmc_hw_reset_check);
+ 
+ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
+ {
++	#if defined(CONFIG_MMC_FTSDC021_VEND_TUNE)	
++	uint d_strength, d_strength_retry = 0;
++	uint strength_level[] = { 2, 3, 1, 0 };
++	#endif
++	
+ 	host->f_init = freq;
+ 
+ #ifdef CONFIG_MMC_DEBUG
+@@ -2082,14 +2096,47 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
+ 	mmc_send_if_cond(host, host->ocr_avail);
+ 
+ 	/* Order's important: probe SDIO, then SD, then MMC */
+-	if (!mmc_attach_sdio(host))
+-		return 0;
+-	if (!mmc_attach_sd(host))
+-		return 0;
+-	if (!mmc_attach_mmc(host))
+-		return 0;
++	#if defined(CONFIG_MMC_FTSDC021_VEND_TUNE)
++			for (d_strength_retry = 0; d_strength_retry < 4; d_strength_retry++) 
++			{
++		                /* Change driving strength */	
++		                /* sdc _dcsr[1:0]: Driving capability control
++		                 *  0: 6mA, 1: 8mA, 2: 10mA, 3: 12mA
++		                 */	
++				d_strength = (readl(PMU_FTPMU010_VA_BASE + 0x40) & 0x0f0) >> 4;
++		    if (strength_level[d_strength_retry] != d_strength) 
++		    {
++		    	d_strength = readl(PMU_FTPMU010_VA_BASE + 0x40);
++		      d_strength &= ~(0x3 << 4);
++		      d_strength |= (strength_level[d_strength_retry] << 4);
++		      writel(d_strength, PMU_FTPMU010_VA_BASE + 0x40);				
++	     	}
++			#ifdef CONFIG_MMC_DEBUG
++				 pr_info("SCU 0x40 : 0x%08x at %u Hz\n", readl(PMU_FTPMU010_VA_BASE + 0x40), host->f_init);
++			#endif					
++					if (!mmc_attach_sdio(host))
++						return 0;
++					if (!mmc_attach_sd(host))
++						return 0;
++					if (!mmc_attach_mmc(host))
++						return 0;
++			}		
++	#else 
++				if (!mmc_attach_sdio(host))
++					return 0;
++				if (!mmc_attach_sd(host))
++					return 0;
++				if (!mmc_attach_mmc(host))
++					return 0;	
++	#endif
+ 
+ 	mmc_power_off(host);
++	#if defined(CONFIG_MMC_FTSDC021_VEND_TUNE)
++		d_strength = readl(PMU_FTPMU010_VA_BASE + 0x40);
++		d_strength &= ~(0x3 << 4);
++		d_strength |= (strength_level[0] << 4);
++		writel(d_strength, PMU_FTPMU010_VA_BASE + 0x40);	
++	#endif
+ 	return -EIO;
+ }
+ 
+@@ -2136,7 +2183,11 @@ void mmc_rescan(struct work_struct *work)
+ 	struct mmc_host *host =
+ 		container_of(work, struct mmc_host, detect.work);
+ 	int i;
+-
++	
++	#if defined(CONFIG_MMC_FTSDC021_VEND_TUNE)
++	static uint ftsdc021_pulse_latch_tmp = 0xffffffff;
++	#endif
++	
+ 	if (host->rescan_disable)
+ 		return;
+ 
+@@ -2180,6 +2231,24 @@ void mmc_rescan(struct work_struct *work)
+ 			break;
+ 		if (freqs[i] <= host->f_min)
+ 			break;
++	
++	#if defined(CONFIG_MMC_FTSDC021_VEND_TUNE)																
++		if (host->actual_clock < 100000000) 
++		{
++			if(ftsdc021_pulse_latch_tmp == 0xffffffff)		 
++			{
++				ftsdc021_pulse_latch_tmp = ftsdc021_pulse_latch;
++			}
++    	ftsdc021_pulse_latch = ((~ftsdc021_pulse_latch) & 0x00000001);		
++    								
++			if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
++			{
++				ftsdc021_pulse_latch = ftsdc021_pulse_latch_tmp;
++				break;
++			}
++			ftsdc021_pulse_latch = ftsdc021_pulse_latch_tmp;
++		} 		
++	#endif	
+ 	}
+ 	mmc_release_host(host);
+ 
+diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
+index c272c686..a6fc2c84 100644
+--- a/drivers/mmc/core/sd.c
++++ b/drivers/mmc/core/sd.c
+@@ -365,7 +365,7 @@ out:
+  */
+ int mmc_sd_switch_hs(struct mmc_card *card)
+ {
+-	int err;
++	int err, mode = 1;
+ 	u8 *status;
+ 
+ 	if (card->scr.sda_vsn < SCR_SPEC_VER_1)
+@@ -389,8 +389,13 @@ int mmc_sd_switch_hs(struct mmc_card *card)
+ 		return -ENOMEM;
+ 	}
+ 
+-	err = mmc_sd_switch(card, 1, 0, 1, status);
+-	if (err)
++retry_cmd6:
++
++	err = mmc_sd_switch(card, 1, 0, mode, status);
++	if (err && mode > 0) {
++        mode --;
++        goto retry_cmd6;
++    } else if (err)
+ 		goto out;
+ 
+ 	if ((status[16] & 0xF) != 1) {
+@@ -758,7 +763,9 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
+ 	    MMC_CAP_SET_XPC_180))
+ 		ocr |= SD_OCR_XPC;
+ 
++#if !defined(CONFIG_ARCH_GM)
+ try_again:
++#endif
+ 	err = mmc_send_app_op_cond(host, ocr, rocr);
+ 	if (err)
+ 		return err;
+@@ -767,6 +774,7 @@ try_again:
+ 	 * In case CCS and S18A in the response is set, start Signal Voltage
+ 	 * Switch procedure. SPI mode doesn't support CMD11.
+ 	 */
++#if !defined(CONFIG_ARCH_GM)
+ 	if (!mmc_host_is_spi(host) && rocr &&
+ 	   ((*rocr & 0x41000000) == 0x41000000)) {
+ 		err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
+@@ -775,6 +783,7 @@ try_again:
+ 			goto try_again;
+ 		}
+ 	}
++#endif
+ 
+ 	if (mmc_host_is_spi(host))
+ 		err = mmc_send_cid(host, cid);
+@@ -1242,4 +1251,3 @@ err:
+ 
+ 	return err;
+ }
+-
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 00fcbed1..bc9620d3 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -229,6 +229,40 @@ config MMC_SDHCI_S3C_DMA
+ 
+ 	  YMMV.
+ 
++config MMC_FTSDC021
++	tristate "FTSDC021 Secure Digital Host Controller Interface support"
++	depends on HAS_DMA && MMC_SDHCI && MMC_SDHCI_PLTFM && (ARCH_GM || ARCH_GM_DUO || ARCH_GM_SMP || ARCH_FARADAY)
++	help
++	  This selects the faraday-tech ftsdc021 controller.
++
++	  If you have a faraday-tech ftsdc021 SD Host Controller, say Y or M here. You
++	  also need to enable an appropriate bus interface.
++
++	  If unsure, say N.
++
++config SDC0_IP
++	bool "FT SDC sdc0 enable"
++	default y
++	depends on MMC_FTSDC021 && PLATFORM_GM8136
++	help
++	  If you say yes to this open, it will create the mmc0 sdc host.
++
++config SDC1_IP
++	bool "FT SDC sdc1 enable"
++	default n
++	depends on MMC_FTSDC021 && PLATFORM_GM8136
++	help
++	  If you say yes to this open, it will create the mmc1 sdc host (if sdc0 is enabled).
++
++config MMC_FTSDC021_VEND_TUNE
++	bool "FTSDC021 Vendor tune enable"
++	depends on MMC_FTSDC021
++	default y
++	help
++	  This flag supports Vendor tune for ftsdc021.
++	  If you say yes to enable tune.
++	  If unsure, say N.
++	  
+ config MMC_OMAP
+ 	tristate "TI OMAP Multimedia Card Interface support"
+ 	depends on ARCH_OMAP
+diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
+index 745f8fce..77cdea88 100644
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -43,6 +43,7 @@ obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
+ obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
+ obj-$(CONFIG_MMC_VUB300)	+= vub300.o
+ obj-$(CONFIG_MMC_USHC)		+= ushc.o
++obj-$(CONFIG_MMC_FTSDC021)	+= sdhci-ftsdc021.o
+ 
+ obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o
+ obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o
+diff --git a/drivers/mmc/host/sdhci-ftsdc021.c b/drivers/mmc/host/sdhci-ftsdc021.c
+new file mode 100644
+index 00000000..78d5b676
+--- /dev/null
++++ b/drivers/mmc/host/sdhci-ftsdc021.c
+@@ -0,0 +1,235 @@
++#include <linux/module.h>
++#include <linux/mmc/host.h>
++
++#include <mach/ftpmu010.h>
++#include "sdhci-pltfm.h"
++
++#if defined(CONFIG_PLATFORM_GM8210)
++#include <mach/fmem.h>
++#endif
++
++#define DRIVER_NAME "ftsdc021"
++
++/* Transfer Mode
++ * Note: Only one of them can be chosen */
++#define Transfer_Mode_ADMA 1
++//#define Transfer_Mode_SDMA 1
++//#define Transfer_Mode_PIO 1
++
++//ftsdc021_pulse_latch: 00h ~ 3Fh -> Latch value at 00h ~ 3Fh sdclk1x rising after the SCLK edge
++uint ftsdc021_pulse_latch = 0;
++module_param(ftsdc021_pulse_latch, uint, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(ftsdc021_pulse_latch, "Sdhc Vendor defined Register0(offset = 0x100)[13:8]: value of Pulse Latch Offset");
++
++static int ftsdc021_enable_dma(struct sdhci_host *host)
++{
++	return 0;
++}
++
++static unsigned int ftsdc021_get_timeout_clk(struct sdhci_host *host)
++{
++	return 33;
++}
++
++static unsigned int ftsdc021_get_max_clk(struct sdhci_host *host)
++{
++	/* Controller does not specify the base clock frequency.
++	 * Current design base clock  = SD ODC frequency x 2.
++	 */
++#if defined(CONFIG_PLATFORM_GM8210)
++	if (ftpmu010_read_reg(0x28) & BIT(26))
++		return ftpmu010_get_attr(ATTR_TYPE_AXI) / 4;
++	return ftpmu010_get_attr(ATTR_TYPE_AHB) / 2;
++#endif
++#if defined(CONFIG_PLATFORM_GM8287)
++    /* [28, 26] : sdcclk_sel(sdcclk_2x) 0x-hclk/2, 10-pll1out3/4, 11-pll1out4/4 */
++	if (ftpmu010_read_reg(0x28) & BIT(28)) {
++        if (ftpmu010_read_reg(0x28) & BIT(26))
++            return (ftpmu010_get_attr(ATTR_TYPE_PLL1) * 10 / 25 / 4); // pll1out3 = pll1 / 2.5
++        else
++            return (ftpmu010_get_attr(ATTR_TYPE_PLL1) / 3 / 4); // pll1out4 = pll1 / 3
++    } else {
++		return ftpmu010_get_attr(ATTR_TYPE_AHB) / 2;
++    }
++#endif
++#if defined(CONFIG_PLATFORM_GM8139)
++    unsigned int clk;
++	if (ftpmu010_read_reg(0x28) & BIT(11))
++        clk = ftpmu010_get_attr(ATTR_TYPE_PLL2) / 4;
++    else
++        clk = ftpmu010_get_attr(ATTR_TYPE_PLL1) / 2;
++    clk /= ((ftpmu010_read_reg(0x70) & 0x7) + 1);
++    return clk / 2;
++#endif
++#if defined(CONFIG_PLATFORM_GM8136)
++    unsigned int clk;
++    if (ftpmu010_read_reg(0x28) & BIT(7))
++        clk = ftpmu010_get_attr(ATTR_TYPE_PLL1) / 2;
++    else
++        clk = ftpmu010_get_attr(ATTR_TYPE_PLL2);
++    clk /= ((ftpmu010_read_reg(0x70) & 0x7) + 1);
++    return clk / 2;
++#endif
++}
++static struct sdhci_ops ftsdc021_ops = {
++	.enable_dma = ftsdc021_enable_dma,
++	.get_max_clock	= ftsdc021_get_max_clk,
++	.get_timeout_clock = ftsdc021_get_timeout_clk,
++};
++
++/* PMU register data */
++static int sdc_fd = -1;
++int sdhci_get_fd(void) {return sdc_fd;}
++EXPORT_SYMBOL(sdhci_get_fd);
++static pmuReg_t regSDCArray[] = {
++	/* reg_off, bit_masks, lock_bits, init_val, init_mask */
++#if defined(CONFIG_PLATFORM_GM8210)
++	{0x28, BIT(26), BIT(26), BIT(26), BIT(26)}, /* sdcclk_sel */
++	{0x44, 0x1E00000, 0x1E00000, 0, 0x1E00000}, /* BIT21~BIT24 */
++	{0xB4, BIT(19), BIT(19), 0, BIT(19)},       /* FTSDC021 clk */
++#endif
++#if defined(CONFIG_PLATFORM_GM8287)
++	{0x28, BIT(28), BIT(28), 0, BIT(28)},       /* sdcclk_sel */
++	{0x44, 0x1E00000, 0x1E00000, 0, 0x1E00000}, /* BIT21~BIT24 */
++	{0xB4, BIT(19), BIT(19), 0, BIT(19)},       /* FTSDC021 clk */
++#endif
++#if defined(CONFIG_PLATFORM_GM8139)
++	{0x58, 0xfc03fc, 0, 0x540154, 0xfc03fc},    /* sd pinmux setting */
++	{0x28, 0x880, 0x0, 0x880, 0x880},           /* sdcclk_sel(BIT11), BIT7 for nand pinmux */
++	{0x70, 0x7, 0x7, 0x0, 0x7},                 /* sdcclk divided value */
++	{0x40, 0x70, 0x70, 0x20, 0x70},             /* sdc Driving Capacity and Slew Rate, 10mA */
++	{0xB4, BIT(14), BIT(14), 0, BIT(14)},       /* FTSDC021 clk */
++#endif
++#if defined(CONFIG_PLATFORM_GM8136)
++	{0x28, 0x80, 0x0, 0, 0x80},                 /* sdcclk_sel(BIT7) */
++	{0x70, 0x7, 0x7, 0x2, 0x7},                 /* sdcclk divided value */
++	{0x40, 0x70, 0x70, 0x20, 0x70},             /* sdc Driving Capacity and Slew Rate, 10mA */
++    #if defined(CONFIG_SDC0_IP)
++        {0x58, 0xfc03fc, 0, 0x540154, 0xfc03fc},    /* sd pinmux setting */
++	{0xB4, BIT(14), BIT(14), 0, BIT(14)},       /* FTSDC021 clk */
++    #endif
++    #if defined(CONFIG_SDC1_IP)
++        /* Shared pins with CAP0_D5 ~ CAP0_D11 */ 
++        {0x50, 0xf0000000, 0, 0xf0000000, 0xf0000000},    /* sd#1 pinmux setting */
++        {0x54, 0xfcf, 0, 0xfcf, 0xfcf},                   /* sd#1 pinmux setting */
++        /* Shared pins with GPIO_1[22:19], GPIO_1[31:29] */
++        //{0x58, 0x3f000, 0, 0x2a000, 0x3f000},             /* sd#1 pinmux setting */
++        //{0x5C, 0xff000000, 0, 0x55000000, 0xff000000},    /* sd#1 pinmux setting */
++        {0xB4, BIT(22), BIT(22), 0, BIT(22)},             /* FTSDC021#1 clk */
++    #endif
++#endif
++
++};
++static pmuRegInfo_t sdc_clk_info = {
++	"sdc_clk",
++	ARRAY_SIZE(regSDCArray),
++	ATTR_TYPE_NONE,             /* no clock source */
++	regSDCArray
++};
++static void ftsdc021_hw_init(void)
++{
++	sdc_fd = ftpmu010_register_reg(&sdc_clk_info);
++	if (unlikely(sdc_fd < 0)) {
++		panic("SDC registers to PMU fail!");
++	}
++}
++
++static void ftsdc021_hw_remove(void)
++{
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id != FMEM_CPU_FA726 || pci_id != FMEM_PCI_HOST)
++        return;
++#endif
++#if defined(CONFIG_PLATFORM_GM8287)
++	/* disable ftsdc021 clk	*/
++	if (ftpmu010_write_reg(sdc_fd, 0xB4, BIT(19), BIT(19)) < 0)
++		printk(KERN_ERR "Write PMU register 0xB4 Failed\n");
++#endif
++#if defined(CONFIG_PLATFORM_GM8139)
++	/* disable ftsdc021 clk	*/
++	if (ftpmu010_write_reg(sdc_fd, 0xB4, BIT(14), BIT(14)) < 0)
++		printk(KERN_ERR "Write PMU register 0xB4 Failed\n");
++#endif
++#if defined(CONFIG_PLATFORM_GM8136)
++    #if defined(CONFIG_SDC0_IP)
++	/* disable ftsdc021 clk	*/
++	if (ftpmu010_write_reg(sdc_fd, 0xB4, BIT(14), BIT(14)) < 0)
++		printk(KERN_ERR "Write PMU register 0xB4 Failed\n");
++    #endif
++    #if defined(CONFIG_SDC1_IP)
++	/* disable ftsdc021#1 clk	*/
++	if (ftpmu010_write_reg(sdc_fd, 0xB4, BIT(22), BIT(22)) < 0)
++		printk(KERN_ERR "Write PMU register 0xB4 Failed\n");
++    #endif
++#endif
++	/* unregister sdc from pmu core */
++	if (ftpmu010_deregister_reg(sdc_fd) < 0)
++		printk(KERN_ERR "Unregister SDC from PMU Failed\n");
++}
++
++static struct sdhci_pltfm_data ftsdc021_pdata = {
++	.ops = &ftsdc021_ops,
++	.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
++		  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
++#if defined(Transfer_Mode_PIO)
++		  | SDHCI_QUIRK_BROKEN_DMA |
++		  SDHCI_QUIRK_BROKEN_ADMA,
++#elif defined(Transfer_Mode_SDMA)
++		  | SDHCI_QUIRK_FORCE_DMA |
++		  SDHCI_QUIRK_BROKEN_ADMA,
++#elif defined(Transfer_Mode_ADMA)
++		 ,
++#endif
++};
++static int __devinit ftsdc021_probe(struct platform_device *pdev)
++{
++	ftsdc021_hw_init();
++	return sdhci_pltfm_register(pdev, &ftsdc021_pdata);
++}
++
++static int __devexit ftsdc021_remove(struct platform_device *pdev)
++{
++	ftsdc021_hw_remove();
++	return sdhci_pltfm_unregister(pdev);
++}
++
++static struct platform_driver ftsdc021_driver = {
++	.probe = ftsdc021_probe,
++	.remove = ftsdc021_remove,
++	.driver = {
++		.owner = THIS_MODULE,
++		.name = DRIVER_NAME,
++	},
++};
++
++static int __init ftsdc021_driver_init(void)
++{
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id != FMEM_CPU_FA726 || pci_id != FMEM_PCI_HOST)
++        return 0;
++#endif
++    return platform_driver_register(&ftsdc021_driver);
++}
++module_init(ftsdc021_driver_init);
++static void __exit ftsdc021_driver_exit(void)
++{
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id != FMEM_CPU_FA726 || pci_id != FMEM_PCI_HOST)
++        return;
++#endif
++    platform_driver_unregister(&ftsdc021_driver);
++}
++module_exit(ftsdc021_driver_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("MikeYeh <mikeyeh@faraday-tech.com>");
++MODULE_DESCRIPTION("FTSDC021 driver");
+diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
+index 8d667068..a5a8fd5e 100644
+--- a/drivers/mmc/host/sdhci.c
++++ b/drivers/mmc/host/sdhci.c
+@@ -27,9 +27,20 @@
+ 
+ #include <linux/mmc/mmc.h>
+ #include <linux/mmc/host.h>
++#include <linux/mmc/card.h>
++
++#include <asm/setup.h>
++#include <linux/kthread.h>
+ 
+ #include "sdhci.h"
+ 
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <mach/platform/board.h>
++#include <mach/platform/platform_io.h>
++#endif
++
+ #define DRIVER_NAME "sdhci"
+ 
+ #define DBG(f, x...) \
+@@ -42,6 +53,28 @@
+ 
+ #define MAX_TUNING_LOOP 40
+ 
++#define SDHCI_FTSDC021_VENDOR0		0x100
++#define  SDHCI_PULSE_LATCH_OFF_MASK	0x3F00
++#define  SDHCI_PULSE_LATCH_OFF_SHIFT	8
++#define  SDHCI_PULSE_LATCH_EN		0x1
++
++#define SDHCI_FTSDC021_VENDOR3		0x10C
++#define  SDHCI_AUTO_TUNING_TIMES_MASK	0x1F000000
++#define  SDHCI_AUTO_TUNING_TIMES_SHIFT  24
++
++#define SDHCI_FTSDC021_VENDOR4		0x110
++
++#if defined(CONFIG_PLATFORM_GM8139)
++#define NAND_TIMEOUT 5
++static struct timer_list nand_timer;
++static unsigned int nand_flag = 0;
++#endif
++
++extern uint ftsdc021_pulse_latch;
++
++int sd_cd_inv_enable = 0;
++static char *command_line = NULL;
++
+ static unsigned int debug_quirks = 0;
+ static unsigned int debug_quirks2;
+ 
+@@ -990,6 +1023,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+ 
+ 	host->cmd = cmd;
+ 
++	host->busy_handle = 0;
++
+ 	sdhci_prepare_data(host, cmd);
+ 
+ 	sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
+@@ -1170,6 +1205,24 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+ 	clk |= SDHCI_CLOCK_CARD_EN;
+ 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+ 
++{
++	int vendor0;
++
++	vendor0 = sdhci_readl(host, SDHCI_FTSDC021_VENDOR0);
++	if (host->mmc->actual_clock < 100000000) {
++		/* Enable pulse latch */
++		vendor0 |= SDHCI_PULSE_LATCH_EN;
++
++		if (real_div > 1)
++			//vendor0 |= (1 << SDHCI_PULSE_LATCH_OFF_SHIFT);
++			vendor0 &= ~(0x3F << SDHCI_PULSE_LATCH_OFF_SHIFT);
++			vendor0 |= (ftsdc021_pulse_latch << SDHCI_PULSE_LATCH_OFF_SHIFT);
++			
++	} else
++		vendor0 &= ~(SDHCI_PULSE_LATCH_OFF_MASK | SDHCI_PULSE_LATCH_EN);
++
++	sdhci_writel(host, vendor0, SDHCI_FTSDC021_VENDOR0);
++}
+ out:
+ 	host->clock = clock;
+ }
+@@ -1240,6 +1293,10 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
+  *                                                                           *
+ \*****************************************************************************/
+ 
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++#include <mach/ftpmu010.h>
++extern int sdhci_get_fd(void);
++#endif
+ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+ {
+ 	struct sdhci_host *host;
+@@ -1254,6 +1311,24 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+ 
+ 	WARN_ON(host->mrq != NULL);
+ 
++#if defined(CONFIG_PLATFORM_GM8139)
++    /* sdhc pinmux with nand */
++    if (in_interrupt() || in_atomic()) {
++        u32 count = 0;
++        while (ftpmu010_request_pins(sdhci_get_fd(), 0x28, BIT(7), 0) != 0 && count < 10) {
++            count ++;
++            mdelay(100);
++        }
++    } else {
++        if (ftpmu010_request_pins(sdhci_get_fd(), 0x28, BIT(7), 1) != 0)
++            panic("%s:%d, request pin failed\n", __func__, __LINE__);
++    }
++
++    /* set pinmux to SDHC */
++    if (ftpmu010_write_reg(sdhci_get_fd(), 0x58, 0x154, 0x3fc) < 0) {
++        panic("%s:%d, Write PMU reg failed\n", __func__, __LINE__);
++    }
++#endif
+ #ifndef SDHCI_USE_LEDS_CLASS
+ 	sdhci_activate_led(host);
+ #endif
+@@ -1292,9 +1367,19 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+ 		 */
+ 		if ((host->flags & SDHCI_NEEDS_RETUNING) &&
+ 		    !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
++#if 0
++			/* eMMC uses cmd21 while sd and sdio use cmd19 */
++			u32 tuning_opcode = mmc->card->type == MMC_TYPE_MMC ?
++				MMC_SEND_TUNING_BLOCK_HS200 :
++				MMC_SEND_TUNING_BLOCK;
+ 			spin_unlock_irqrestore(&host->lock, flags);
+-			sdhci_execute_tuning(mmc, mrq->cmd->opcode);
++			sdhci_execute_tuning(mmc, tuning_opcode);
+ 			spin_lock_irqsave(&host->lock, flags);
++#else
++            spin_unlock_irqrestore(&host->lock, flags);
++            sdhci_execute_tuning(mmc, mrq->cmd->opcode);
++            spin_lock_irqsave(&host->lock, flags);
++#endif
+ 
+ 			/* Restore original mmc_request structure */
+ 			host->mrq = mrq;
+@@ -1633,7 +1718,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
+ 			sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+ 
+ 			/* Wait for 5ms */
+-			usleep_range(5000, 5500);
++			usleep_range(12000, 15000);
+ 
+ 			ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ 			if (ctrl & SDHCI_CTRL_VDD_180) {
+@@ -1700,6 +1785,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ 	unsigned long timeout;
+ 	int err = 0;
+ 	bool requires_tuning_nonuhs = false;
++	u32 ven_def;
+ 
+ 	host = mmc_priv(mmc);
+ 
+@@ -1731,6 +1817,21 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ 		return 0;
+ 	}
+ 
++	/* Mikeyeh@110817:
++	 * According to the multiphase DLL feature in FPGA, we
++	 * filled the field of Repeating times of Auto-tuning
++	 * Opertaion with 15.
++	 */
++	ven_def = sdhci_readl(host, SDHCI_FTSDC021_VENDOR3);
++	ven_def &= ~SDHCI_AUTO_TUNING_TIMES_MASK;
++	ven_def |= (15 << SDHCI_AUTO_TUNING_TIMES_SHIFT);
++	sdhci_writel(host, ven_def, SDHCI_FTSDC021_VENDOR3);
++
++	ven_def = sdhci_readl(host, SDHCI_FTSDC021_VENDOR0);
++	ven_def &= ~(SDHCI_PULSE_LATCH_OFF_MASK |
++		     SDHCI_PULSE_LATCH_EN);
++	sdhci_writel(host, ven_def, SDHCI_FTSDC021_VENDOR0);
++
+ 	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+ 
+ 	/*
+@@ -1843,6 +1944,16 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+ 				" failed, falling back to fixed sampling"
+ 				" clock\n");
+ 			err = -EIO;
++		} else {
++			u32 delay;
++
++			delay = (sdhci_readl(host, SDHCI_FTSDC021_VENDOR3) >> 16) & 0x1F;
++			ven_def = sdhci_readl(host, SDHCI_FTSDC021_VENDOR4);
++			printk("Tuning complete(0x%x), delay %d", ven_def, delay);
++
++			if (!(ven_def & (1 << delay)))
++				printk("Tuning delay result not correct\n");
++
+ 		}
+ 	}
+ 
+@@ -1885,7 +1996,7 @@ out:
+ 
+ 	return err;
+ }
+-
++#if 0
+ static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable)
+ {
+ 	u16 ctrl;
+@@ -1924,7 +2035,7 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
+ 	sdhci_do_enable_preset_value(host, enable);
+ 	sdhci_runtime_pm_put(host);
+ }
+-
++#endif
+ static const struct mmc_host_ops sdhci_ops = {
+ 	.request	= sdhci_request,
+ 	.set_ios	= sdhci_set_ios,
+@@ -1933,7 +2044,9 @@ static const struct mmc_host_ops sdhci_ops = {
+ 	.enable_sdio_irq = sdhci_enable_sdio_irq,
+ 	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch,
+ 	.execute_tuning			= sdhci_execute_tuning,
++#if 0
+ 	.enable_preset_value		= sdhci_enable_preset_value,
++#endif
+ };
+ 
+ /*****************************************************************************\
+@@ -2014,6 +2127,9 @@ static void sdhci_tasklet_finish(unsigned long param)
+ 			sdhci_set_clock(host, clock);
+ 		}
+ 
++#if defined(CONFIG_PLATFORM_GM8139)
++        ftpmu010_release_pins(sdhci_get_fd(), 0x28, BIT(7));
++#endif
+ 		/* Spec says we should do both at the same time, but Ricoh
+ 		   controllers do not like that. */
+ 		sdhci_reset(host, SDHCI_RESET_CMD);
+@@ -2033,6 +2149,18 @@ static void sdhci_tasklet_finish(unsigned long param)
+ 
+ 	mmc_request_done(host->mmc, mrq);
+ 	sdhci_runtime_pm_put(host);
++
++#if defined(CONFIG_PLATFORM_GM8139)
++    nand_flag = 1;
++    mod_timer(&nand_timer, jiffies + NAND_TIMEOUT * HZ);
++
++    /* This is used to check DAT state because of pinmux with nand flash */
++    while ((sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_DATA_INHIBIT) && nand_flag) {/* nop */}
++
++    del_timer(&nand_timer);
++
++    ftpmu010_release_pins(sdhci_get_fd(), 0x28, BIT(7));
++#endif
+ }
+ 
+ static void sdhci_timeout_timer(unsigned long data)
+@@ -2080,6 +2208,15 @@ static void sdhci_tuning_timer(unsigned long data)
+ 	spin_unlock_irqrestore(&host->lock, flags);
+ }
+ 
++#if defined(CONFIG_PLATFORM_GM8139)
++static void sdhci_nand_timer(unsigned long data)
++{
++	unsigned int *flag = (unsigned int *)data;
++	*flag = 0;
++	printk(KERN_ERR "Wait status reg(0x24) Command Inhibit(BIT1) = 0 for %d seconds timeout\n", NAND_TIMEOUT);
++}
++#endif
++
+ /*****************************************************************************\
+  *                                                                           *
+  * Interrupt handling                                                        *
+@@ -2124,8 +2261,12 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
+ 		if (host->cmd->data)
+ 			DBG("Cannot wait for busy signal when also "
+ 				"doing a data transfer");
+-		else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ))
+-			return;
++		else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)
++                && !host->busy_handle) {
++            /* Mark that command complete before busy is ended */
++            host->busy_handle = 1;
++            return;
++        }
+ 
+ 		/* The controller does not support the end-of-busy IRQ,
+ 		 * fall through and take the SDHCI_INT_RESPONSE */
+@@ -2188,7 +2329,15 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
+ 		 */
+ 		if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+ 			if (intmask & SDHCI_INT_DATA_END) {
+-				sdhci_finish_command(host);
++				/*
++				 * Some cards handle busy-end interrupt
++				 * before the command completed, so make
++				 * sure we do things in the proper order.
++				 */
++				if (host->busy_handle)
++                    sdhci_finish_command(host);
++				else
++					host->busy_handle = 1;
+ 				return;
+ 			}
+ 		}
+@@ -2561,6 +2710,41 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
+ 
+ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
+ 
++static int card_detect_handler(void *data)
++{
++    struct sdhci_host *host = (struct sdhci_host *)data;
++
++    do {
++        u32 ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL);
++        u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE);
++
++        if ((present & SDHCI_CARD_DETECT) == 0) { /* SDCD#=1 */
++            ctrl |= (SDHCI_CTRL_CD_TL | SDHCI_CTRL_CD_SS);
++            sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL);
++        } else {
++            if ((ctrl & SDHCI_CTRL_CD_TL) > 0) {
++                ctrl &= ~SDHCI_CTRL_CD_TL;
++                sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL);
++            }
++
++            /* After setting SDHCI_CTRL_CD_TL,
++             * SDHCI_HOST_CONTROL is been cleared.
++             * We need to turn on SDHCI_CTRL_CD_SS again.
++             */
++            sdhci_disable_card_detection(host);
++            ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL);
++            ctrl |= SDHCI_CTRL_CD_SS;
++            sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL);
++            sdhci_enable_card_detection(host);
++        }
++
++        msleep(200);
++    } while (1);
++
++    return 0;
++}
++static struct task_struct *card_detect_thread = NULL;
++
+ int sdhci_add_host(struct sdhci_host *host)
+ {
+ 	struct mmc_host *mmc;
+@@ -2568,11 +2752,33 @@ int sdhci_add_host(struct sdhci_host *host)
+ 	u32 max_current_caps;
+ 	unsigned int ocr_avail;
+ 	int ret;
++	#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++	int clk_tmp;
++	#endif
+ 
+ 	WARN_ON(host == NULL);
+ 	if (host == NULL)
+ 		return -EINVAL;
+-
++    if(sd_cd_inv_enable == 1) {
++        printk("SD card detect pin polarity inversed!\n");
++        if (!card_detect_thread) {
++            u32 ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL);
++
++            /* don't use SDCD# for card detect */
++            sdhci_disable_card_detection(host);
++            ctrl = sdhci_readl(host, SDHCI_HOST_CONTROL);
++            ctrl |= SDHCI_CTRL_CD_SS;
++            sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL);
++            sdhci_enable_card_detection(host);
++
++            card_detect_thread = kthread_run(card_detect_handler, (void *)host, "card_detect_thread");
++
++            if (IS_ERR(card_detect_thread)) {
++                panic("%s: unable to create kernel thread: %ld\n",
++                        __func__, PTR_ERR(card_detect_thread));
++            }
++        }
++    }
+ 	mmc = host->mmc;
+ 
+ 	if (debug_quirks)
+@@ -2959,6 +3165,9 @@ int sdhci_add_host(struct sdhci_host *host)
+ 		sdhci_tasklet_finish, (unsigned long)host);
+ 
+ 	setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
++#if defined(CONFIG_PLATFORM_GM8139)
++    setup_timer(&nand_timer, sdhci_nand_timer, (unsigned long)&nand_flag);
++#endif
+ 
+ 	if (host->version >= SDHCI_SPEC_300) {
+ 		init_waitqueue_head(&host->buf_ready_int);
+@@ -3007,7 +3216,19 @@ int sdhci_add_host(struct sdhci_host *host)
+ 		mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
+ 		(host->flags & SDHCI_USE_ADMA) ? "ADMA" :
+ 		(host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
+-
++		
++  #if defined(CONFIG_PLATFORM_GM8136)
++		clk_tmp = readl(PMU_FTPMU010_VA_BASE + 0x70);
++		clk_tmp = clk_tmp + 2;
++		writel(clk_tmp, PMU_FTPMU010_VA_BASE + 0x70);	
++	#endif
++	
++	#if defined(CONFIG_PLATFORM_GM8139)
++		clk_tmp = readl(PMU_FTPMU010_VA_BASE + 0x70);
++		clk_tmp = clk_tmp + 1;
++		writel(clk_tmp, PMU_FTPMU010_VA_BASE + 0x70);	
++	#endif
++	
+ 	sdhci_enable_card_detection(host);
+ 
+ 	return 0;
+@@ -3030,6 +3251,11 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
+ {
+ 	unsigned long flags;
+ 
++    if(sd_cd_inv_enable == 1) {
++        if (!IS_ERR(card_detect_thread))
++            kthread_stop(card_detect_thread);
++    }
++
+ 	if (dead) {
+ 		spin_lock_irqsave(&host->lock, flags);
+ 
+@@ -3090,9 +3316,16 @@ EXPORT_SYMBOL_GPL(sdhci_free_host);
+  * Driver init/exit                                                          *
+  *                                                                           *
+ \*****************************************************************************/
+-
+ static int __init sdhci_drv_init(void)
+ {
++    char *ptr = NULL;
++
++    command_line = kmalloc(COMMAND_LINE_SIZE, GFP_KERNEL);
++    memcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
++    ptr = strstr(command_line, "sdcd_inv=");
++    if(ptr)
++        sd_cd_inv_enable = *(ptr+9)=='1'?1:0;
++
+ 	pr_info(DRIVER_NAME
+ 		": Secure Digital Host Controller Interface driver\n");
+ 	pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
+diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
+index ad265b96..2bbd651c 100644
+--- a/drivers/mmc/host/sdhci.h
++++ b/drivers/mmc/host/sdhci.h
+@@ -69,6 +69,7 @@
+ #define  SDHCI_SPACE_AVAILABLE	0x00000400
+ #define  SDHCI_DATA_AVAILABLE	0x00000800
+ #define  SDHCI_CARD_PRESENT	0x00010000
++#define  SDHCI_CARD_DETECT	0x00040000
+ #define  SDHCI_WRITE_PROTECT	0x00080000
+ #define  SDHCI_DATA_LVL_MASK	0x00F00000
+ #define   SDHCI_DATA_LVL_SHIFT	20
+@@ -83,6 +84,8 @@
+ #define   SDHCI_CTRL_ADMA32	0x10
+ #define   SDHCI_CTRL_ADMA64	0x18
+ #define   SDHCI_CTRL_8BITBUS	0x20
++#define  SDHCI_CTRL_CD_TL	0x40
++#define  SDHCI_CTRL_CD_SS	0x80
+ 
+ #define SDHCI_POWER_CONTROL	0x29
+ #define  SDHCI_POWER_ON		0x01
+diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
+index 37b05c3f..81d7c0f8 100644
+--- a/drivers/mtd/devices/Kconfig
++++ b/drivers/mtd/devices/Kconfig
+@@ -102,6 +102,19 @@ config M25PXX_USE_FAST_READ
+ 	help
+ 	  This option enables FAST_READ access supported by ST M25Pxx.
+ 
++config MTD_SPI_FLASH
++    	bool "Support most SPI Flash chips (Winbond...)"
++    	depends on SPI_MASTER
++    	help
++	  The SPI Flash driver which Faraday supports. 
++
++config MTD_ERASE_64K
++	bool "ERASE 64K"
++	default y
++	depends on MTD_SPI_FLASH
++	help
++	  Erase Sector one time 64KB. If user want to use this command, say Y; otherwise say N.
++
+ config MTD_SST25L
+ 	tristate "Support SST25L (non JEDEC) SPI Flash chips"
+ 	depends on SPI_MASTER
+diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
+index 56c7cd46..30826eb8 100644
+--- a/drivers/mtd/devices/Makefile
++++ b/drivers/mtd/devices/Makefile
+@@ -18,5 +18,9 @@ obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o
+ obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
+ obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
+ obj-$(CONFIG_MTD_SST25L)	+= sst25l.o
+-
++ifeq ($(CONFIG_PLATFORM_GM8220),y)
++obj-$(CONFIG_MTD_SPI_FLASH) 	+= spi_flash_v2.o
++else
++obj-$(CONFIG_MTD_SPI_FLASH)     += spi_flash.o
++endif
+ CFLAGS_docg3.o			+= -I$(src)
+\ No newline at end of file
+diff --git a/drivers/mtd/devices/spi_flash.c b/drivers/mtd/devices/spi_flash.c
+new file mode 100644
+index 00000000..a388d5a3
+--- /dev/null
++++ b/drivers/mtd/devices/spi_flash.c
+@@ -0,0 +1,1299 @@
++/*
++ * MTD SPI driver for ST M25Pxx (and similar) serial flash chips
++ *
++ * 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.
++ *
++ *
++ * Copyright (c) 2011 BingJiun Luo <bjluo@faraday-tech.com>
++ * - Modify for FTSPI020 Faraday SPI flash controller.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/mutex.h>
++#include <linux/delay.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <mach/platform/pmu.h>
++
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#ifdef MODULE
++#include "ftspi020.h"
++#else
++#include <linux/spi/ftspi020.h>
++#endif
++
++#define FLASH_PAGESIZE		256
++
++/* Flash opcodes. */
++#define	OPCODE_WREN		0x06    /* Write enable */
++#define	OPCODE_RDSR		0x05    /* Read status register */
++#define	OPCODE_RDSR2	0x35
++#define	OPCODE_WRSR		0x01    /* Write status register 1 byte */
++#define	OPCODE_EN4B		0xB7
++#define	OPCODE_EX4B		0xE9
++#define	OPCODE_NORM_READ	0x03    /* Read data bytes (low frequency) */
++#define	OPCODE_FAST_READ	0x0b    /* Read data bytes (high frequency) */
++#define OPCODE_FAST_READ_DUAL	    0x3B
++#define	OPCODE_QUAD_READ	0xEB
++#define OPCODE_WINBOND_PP 0x32
++#define	OPCODE_QUAD_PP		0x38
++#define	OPCODE_PP		0x02    /* Page program (up to 256 bytes) */
++#define	OPCODE_SE		0x20    /* Erase Sector 4KiB */
++#define	OPCODE_BE_32K		0x52    /* Erase 32KiB block */
++#define	OPCODE_BE_64K		0xd8    /* Erase 64KiB block */
++#define	OPCODE_CHIP_ERASE	0xc7    /* Erase whole flash chip */
++#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 spi_operate_serial_mode         0
++#define spi_operate_dual_mode           0x20
++#define spi_operate_quad_mode           0x40
++#define spi_operate_dualio_mode         0x60
++#define spi_operate_quadio_mode         0x80
++
++#define	CMD_SIZE		4
++/*
++#ifdef CONFIG_SPI_QUAD_MODE
++#define OPCODE_READ 	OPCODE_QUAD_READ
++#define READ_DUMMY_CYCLE	4
++#else
++#if 1                           //USE_FAST_READ
++#define OPCODE_READ 	OPCODE_FAST_READ
++#define READ_DUMMY_CYCLE	8
++#else
++#define OPCODE_READ 	OPCODE_NORM_READ
++#define READ_DUMMY_CYCLE	0
++#endif
++#endif
++*/
++#define READ_DUMMY_CYCLE	8
++
++unsigned char OPCODE_READ_COMMAND, OPCODE_WRITE_COMMAND, OPCODE_ERASE_COMMAND;
++  
++#define SPI_NAME	"SPI_FLASH"
++
++#define BLOCK_ALIGN(base, blk_shift) ((((base) + (0x1 << (blk_shift)) - 1) >> (blk_shift)) << (blk_shift))
++
++static struct mtd_partition ftspi020_partition_info[20];
++
++static struct flash_platform_data spi_flash_platform_data = {
++    .name = "wb_spi_flash",
++    .parts = ftspi020_partition_info,
++    .nr_parts = ARRAY_SIZE(ftspi020_partition_info)
++};
++
++#ifdef CONFIG_SECOND_SPI_FLASH
++static struct mtd_partition extra_partitions[] = {
++    {
++     .name = "Extra Code Section",
++     .offset = 0x000000,
++     .size = 0x800000           // 8MB
++     },
++    {
++     .name = "Extra User Section",      // free for use
++     .offset = 0x800000,
++     .size = 0x800000},
++};
++
++static struct flash_platform_data extra_spi_flash_platform_data = {
++    .name = "wb_spi_flash",
++    .parts = extra_partitions,
++    .nr_parts = ARRAY_SIZE(extra_partitions)
++};
++#endif //end of CONFIG_SECOND_SPI_FLASH
++static struct spi_board_info spi_devs_info[] __initdata = {
++    {
++     .modalias = SPI_NAME,
++     .platform_data = &spi_flash_platform_data,
++     .max_speed_hz = 45 * 1000 * 1000,  //40Mhz
++     .bus_num = 0,              //on bus 0
++     .chip_select = 0,          //first chip select//???
++     .mode = SPI_MODE_0,
++     },
++#ifdef CONFIG_SECOND_SPI_FLASH
++    {
++     .modalias = SPI_NAME,
++     .platform_data = &extra_spi_flash_platform_data,
++     .max_speed_hz = 45 * 1000 * 1000,  //40Mhz
++     .bus_num = 0,              //on bus 0
++     .chip_select = 1,          //first chip select
++     .mode = SPI_MODE_0,
++     }
++#endif
++};
++
++static const char *part_probes[] = { "cmdlinepart", NULL, };
++
++/****************************************************************************/
++
++struct common_spi_flash {
++    struct spi_device *spi;
++    struct mutex lock;
++    struct mtd_info mtd;
++    sys_header_t *sys_hdr;      /* system header */
++
++    u8 erase_opcode;
++    u8 mode_3_4;
++    u8 flash_type;
++};
++
++static inline struct common_spi_flash *mtd_to_common_spi_flash(struct mtd_info *mtd)
++{
++    return container_of(mtd, struct common_spi_flash, 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 common_spi_flash *flash, u8 ins_cmd)
++{
++    struct spi_transfer t[2];
++    struct spi_message m;
++    u8 val;
++    struct ftspi020_cmd cmd[2];
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(t, 0, (sizeof t));
++
++    t[0].tx_buf = &cmd[0];
++    spi_message_add_tail(&t[0], &m);
++
++    memset(&cmd[0], 0, sizeof(struct ftspi020_cmd));
++    cmd[0].ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd[0].write_en = FTSPI020_CMD3_READ;
++    cmd[0].read_status_en = FTSPI020_CMD3_RD_STS_EN;
++    cmd[0].read_status = FTSPI020_CMD3_STS_SW_READ;
++    cmd[0].ins_code = FTSPI020_CMD3_INSTR_CODE(ins_cmd);
++    cmd[0].flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    t[1].tx_buf = &cmd[1];
++    spi_message_add_tail(&t[1], &m);
++
++    memset(&cmd[1], 0, sizeof(struct ftspi020_cmd));
++    cmd[1].rx_buf = &val;
++    cmd[1].data_cnt = 1;
++    cmd[1].read_status_en = FTSPI020_CMD3_RD_STS_EN;
++    cmd[1].read_status = FTSPI020_CMD3_STS_SW_READ;;
++    cmd[1].flags = FTSPI020_XFER_DATA_STATE;
++
++    spi_sync(flash->spi, &m);
++
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d reading SR\n", (int)m.actual_length);
++        return m.status;
++    }
++
++    return val;
++}
++
++/*
++ * Write status register 1 byte
++ * Returns negative if error occurred.
++ */
++static int write_sr(struct common_spi_flash *flash, u8 * val, u8 len)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WRSR);
++    cmd.tx_buf = val;
++    cmd.data_cnt = len;
++    cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d write enable\n", (int)m.status);
++        return m.status;
++    }
++
++    return 0;
++}
++
++static inline int change_4b(struct common_spi_flash *flash, u8 val)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    if (val)
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_EN4B);
++    else
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_EX4B);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d write enable\n", (int)m.status);
++        return m.status;
++    }
++
++    return 0;
++}
++
++/*
++ * Set write enable latch with Write Enable command.
++ * Returns negative if error occurred.
++ */
++static inline int write_enable(struct common_spi_flash *flash)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WREN);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d write enable\n", (int)m.status);
++        return m.status;
++    }
++
++    return 0;
++}
++
++/*
++ * Service routine to read status register until ready, or timeout occurs.
++ * Returns non-zero if error.
++ */
++static int wait_till_ready(struct common_spi_flash *flash, int wait_time)
++{
++	int sr = 0;
++	unsigned long timeo = jiffies;
++
++    timeo += (wait_time * HZ);
++	/* one chip guarantees max 5 msec wait here after page writes,
++	 * but potentially three seconds (!) after page erase.
++	 */
++	while (time_before(jiffies, timeo)){
++		if ((sr = read_sr(flash, OPCODE_RDSR)) < 0)
++			break;
++		else if (!(sr & SR_WIP))
++			return 0;
++	}
++	if (sr & SR_WIP)
++        printk(KERN_ERR "SPI wait ready time out\n");
++        
++	return 1;
++}
++
++static inline int flash_set_quad_enable(struct common_spi_flash *flash)
++{
++    u8 sr[2];
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    /* Wait until finished previous write command. */
++    if (wait_till_ready(flash, 3))
++        return 1;
++
++    if ((sr[0] = read_sr(flash, OPCODE_RDSR)) < 0)
++        return 1;
++
++    if (flash->flash_type == 1) {       //winbond
++        if ((sr[1] = read_sr(flash, OPCODE_RDSR2)) < 0)
++            return 1;
++        if (sr[1] & (1 << 1))   //has enable
++            return 0;
++    } else {
++        if (sr[0] & (1 << 6))   //has enable
++            return 0;
++    }
++    /* Send write enable, then erase commands. */
++    write_enable(flash);
++    if (flash->flash_type == 1) //winbond
++        write_sr(flash, &sr[0], 2);
++    else
++        write_sr(flash, &sr[0], 1);
++
++    return 0;
++}
++
++/*
++ * Erase the whole flash memory
++ *
++ * Returns 0 if successful, non-zero otherwise.
++ */
++static int erase_chip(struct common_spi_flash *flash)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s %dKiB\n", dev_name(&flash->spi->dev), __func__, (int)(flash->mtd.size / 1024));
++
++    /* Wait until finished previous write command. */
++    if (wait_till_ready(flash, 3))
++        return 1;
++
++    /* Send write enable, then erase commands. */
++    write_enable(flash);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    /* Set up command buffer. */
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_CHIP_ERASE);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d erase chip\n", (int)m.status);
++        return m.status;
++    }
++
++    return 0;
++}
++
++/*
++ * Erase one sector of flash memory at offset ``offset'' which is any
++ * address within the sector which should be erased.
++ *
++ * Returns 0 if successful, non-zero otherwise.
++ */
++static int erase_sector(struct common_spi_flash *flash, u32 offset)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++    int ret = 0;
++
++    pr_debug("%s: %s %dKiB at 0x%08x\n",
++             dev_name(&flash->spi->dev), __func__, flash->mtd.erasesize / 1024, offset);
++
++    /* Wait until finished previous write command. */
++    if (wait_till_ready(flash, 3))
++        return 1;
++
++    /* Enter 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 1);
++
++    /* Send write enable, then erase commands. */
++    write_enable(flash);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    /* Set up command buffer. */
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.spi_addr = offset;
++    if (flash->mode_3_4 == 3)
++        cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++    else
++        cmd.addr_len = FTSPI020_CMD1_ADDR_4BYTE;
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(flash->erase_opcode);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d erase sector\n", (int)m.status);
++        ret = m.status;
++    }
++    /* Exit 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 0);
++
++    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 common_spi_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++    struct common_spi_flash *flash = mtd_to_common_spi_flash(mtd);
++    u32 addr, len;
++    uint32_t rem;
++
++    pr_debug("%s: %s %s 0x%08x, len %d\n",
++             dev_name(&flash->spi->dev), __func__, "at", (u32) instr->addr, (int)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;
++    //}
++    div_u64_rem(instr->len, mtd->erasesize, &rem);
++    if (rem)
++        return -EINVAL;
++
++    addr = instr->addr;
++    len = instr->len;
++
++	mutex_lock(&flash->lock);
++
++	if (addr != 0 || len != mtd->size) {
++		while (len) {
++
++			if (erase_sector(flash, addr)) {
++				instr->state = MTD_ERASE_FAILED;
++				mutex_unlock(&flash->lock);
++				return -EIO;
++			}
++
++			addr += mtd->erasesize;
++			len -= mtd->erasesize;
++        	/* Wait until finished previous write command. */
++        	if (wait_till_ready(flash, 5)) {
++        	    printk(KERN_ERR "SPI wait previous erase command time out\n");
++        		mutex_unlock(&flash->lock);
++        		return -EIO;
++        	}			
++		}
++	} else {
++		if (erase_chip(flash)) {
++			instr->state = MTD_ERASE_FAILED;
++			mutex_unlock(&flash->lock);
++			return -EIO;
++		}
++        if (wait_till_ready(flash, 500)) {
++            printk(KERN_ERR "SPI wait chip erase command time out\n");
++        	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 common_spi_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
++                                 size_t * retlen, u_char * buf)
++{
++    struct common_spi_flash *flash = mtd_to_common_spi_flash(mtd);
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++    int ret = 0;
++
++    pr_debug("%s: %s %s 0x%08x, len %zd\n",
++             dev_name(&flash->spi->dev), __func__, "from", (u32) from, len);
++    /* sanity checks */
++    if (!len)
++        return 0;
++
++    if (from + len > flash->mtd.size)
++        return -EINVAL;
++
++    /* Enter 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 1);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    t.bits_per_word = 8;
++    spi_message_add_tail(&t, &m);
++
++    /* NOTE:
++     * OPCODE_FAST_READ (if available) is faster.
++     * Should add 1 byte DUMMY_BYTE.
++     */
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.spi_addr = from;
++    if (flash->mode_3_4 == 3)
++        cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++    else
++        cmd.addr_len = FTSPI020_CMD1_ADDR_4BYTE;
++
++    cmd.dum_2nd_cyc = FTSPI020_CMD1_DUMMY_CYCLE(READ_DUMMY_CYCLE);
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_READ;
++	if(OPCODE_READ_COMMAND == OPCODE_FAST_READ_DUAL)
++		cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_READ_COMMAND) | spi_operate_dual_mode;
++	else
++    	cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_READ_COMMAND);
++
++    cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++    cmd.rx_buf = buf;
++    cmd.data_cnt = len;
++
++    /* 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, 2)) {
++        /* REVISIT status return?? */
++        mutex_unlock(&flash->lock);
++        ret = 1;
++        goto exit_read;
++    }
++
++    spi_sync(flash->spi, &m);
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d read\n", (int)m.status);
++        mutex_unlock(&flash->lock);
++        ret = m.status;
++        goto exit_read;
++    }
++
++    *retlen = m.actual_length;
++
++    mutex_unlock(&flash->lock);
++
++exit_read:
++    /* Exit 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 0);
++
++    return ret;
++
++}
++
++/*
++ * 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 common_spi_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
++                                  size_t * retlen, const u_char * buf)
++{
++    struct common_spi_flash *flash = mtd_to_common_spi_flash(mtd);
++    u32 page_offset, page_size;
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s %s 0x%08x, len %zd\n",
++             dev_name(&flash->spi->dev), __func__, "to", (u32) to, len);
++
++    if (retlen)
++        *retlen = 0;
++
++    /* sanity checks */
++    if (!len)
++        return (0);
++
++    if (to + len > flash->mtd.size)
++        return -EINVAL;
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    t.bits_per_word = 8;
++    spi_message_add_tail(&t, &m);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    if (flash->mode_3_4 == 3)
++        cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++    else
++        cmd.addr_len = FTSPI020_CMD1_ADDR_4BYTE;
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++#ifdef CONFIG_SPI_QUAD_MODE
++    if (flash->flash_type == 1)
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WINBOND_PP);
++    else
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_QUAD_PP);
++#else
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WRITE_COMMAND);
++#endif
++    cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++    cmd.tx_buf = buf;
++
++    mutex_lock(&flash->lock);
++
++    /* Wait until finished previous write command. */
++	if (wait_till_ready(flash, 3)) {
++	    printk(KERN_ERR "SPI wait previous command time out\n");
++        mutex_unlock(&flash->lock);
++        return 1;
++    }
++
++    /* Enter 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 1);
++
++    write_enable(flash);
++
++    /* Set up the opcode in the write buffer. */
++    cmd.spi_addr = to;
++
++    /* what page do we start with? */
++    page_offset = to % FLASH_PAGESIZE;
++
++    /* do all the bytes fit onto one page? */
++    if (page_offset + len <= FLASH_PAGESIZE) {
++        cmd.data_cnt = len;
++
++        spi_sync(flash->spi, &m);
++
++        if (retlen)
++            *retlen = m.actual_length;
++    } else {
++        u32 i;
++
++        /* the size of data remaining on the first page */
++        page_size = FLASH_PAGESIZE - page_offset;
++
++        cmd.data_cnt = page_size;
++        spi_sync(flash->spi, &m);
++
++        *retlen = m.actual_length;
++
++        /* write everything in PAGESIZE chunks */
++        for (i = page_size; i < len; i += page_size) {
++            page_size = len - i;
++            if (page_size > FLASH_PAGESIZE)
++                page_size = FLASH_PAGESIZE;
++
++            /* write the next page to flash */
++            cmd.spi_addr = to + i;
++
++            cmd.tx_buf = buf + i;
++            cmd.data_cnt = page_size;
++
++            if (wait_till_ready(flash, 3)) {
++			    printk(KERN_ERR "SPI wait previous write command time out\n");
++		        mutex_unlock(&flash->lock);
++		        return 1;
++            }
++            write_enable(flash);
++
++            spi_sync(flash->spi, &m);
++
++            if (retlen)
++                *retlen += m.actual_length;
++        }
++    }
++
++    /* Exit 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 0);
++
++    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;
++    u16 ext_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_SE works uniformly */
++#define	SECT_64K	0x02    /* OPCODE_SE works uniformly */
++    u8 mode_3_4;
++    u8 flash_type;
++};
++
++/* 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 common_spi_flash_data[] = {
++#ifdef CONFIG_MTD_ERASE_64K     //for erase performance, one time 64KB
++    /* winbond */
++    {"w25q32bv", 0xef4016, 0, 65536, 64, SECT_64K, 3, 1},
++    {"w25X64V", 0xef3017, 0, 65536, 128, SECT_64K, 3, 1},
++    {"w25Q64F", 0xef4017, 0, 65536, 128, SECT_64K, 3, 1},
++    {"w25q128bv", 0xef4018, 0, 65536, 256, SECT_64K, 3, 1},
++    {"w25q25xFV", 0xef4019, 0, 65536, 512, SECT_64K, 4, 1},
++    /* mxic */
++    {"MX25L64", 0xc22017, 0, 65536, 128, SECT_64K, 3, 2},    
++    {"KH25L64", 0xc22617, 0, 65536, 128, SECT_64K, 3, 2}, 
++    {"MX25L12845E", 0xc22018, 0, 65536, 256, SECT_64K, 3, 2},
++    {"MX25L25x35E", 0xc22019, 0, 65536, 512, SECT_64K, 4, 2},
++    /* eon */
++    {"en25q128", 0x1c3018, 0, 65536, 256, SECT_64K, 3, 3},
++    {"en25qh128a", 0x1c7018, 0, 65536, 256, SECT_64K, 3, 3},
++    {"en25qh256", 0x1c7019, 0, 65536, 512, SECT_64K, 4, 3},
++    /* esmt */
++    {"w25Q64F", 0x8c4117, 0, 65536, 128, SECT_64K, 3, 3},
++	/* Spansion */
++	{"s25fl164k", 0x014017, 0, 65536, 128, SECT_64K, 3, 3},
++	{"s25fl128s", 0x012018, 0, 65536, 256, SECT_64K, 3, 3},
++	{"s25fl256s", 0x010219, 0, 65536, 512, SECT_64K, 4, 3},
++	/* GD */
++    {"gd25q64c", 0xc84017, 0, 65536, 128, SECT_64K, 3, 3},	
++	{"gd25q128c", 0xc84018, 0, 65536, 256, SECT_64K, 3, 3},
++	{"gd25q256c", 0xc84019, 0, 65536, 512, SECT_64K, 4, 3},
++	/* Micron */
++	{"N25q256", 0x20BA19, 0, 65536, 512, SECT_64K, 4, 4},
++#else
++    /* winbond */
++    {"w25q32bv", 0xef4016, 0, 4096, 1024, SECT_4K, 3, 1},
++    {"w25X64V", 0xef3017, 0, 4096, 2048, SECT_4K, 3, 1},
++    {"w25Q64F", 0xef4017, 0, 4096, 2048, SECT_4K, 3, 1},
++    {"w25q128bv", 0xef4018, 0, 4096, 4096, SECT_4K, 3, 1},
++    /* mxic */
++    {"MX25L12845E", 0xc22018, 0, 4096, 4096, SECT_4K, 3, 2},
++    {"MX25L25635E", 0xc22019, 0, 4096, 8192, SECT_4K, 4, 2},
++    /* eon */
++    {"en25q128", 0x1c3018, 0, 4096, 4096, SECT_4K, 3, 3},
++    {"en25qh256", 0x1c7019, 0, 4096, 8192, SECT_4K, 4, 3},
++#endif
++#if 0                           //ratbert
++    /* Atmel -- some are (confusingly) marketed as "DataFlash" */
++    {"at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K,},
++    {"at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K,},
++
++    {"at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K,},
++    {"at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K,},
++
++    {"at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K,},
++    {"at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K,},
++    {"at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K,},
++    {"at26df321", 0x1f4701, 0, 64 * 1024, 64, SECT_4K,},
++
++    /* Spansion -- single (large) sector size only, at least
++     * for the chips listed here (without boot sectors).
++     */
++    {"s25sl004a", 0x010212, 0, 64 * 1024, 8,},
++    {"s25sl008a", 0x010213, 0, 64 * 1024, 16,},
++    {"s25sl016a", 0x010214, 0, 64 * 1024, 32,},
++    {"s25sl032a", 0x010215, 0, 64 * 1024, 64,},
++    {"s25sl064a", 0x010216, 0, 64 * 1024, 128,},
++    {"s25sl12800", 0x012018, 0x0300, 256 * 1024, 64,},
++    {"s25sl12801", 0x012018, 0x0301, 64 * 1024, 256,},
++
++    /* SST -- large erase sizes are "overlays", "sectors" are 4K */
++    {"sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K,},
++    {"sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K,},
++    {"sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K,},
++    {"sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K,},
++
++    /* ST Microelectronics -- newer production may have feature updates */
++    {"w25q05", 0x202010, 0, 32 * 1024, 2,},
++    {"w25q10", 0x202011, 0, 32 * 1024, 4,},
++    {"w25q20", 0x202012, 0, 64 * 1024, 4,},
++    {"w25q40", 0x202013, 0, 64 * 1024, 8,},
++    {"w25q80", 0, 0, 64 * 1024, 16,},
++    {"w25q16", 0x202015, 0, 64 * 1024, 32,},
++    {"w25q32", 0x202016, 0, 64 * 1024, 64,},
++    {"w25q64", 0x202017, 0, 64 * 1024, 128,},
++    {"w25q128", 0x202018, 0, 256 * 1024, 64,},
++
++    {"m45pe80", 0x204014, 0, 64 * 1024, 16,},
++    {"m45pe16", 0x204015, 0, 64 * 1024, 32,},
++
++    {"w25qe80", 0x208014, 0, 64 * 1024, 16,},
++    {"w25qe16", 0x208015, 0, 64 * 1024, 32, SECT_4K,},
++
++    /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
++    {"w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K,},
++    {"w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K,},
++    {"w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K,},
++    {"w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K,},
++    {"w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K,},
++    {"w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K,},
++    {"w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K,},
++    {"w25p16", 0xef2015, 0, 64 * 1024, 32,},    //ratbert
++#endif
++};
++
++static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
++{
++    u8 id[4];
++    u32 jedec;
++    u32 tmp;
++    struct flash_info *info;
++    struct ftspi020_cmd spi_cmd;
++    struct spi_transfer t;
++    struct spi_message m;
++
++    pr_debug("%s: %s\n", dev_name(&spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &spi_cmd;
++    t.bits_per_word = 8;
++    spi_message_add_tail(&t, &m);
++
++    memset(&spi_cmd, 0, sizeof(struct ftspi020_cmd));
++    spi_cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++    spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    spi_cmd.data_cnt = 4;
++    spi_cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_RDID);
++    spi_cmd.write_en = FTSPI020_CMD3_READ;
++
++    spi_cmd.rx_buf = &id;
++    spi_sync(spi, &m);
++
++    if (m.status < 0) {
++        printk(KERN_ERR "%s: error %d reading JEDEC ID\n", dev_name(&spi->dev), m.actual_length);
++        return NULL;
++    }
++
++    jedec = id[0];
++    jedec = jedec << 8;
++    jedec |= id[1];
++    jedec = jedec << 8;
++    jedec |= id[2];
++
++    pr_debug("SPI flash id[0] = %x, id[1] = %x, id[2] = %x\n", id[0], id[1], id[2]);
++    for (tmp = 0, info = common_spi_flash_data;
++         tmp < ARRAY_SIZE(common_spi_flash_data); tmp++, info++) {
++        if (info->jedec_id == jedec)
++            return info;
++    }
++
++    dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
++    return NULL;
++}
++
++static int partition_check(struct mtd_partition *partitions, sys_header_t *sys_hdr, int page_size, int chip_size)
++{
++    int i, num = 0;
++    int j, A_begin, A_end, B_begin, B_end;
++
++	//block alignment check
++    for(i = 0; i < ARRAY_SIZE(sys_hdr->image); i++){
++        
++        if(sys_hdr->image[i].size == 0)
++    	    continue;
++
++        if(sys_hdr->image[i].addr % page_size){
++    	    printk(KERN_WARNING "Warning............partition %d addr 0x%x not block alignment, one block = 0x%x\n", i, sys_hdr->image[i].addr, page_size);
++    	    partitions[num].offset = BLOCK_ALIGN(sys_hdr->image[i].addr, page_size);
++        } else {
++       	    partitions[num].offset = sys_hdr->image[i].addr;
++       	}
++
++        if(sys_hdr->image[i].size % page_size){
++    	    printk(KERN_WARNING "Warning............partition %d size 0x%x not block alignment, one block = 0x%x\n", i, sys_hdr->image[i].size, page_size);
++    	    partitions[num].size = BLOCK_ALIGN(sys_hdr->image[i].size, page_size);
++        } else {
++      	    partitions[num].size = sys_hdr->image[i].size;
++      	}
++
++        partitions[num].name = sys_hdr->image[i].name;
++	//printk("p[%d] offset = 0x%x, size = 0x%x, name = %s\n", num, (u32)partitions[num].offset, (u32)partitions[num].size, partitions[num].name);
++        num++;
++    }
++
++    //overlap check
++    for(i = 0; i < (num - 1); i++){
++        A_begin = sys_hdr->image[i].addr;
++        A_end = A_begin + sys_hdr->image[i].size;
++	    //printk("A %x,%x\n",A_begin,A_end);
++			
++        for(j = (i + 1); j < num; j++){
++            B_begin = sys_hdr->image[j].addr;
++	        B_end = B_begin + sys_hdr->image[j].size;
++		    //printk("B %x,%x\n",B_begin,B_end);
++				      
++	        /* A_end between B_end and B_begin */
++	        if((B_end >= A_end) && (A_end > B_begin))
++	      	    goto check_fail;
++	        /* A_begin between B_end and B_begin */
++	        if((B_end > A_begin) && (A_begin >= B_begin))
++	      	    goto check_fail;
++	        /* B between A */
++	        if((A_end >= B_end) && (B_begin >= A_begin))
++	      	    goto check_fail;	      	      	
++	    }
++    }
++    
++#ifdef CONFIG_PLATFORM_GM8210
++    if(sys_hdr->addr != 0) {
++        partitions[num].offset = sys_hdr->addr;
++        partitions[num].size = sys_hdr->size;
++        partitions[num].name = sys_hdr->name;
++        num++;        
++    }
++#endif 
++    
++    /* total flash map to last MTD
++     */
++    partitions[num].offset = 0;
++    partitions[num].size = chip_size;
++
++    partitions[num].name = "ALL";
++    num++;
++    return num;
++    
++check_fail:
++    printk(KERN_WARNING "Warning ============> partition %d overlap with %d\n", i, j);
++    return num;
++}
++
++/*
++ * 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 common_spi_flash_probe(struct spi_device *spi)
++{
++    struct flash_platform_data *data;
++    struct common_spi_flash *flash;
++    struct flash_info *info;
++    struct mtd_partition *parts = NULL;
++    int nr_parts = 0;
++    size_t retlen[1], i;
++
++    pr_debug("%s: %s\n", dev_name(&spi->dev), __func__);
++
++    /* 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 = common_spi_flash_data;
++             i < ARRAY_SIZE(common_spi_flash_data); i++, info++) {
++            if (strcmp(data->type, info->name) == 0)
++                break;
++        }
++
++        /* unrecognized chip? */
++        if (i == ARRAY_SIZE(common_spi_flash_data)) {
++            printk(KERN_ERR "%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->spi = spi;
++    mutex_init(&flash->lock);
++    dev_set_drvdata(&spi->dev, flash);
++
++    if (data && data->name)
++        flash->mtd.name = "nor-flash";//u-boot commandline
++    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 = common_spi_flash_erase;
++    flash->mtd.read = common_spi_flash_read;
++    flash->mtd.write = common_spi_flash_write;
++    flash->mode_3_4 = info->mode_3_4;
++    flash->flash_type = info->flash_type;
++
++    if (flash->mode_3_4 == 3){
++        OPCODE_READ_COMMAND = OPCODE_FAST_READ_DUAL;//0x0B
++        OPCODE_WRITE_COMMAND = 0x02;
++        OPCODE_ERASE_COMMAND = 0xD8;
++    } else {
++        switch (flash->flash_type){
++            case 1:	//winbond
++                OPCODE_READ_COMMAND = OPCODE_FAST_READ_DUAL;//0x0B
++                OPCODE_WRITE_COMMAND = 0x02;
++                OPCODE_ERASE_COMMAND = 0xD8;
++                break;
++            case 2:	//MXIC
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)                
++                if (platform_spi_four_byte_mode()) {	//3 byte mode
++                    OPCODE_READ_COMMAND = OPCODE_FAST_READ_DUAL;//0x0B
++                    OPCODE_WRITE_COMMAND = 0x02;
++                    OPCODE_ERASE_COMMAND = 0xD8;
++                } else {	//4 byte mode
++                    OPCODE_READ_COMMAND = 0x0C;//0x3C
++                    OPCODE_WRITE_COMMAND = 0x12;
++                    OPCODE_ERASE_COMMAND = 0xDC;
++                }
++                break;
++#else
++                OPCODE_READ_COMMAND = 0x0B;
++                OPCODE_WRITE_COMMAND = 0x02;
++                OPCODE_ERASE_COMMAND = 0xD8;                
++#endif                
++            case 3:	//EON, ESMT, spansion, GD
++                OPCODE_READ_COMMAND = 0x0B;
++                OPCODE_WRITE_COMMAND = 0x02;
++                OPCODE_ERASE_COMMAND = 0xD8;
++                break;                
++            case 4:	//Micron
++                OPCODE_READ_COMMAND = 0x0C;
++                OPCODE_WRITE_COMMAND = 0x12;
++                OPCODE_ERASE_COMMAND = 0xD8;
++                break; 
++            default:
++                OPCODE_READ_COMMAND = 0x0B;
++                OPCODE_WRITE_COMMAND = 0x02;
++                OPCODE_ERASE_COMMAND = 0xD8;
++                break;
++        }
++        change_4b(flash, 1);
++    }
++#ifdef CONFIG_SPI_QUAD_MODE
++    flash_set_quad_enable(flash);
++#endif
++
++    /* prefer "small sector" erase if possible */
++    if (info->flags & SECT_4K) {
++        flash->erase_opcode = OPCODE_SE;
++        flash->mtd.erasesize = 4096;
++        printk(KERN_INFO "ERASE SECTOR 4K\n");
++    } else if (info->flags & SECT_64K) {
++        flash->erase_opcode = OPCODE_ERASE_COMMAND;
++        flash->mtd.erasesize = 64 * 1024;
++        printk(KERN_INFO "ERASE SECTOR 64K\n");
++    } else {
++        flash->erase_opcode = OPCODE_CHIP_ERASE;
++        flash->mtd.erasesize = flash->mtd.size;
++    }
++
++    dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name, (int)(flash->mtd.size / 1024));
++
++    pr_debug("mtd .name = %s, .size = 0x%.8x (%uMiB) "
++             ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
++             flash->mtd.name,
++             (int)flash->mtd.size, (int)(flash->mtd.size / (1024 * 1024)),
++             (int)flash->mtd.erasesize, (int)(flash->mtd.erasesize / 1024),
++             flash->mtd.numeraseregions);
++
++    if (flash->mtd.numeraseregions)
++        for (i = 0; i < flash->mtd.numeraseregions; i++)
++            pr_debug("mtd.eraseregions[%d] = { .offset = 0x%.8x, "
++                     ".erasesize = 0x%.8x (%uKiB), "
++                     ".numblocks = %d }\n",
++                     i, (u32) flash->mtd.eraseregions[i].offset,
++                     (int)flash->mtd.eraseregions[i].erasesize,
++                     (int)(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).
++     */
++
++    /* read system header
++     */
++    flash->sys_hdr = kzalloc(sizeof(struct sys_header), GFP_KERNEL);
++
++    if (flash->sys_hdr == NULL) {
++        printk(KERN_ERR "Warning............SPI: can't alloc memory");
++        return -ENOMEM;
++    }
++
++    if (common_spi_flash_read
++        (&flash->mtd, 0x0, sizeof(struct sys_header), retlen, (u_char *) flash->sys_hdr) < 0)
++        printk(KERN_ERR "SPI: read system header fail!");
++
++    //printk("addr=%x, size=%x\n",flash->sys_hdr->image[0].addr, flash->sys_hdr->image[0].size);//???
++    if (flash->sys_hdr->image[0].size == 0) {
++        printk(KERN_WARNING "Not find partition message, use default setting\n");
++
++        flash->sys_hdr->image[0].name[0] = 'a'; //???
++        flash->sys_hdr->image[0].addr = 0x20000;
++        flash->sys_hdr->image[0].size = 0x30000;
++
++        flash->sys_hdr->image[1].name[0] = 'u';
++        flash->sys_hdr->image[1].addr = 0x700000;
++        flash->sys_hdr->image[1].size = 0x100000;
++
++        flash->sys_hdr->image[2].name[0] = 'r';
++        flash->sys_hdr->image[2].addr = 0x00000;
++        flash->sys_hdr->image[2].size = 0x10000;
++
++        for (i = 3; i < 10; i++) {
++            flash->sys_hdr->image[i].addr = 0;
++            flash->sys_hdr->image[i].size = 0;
++        }
++    }
++    nr_parts =
++        partition_check(ftspi020_partition_info, flash->sys_hdr, sizeof(struct sys_header),
++                        flash->mtd.size);
++    parts = ftspi020_partition_info;
++
++    if (nr_parts <= 0 && data && data->parts) {
++        parts = data->parts;
++        nr_parts = data->nr_parts;
++    }
++
++    if (nr_parts > 0) {
++        for (i = 0; i < nr_parts; i++) {
++            pr_debug("partitions[%d] = "
++                     "{.name = %s, .offset = 0x%.8x, "
++                     ".size = 0x%.8x (%uKiB) }\n",
++                     i, parts[i].name,
++                     (u32) parts[i].offset, (int)parts[i].size, (int)(parts[i].size / 1024));
++        }
++    }
++    return mtd_device_parse_register(&flash->mtd, part_probes, 0, parts, nr_parts);
++}
++
++static int __devexit common_spi_flash_remove(struct spi_device *spi)
++{
++    struct common_spi_flash *flash = dev_get_drvdata(&spi->dev);
++    int status;
++
++    /* Clean up MTD stuff. */
++    status = mtd_device_unregister(&flash->mtd);
++    if (status == 0) {
++        kfree(flash->sys_hdr);
++        kfree(flash);
++    }
++    return 0;
++}
++
++static struct spi_driver common_spi_flash_driver = {
++    .driver = {
++               .name = SPI_NAME,
++               .bus = &spi_bus_type,
++               .owner = THIS_MODULE,
++               },
++    .probe = common_spi_flash_probe,
++    .remove = __devexit_p(common_spi_flash_remove),
++
++    /* REVISIT: many of these chips have deep power-down modes, which
++     * should clearly be entered on suspend() to minimize power use.
++     * And also when they're otherwise idle...
++     */
++};
++
++static int __init common_spi_flash_init(void)
++{
++    /* add spi device here, when add corresponding spi driver, they will bind together
++     */
++    spi_register_board_info(spi_devs_info, ARRAY_SIZE(spi_devs_info));
++
++    return spi_register_driver(&common_spi_flash_driver);
++}
++
++static void common_spi_flash_exit(void)
++{
++    spi_unregister_driver(&common_spi_flash_driver);
++}
++
++module_init(common_spi_flash_init);
++module_exit(common_spi_flash_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Mike Lavender");
++MODULE_DESCRIPTION("MTD SPI driver for SPI flash chips");
+diff --git a/drivers/mtd/devices/spi_flash_v2.c b/drivers/mtd/devices/spi_flash_v2.c
+new file mode 100644
+index 00000000..db98b81f
+--- /dev/null
++++ b/drivers/mtd/devices/spi_flash_v2.c
+@@ -0,0 +1,1319 @@
++/*
++ * MTD SPI driver for ST M25Pxx (and similar) serial flash chips
++ *
++ * 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.
++ *
++ *
++ * Copyright (c) 2011 BingJiun Luo <bjluo@faraday-tech.com>
++ * - Modify for FTSPI020 Faraday SPI flash controller.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/mutex.h>
++#include <linux/delay.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <mach/platform/pmu.h>
++
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#ifdef MODULE
++#include "ftspi020.h"
++#else
++#include <linux/spi/ftspi020.h>
++#endif
++
++#define FLASH_PAGESIZE		256
++
++/* Flash opcodes. */
++#define	OPCODE_WREN		0x06    /* Write enable */
++#define	OPCODE_RDSR		0x05    /* Read status register */
++#define	OPCODE_RDSR2	0x35
++#define	OPCODE_WRSR		0x01    /* Write status register 1 byte */
++#define	OPCODE_EN4B		0xB7
++#define	OPCODE_EX4B		0xE9
++#define	OPCODE_NORM_READ	0x03    /* Read data bytes (low frequency) */
++#define	OPCODE_FAST_READ	0x0b    /* Read data bytes (high frequency) */
++#define OPCODE_FAST_READ_DUAL	    0x3B
++#define	OPCODE_QUAD_READ	0xEB
++#define OPCODE_WINBOND_PP 0x32
++#define	OPCODE_QUAD_PP		0x38
++#define	OPCODE_PP		0x02    /* Page program (up to 256 bytes) */
++#define	OPCODE_SE		0x20    /* Erase Sector 4KiB */
++#define	OPCODE_BE_32K		0x52    /* Erase 32KiB block */
++#define	OPCODE_BE_64K		0xd8    /* Erase 64KiB block */
++#define	OPCODE_CHIP_ERASE	0xc7    /* Erase whole flash chip */
++#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 spi_operate_serial_mode         0
++#define spi_operate_dual_mode           0x20
++#define spi_operate_quad_mode           0x40
++#define spi_operate_dualio_mode         0x60
++#define spi_operate_quadio_mode         0x80
++
++#define	CMD_SIZE		4
++/*
++#ifdef CONFIG_SPI_QUAD_MODE
++#define OPCODE_READ 	OPCODE_QUAD_READ
++#define READ_DUMMY_CYCLE	4
++#else
++#if 1                           //USE_FAST_READ
++#define OPCODE_READ 	OPCODE_FAST_READ
++#define READ_DUMMY_CYCLE	8
++#else
++#define OPCODE_READ 	OPCODE_NORM_READ
++#define READ_DUMMY_CYCLE	0
++#endif
++#endif
++*/
++#define READ_DUMMY_CYCLE	8
++
++unsigned char OPCODE_READ_COMMAND, OPCODE_WRITE_COMMAND, OPCODE_ERASE_COMMAND;
++  
++#define SPI_NAME	"SPI_FLASH"
++
++#define BLOCK_ALIGN(base, blk_shift) ((((base) + (0x1 << (blk_shift)) - 1) >> (blk_shift)) << (blk_shift))
++
++static struct mtd_partition ftspi020_partition_info[20];
++
++static struct flash_platform_data spi_flash_platform_data = {
++    .name = "wb_spi_flash",
++    .parts = ftspi020_partition_info,
++    .nr_parts = ARRAY_SIZE(ftspi020_partition_info)
++};
++
++#ifdef CONFIG_SECOND_SPI_FLASH
++static struct mtd_partition extra_partitions[] = {
++    {
++     .name = "Extra Code Section",
++     .offset = 0x000000,
++     .size = 0x800000           // 8MB
++     },
++    {
++     .name = "Extra User Section",      // free for use
++     .offset = 0x800000,
++     .size = 0x800000},
++};
++
++static struct flash_platform_data extra_spi_flash_platform_data = {
++    .name = "wb_spi_flash",
++    .parts = extra_partitions,
++    .nr_parts = ARRAY_SIZE(extra_partitions)
++};
++#endif //end of CONFIG_SECOND_SPI_FLASH
++static struct spi_board_info spi_devs_info[] __initdata = {
++    {
++     .modalias = SPI_NAME,
++     .platform_data = &spi_flash_platform_data,
++     .max_speed_hz = 45 * 1000 * 1000,  //40Mhz
++     .bus_num = 0,              //on bus 0
++     .chip_select = 0,          //first chip select//???
++     .mode = SPI_MODE_0,
++     },
++#ifdef CONFIG_SECOND_SPI_FLASH
++    {
++     .modalias = SPI_NAME,
++     .platform_data = &extra_spi_flash_platform_data,
++     .max_speed_hz = 45 * 1000 * 1000,  //40Mhz
++     .bus_num = 0,              //on bus 0
++     .chip_select = 1,          //first chip select
++     .mode = SPI_MODE_0,
++     }
++#endif
++};
++
++static const char *part_probes[] = { "cmdlinepart", NULL, };
++
++/****************************************************************************/
++typedef struct sys_header_v2 {	
++    char signature[8];          /* Signature is "GM8xxx" */  
++    struct {
++        unsigned int addr;          /* partition address */
++        unsigned int size;          /* partition size */
++        unsigned char name[8];      /* partition name */
++        unsigned int img_size;		/* image size */
++    } image[12];
++    	
++	struct 
++	{
++		unsigned char pagesz_log2;   // page size with bytes in log2
++		unsigned char secsz_log2;    // sector size with bytes in log2
++		unsigned char chipsz_log2;   // chip size with bytes in log2
++		unsigned char clk_div;       // 2/4/6/8
++	} norfixup;	
++	
++	unsigned char 	reserved[2];   	// unused
++	unsigned char   last_256[2];    // byte254:0x55, byte255:0xAA
++} sys_header_v2_t;
++
++struct common_spi_flash {
++    struct spi_device *spi;
++    struct mutex lock;
++    struct mtd_info mtd;
++    sys_header_v2_t *sys_hdr;      /* system header */
++
++    u8 erase_opcode;
++    u8 mode_3_4;
++    u8 flash_type;
++};
++
++static inline struct common_spi_flash *mtd_to_common_spi_flash(struct mtd_info *mtd)
++{
++    return container_of(mtd, struct common_spi_flash, 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 common_spi_flash *flash, u8 ins_cmd)
++{
++    struct spi_transfer t[2];
++    struct spi_message m;
++    u8 val;
++    struct ftspi020_cmd cmd[2];
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(t, 0, (sizeof t));
++
++    t[0].tx_buf = &cmd[0];
++    spi_message_add_tail(&t[0], &m);
++
++    memset(&cmd[0], 0, sizeof(struct ftspi020_cmd));
++    cmd[0].ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd[0].write_en = FTSPI020_CMD3_READ;
++    cmd[0].read_status_en = FTSPI020_CMD3_RD_STS_EN;
++    cmd[0].read_status = FTSPI020_CMD3_STS_SW_READ;
++    cmd[0].ins_code = FTSPI020_CMD3_INSTR_CODE(ins_cmd);
++    cmd[0].flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    t[1].tx_buf = &cmd[1];
++    spi_message_add_tail(&t[1], &m);
++
++    memset(&cmd[1], 0, sizeof(struct ftspi020_cmd));
++    cmd[1].rx_buf = &val;
++    cmd[1].data_cnt = 1;
++    cmd[1].read_status_en = FTSPI020_CMD3_RD_STS_EN;
++    cmd[1].read_status = FTSPI020_CMD3_STS_SW_READ;;
++    cmd[1].flags = FTSPI020_XFER_DATA_STATE;
++
++    spi_sync(flash->spi, &m);
++
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d reading SR\n", (int)m.actual_length);
++        return m.status;
++    }
++
++    return val;
++}
++
++/*
++ * Write status register 1 byte
++ * Returns negative if error occurred.
++ */
++static int write_sr(struct common_spi_flash *flash, u8 * val, u8 len)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WRSR);
++    cmd.tx_buf = val;
++    cmd.data_cnt = len;
++    cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d write enable\n", (int)m.status);
++        return m.status;
++    }
++
++    return 0;
++}
++
++static inline int change_4b(struct common_spi_flash *flash, u8 val)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    if (val)
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_EN4B);
++    else
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_EX4B);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d write enable\n", (int)m.status);
++        return m.status;
++    }
++
++    return 0;
++}
++
++/*
++ * Set write enable latch with Write Enable command.
++ * Returns negative if error occurred.
++ */
++static inline int write_enable(struct common_spi_flash *flash)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WREN);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d write enable\n", (int)m.status);
++        return m.status;
++    }
++
++    return 0;
++}
++
++/*
++ * Service routine to read status register until ready, or timeout occurs.
++ * Returns non-zero if error.
++ */
++static int wait_till_ready(struct common_spi_flash *flash, int wait_time)
++{
++	int sr = 0;
++	unsigned long timeo = jiffies;
++
++    timeo += (wait_time * HZ);
++	/* one chip guarantees max 5 msec wait here after page writes,
++	 * but potentially three seconds (!) after page erase.
++	 */
++	while (time_before(jiffies, timeo)){
++		if ((sr = read_sr(flash, OPCODE_RDSR)) < 0)
++			break;
++		else if (!(sr & SR_WIP))
++			return 0;
++	}
++	if (sr & SR_WIP)
++        printk(KERN_ERR "SPI wait ready time out\n");
++        
++	return 1;
++}
++
++static inline int flash_set_quad_enable(struct common_spi_flash *flash)
++{
++    u8 sr[2];
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    /* Wait until finished previous write command. */
++    if (wait_till_ready(flash, 3))
++        return 1;
++
++    if ((sr[0] = read_sr(flash, OPCODE_RDSR)) < 0)
++        return 1;
++
++    if (flash->flash_type == 1) {       //winbond
++        if ((sr[1] = read_sr(flash, OPCODE_RDSR2)) < 0)
++            return 1;
++        if (sr[1] & (1 << 1))   //has enable
++            return 0;
++    } else {
++        if (sr[0] & (1 << 6))   //has enable
++            return 0;
++    }
++    /* Send write enable, then erase commands. */
++    write_enable(flash);
++    if (flash->flash_type == 1) //winbond
++        write_sr(flash, &sr[0], 2);
++    else
++        write_sr(flash, &sr[0], 1);
++
++    return 0;
++}
++
++/*
++ * Erase the whole flash memory
++ *
++ * Returns 0 if successful, non-zero otherwise.
++ */
++static int erase_chip(struct common_spi_flash *flash)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s %dKiB\n", dev_name(&flash->spi->dev), __func__, (int)(flash->mtd.size / 1024));
++
++    /* Wait until finished previous write command. */
++    if (wait_till_ready(flash, 3))
++        return 1;
++
++    /* Send write enable, then erase commands. */
++    write_enable(flash);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    /* Set up command buffer. */
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_CHIP_ERASE);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d erase chip\n", (int)m.status);
++        return m.status;
++    }
++
++    return 0;
++}
++
++/*
++ * Erase one sector of flash memory at offset ``offset'' which is any
++ * address within the sector which should be erased.
++ *
++ * Returns 0 if successful, non-zero otherwise.
++ */
++static int erase_sector(struct common_spi_flash *flash, u32 offset)
++{
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++    int ret = 0;
++
++    pr_debug("%s: %s %dKiB at 0x%08x\n",
++             dev_name(&flash->spi->dev), __func__, flash->mtd.erasesize / 1024, offset);
++
++    /* Wait until finished previous write command. */
++    if (wait_till_ready(flash, 3))
++        return 1;
++
++    /* Enter 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 1);
++
++    /* Send write enable, then erase commands. */
++    write_enable(flash);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    spi_message_add_tail(&t, &m);
++
++    /* Set up command buffer. */
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.spi_addr = offset;
++    if (flash->mode_3_4 == 3)
++        cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++    else
++        cmd.addr_len = FTSPI020_CMD1_ADDR_4BYTE;
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(flash->erase_opcode);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    spi_sync(flash->spi, &m);
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d erase sector\n", (int)m.status);
++        ret = m.status;
++    }
++    /* Exit 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 0);
++
++    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 common_spi_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++    struct common_spi_flash *flash = mtd_to_common_spi_flash(mtd);
++    u32 addr, len;
++    uint32_t rem;
++
++    pr_debug("%s: %s %s 0x%08x, len %d\n",
++             dev_name(&flash->spi->dev), __func__, "at", (u32) instr->addr, (int)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;
++    //}
++    div_u64_rem(instr->len, mtd->erasesize, &rem);
++    if (rem)
++        return -EINVAL;
++
++    addr = instr->addr;
++    len = instr->len;
++
++	mutex_lock(&flash->lock);
++
++	if (addr != 0 || len != mtd->size) {
++		while (len) {
++
++			if (erase_sector(flash, addr)) {
++				instr->state = MTD_ERASE_FAILED;
++				mutex_unlock(&flash->lock);
++				return -EIO;
++			}
++
++			addr += mtd->erasesize;
++			len -= mtd->erasesize;
++        	/* Wait until finished previous write command. */
++        	if (wait_till_ready(flash, 5)) {
++        	    printk(KERN_ERR "SPI wait previous erase command time out\n");
++        		mutex_unlock(&flash->lock);
++        		return -EIO;
++        	}			
++		}
++	} else {
++		if (erase_chip(flash)) {
++			instr->state = MTD_ERASE_FAILED;
++			mutex_unlock(&flash->lock);
++			return -EIO;
++		}
++        if (wait_till_ready(flash, 500)) {
++            printk(KERN_ERR "SPI wait chip erase command time out\n");
++        	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 common_spi_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
++                                 size_t * retlen, u_char * buf)
++{
++    struct common_spi_flash *flash = mtd_to_common_spi_flash(mtd);
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++    int ret = 0;
++
++    pr_debug("%s: %s %s 0x%08x, len %zd\n",
++             dev_name(&flash->spi->dev), __func__, "from", (u32) from, len);
++    /* sanity checks */
++    if (!len)
++        return 0;
++
++    if (from + len > flash->mtd.size)
++        return -EINVAL;
++
++    /* Enter 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 1);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    t.bits_per_word = 8;
++    spi_message_add_tail(&t, &m);
++
++    /* NOTE:
++     * OPCODE_FAST_READ (if available) is faster.
++     * Should add 1 byte DUMMY_BYTE.
++     */
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.spi_addr = from;
++    if (flash->mode_3_4 == 3)
++        cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++    else
++        cmd.addr_len = FTSPI020_CMD1_ADDR_4BYTE;
++
++    cmd.dum_2nd_cyc = FTSPI020_CMD1_DUMMY_CYCLE(READ_DUMMY_CYCLE);
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_READ;
++	if(OPCODE_READ_COMMAND == OPCODE_FAST_READ_DUAL)
++		cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_READ_COMMAND) | spi_operate_dual_mode;
++	else
++    	cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_READ_COMMAND);
++
++    cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++    cmd.rx_buf = buf;
++    cmd.data_cnt = len;
++
++    /* 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, 2)) {
++        /* REVISIT status return?? */
++        mutex_unlock(&flash->lock);
++        ret = 1;
++        goto exit_read;
++    }
++
++    spi_sync(flash->spi, &m);
++    if (m.status < 0) {
++        dev_err(&flash->spi->dev, "error %d read\n", (int)m.status);
++        mutex_unlock(&flash->lock);
++        ret = m.status;
++        goto exit_read;
++    }
++
++    *retlen = m.actual_length;
++
++    mutex_unlock(&flash->lock);
++
++exit_read:
++    /* Exit 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 0);
++
++    return ret;
++
++}
++
++/*
++ * 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 common_spi_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
++                                  size_t * retlen, const u_char * buf)
++{
++    struct common_spi_flash *flash = mtd_to_common_spi_flash(mtd);
++    u32 page_offset, page_size;
++    struct spi_transfer t;
++    struct spi_message m;
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s %s 0x%08x, len %zd\n",
++             dev_name(&flash->spi->dev), __func__, "to", (u32) to, len);
++
++    if (retlen)
++        *retlen = 0;
++
++    /* sanity checks */
++    if (!len)
++        return (0);
++
++    if (to + len > flash->mtd.size)
++        return -EINVAL;
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &cmd;
++    t.bits_per_word = 8;
++    spi_message_add_tail(&t, &m);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    if (flash->mode_3_4 == 3)
++        cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++    else
++        cmd.addr_len = FTSPI020_CMD1_ADDR_4BYTE;
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++#ifdef CONFIG_SPI_QUAD_MODE
++    if (flash->flash_type == 1)
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WINBOND_PP);
++    else
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_QUAD_PP);
++#else
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WRITE_COMMAND);
++#endif
++    cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++    cmd.tx_buf = buf;
++
++    mutex_lock(&flash->lock);
++
++    /* Wait until finished previous write command. */
++	if (wait_till_ready(flash, 3)) {
++	    printk(KERN_ERR "SPI wait previous command time out\n");
++        mutex_unlock(&flash->lock);
++        return 1;
++    }
++
++    /* Enter 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 1);
++
++    write_enable(flash);
++
++    /* Set up the opcode in the write buffer. */
++    cmd.spi_addr = to;
++
++    /* what page do we start with? */
++    page_offset = to % FLASH_PAGESIZE;
++
++    /* do all the bytes fit onto one page? */
++    if (page_offset + len <= FLASH_PAGESIZE) {
++        cmd.data_cnt = len;
++
++        spi_sync(flash->spi, &m);
++
++        if (retlen)
++            *retlen = m.actual_length;
++    } else {
++        u32 i;
++
++        /* the size of data remaining on the first page */
++        page_size = FLASH_PAGESIZE - page_offset;
++
++        cmd.data_cnt = page_size;
++        spi_sync(flash->spi, &m);
++
++        *retlen = m.actual_length;
++
++        /* write everything in PAGESIZE chunks */
++        for (i = page_size; i < len; i += page_size) {
++            page_size = len - i;
++            if (page_size > FLASH_PAGESIZE)
++                page_size = FLASH_PAGESIZE;
++
++            /* write the next page to flash */
++            cmd.spi_addr = to + i;
++
++            cmd.tx_buf = buf + i;
++            cmd.data_cnt = page_size;
++
++            if (wait_till_ready(flash, 3)) {
++			    printk(KERN_ERR "SPI wait previous write command time out\n");
++		        mutex_unlock(&flash->lock);
++		        return 1;
++            }
++
++            write_enable(flash);
++
++            spi_sync(flash->spi, &m);
++
++            if (retlen)
++                *retlen += m.actual_length;
++        }
++    }
++
++    /* Exit 4 byte mode */
++    //if (flash->mode_3_4 == 3)
++    //    change_4b(flash, 0);
++
++    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;
++    u16 ext_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_SE works uniformly */
++#define	SECT_64K	0x02    /* OPCODE_SE works uniformly */
++    u8 mode_3_4;
++    u8 flash_type;
++};
++
++/* 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 common_spi_flash_data[] = {
++#ifdef CONFIG_MTD_ERASE_64K     //for erase performance, one time 64KB
++    /* winbond */
++    {"w25q32bv", 0xef4016, 0, 65536, 64, SECT_64K, 3, 1},
++    {"w25X64V", 0xef3017, 0, 65536, 128, SECT_64K, 3, 1},
++    {"w25Q64F", 0xef4017, 0, 65536, 128, SECT_64K, 3, 1},
++    {"w25q128bv", 0xef4018, 0, 65536, 256, SECT_64K, 3, 1},
++    {"w25q25xFV", 0xef4019, 0, 65536, 512, SECT_64K, 4, 1},
++    /* mxic */
++    {"MX25L64", 0xc22017, 0, 65536, 128, SECT_64K, 3, 2},    
++    {"MX25L12845E", 0xc22018, 0, 65536, 256, SECT_64K, 3, 2},
++    {"MX25L25x35E", 0xc22019, 0, 65536, 512, SECT_64K, 4, 2},
++    /* eon */
++    {"en25q128", 0x1c3018, 0, 65536, 256, SECT_64K, 3, 3},
++    {"en25qh128a", 0x1c7018, 0, 65536, 256, SECT_64K, 3, 3},
++    {"en25qh256", 0x1c7019, 0, 65536, 512, SECT_64K, 4, 3},
++    /* esmt */
++    {"w25Q64F", 0x8c4117, 0, 65536, 128, SECT_64K, 3, 3},
++	/* Spansion */
++	{"s25fl164k", 0x014017, 0, 65536, 128, SECT_64K, 3, 3},
++	{"s25fl128s", 0x012018, 0, 65536, 256, SECT_64K, 3, 3},
++	{"s25fl256s", 0x010219, 0, 65536, 512, SECT_64K, 4, 3},
++	/* GD */
++    {"gd25q64c", 0xc84017, 0, 65536, 128, SECT_64K, 3, 3},	
++	{"gd25q128c", 0xc84018, 0, 65536, 256, SECT_64K, 3, 3},
++	{"gd25q256c", 0xc84019, 0, 65536, 512, SECT_64K, 4, 3},
++	/* Micron */
++	{"N25q256", 0x20BA19, 0, 65536, 512, SECT_64K, 4, 4},
++#else
++    /* winbond */
++    {"w25q32bv", 0xef4016, 0, 4096, 1024, SECT_4K, 3, 1},
++    {"w25X64V", 0xef3017, 0, 4096, 2048, SECT_4K, 3, 1},
++    {"w25Q64F", 0xef4017, 0, 4096, 2048, SECT_4K, 3, 1},
++    {"w25q128bv", 0xef4018, 0, 4096, 4096, SECT_4K, 3, 1},
++    /* mxic */
++    {"MX25L12845E", 0xc22018, 0, 4096, 4096, SECT_4K, 3, 2},
++    {"MX25L25635E", 0xc22019, 0, 4096, 8192, SECT_4K, 4, 2},
++    /* eon */
++    {"en25q128", 0x1c3018, 0, 4096, 4096, SECT_4K, 3, 3},
++    {"en25qh256", 0x1c7019, 0, 4096, 8192, SECT_4K, 4, 3},
++#endif
++#if 0                           //ratbert
++    /* Atmel -- some are (confusingly) marketed as "DataFlash" */
++    {"at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K,},
++    {"at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K,},
++
++    {"at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K,},
++    {"at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K,},
++
++    {"at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K,},
++    {"at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K,},
++    {"at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K,},
++    {"at26df321", 0x1f4701, 0, 64 * 1024, 64, SECT_4K,},
++
++    /* Spansion -- single (large) sector size only, at least
++     * for the chips listed here (without boot sectors).
++     */
++    {"s25sl004a", 0x010212, 0, 64 * 1024, 8,},
++    {"s25sl008a", 0x010213, 0, 64 * 1024, 16,},
++    {"s25sl016a", 0x010214, 0, 64 * 1024, 32,},
++    {"s25sl032a", 0x010215, 0, 64 * 1024, 64,},
++    {"s25sl064a", 0x010216, 0, 64 * 1024, 128,},
++    {"s25sl12800", 0x012018, 0x0300, 256 * 1024, 64,},
++    {"s25sl12801", 0x012018, 0x0301, 64 * 1024, 256,},
++
++    /* SST -- large erase sizes are "overlays", "sectors" are 4K */
++    {"sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K,},
++    {"sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K,},
++    {"sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K,},
++    {"sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K,},
++
++    /* ST Microelectronics -- newer production may have feature updates */
++    {"w25q05", 0x202010, 0, 32 * 1024, 2,},
++    {"w25q10", 0x202011, 0, 32 * 1024, 4,},
++    {"w25q20", 0x202012, 0, 64 * 1024, 4,},
++    {"w25q40", 0x202013, 0, 64 * 1024, 8,},
++    {"w25q80", 0, 0, 64 * 1024, 16,},
++    {"w25q16", 0x202015, 0, 64 * 1024, 32,},
++    {"w25q32", 0x202016, 0, 64 * 1024, 64,},
++    {"w25q64", 0x202017, 0, 64 * 1024, 128,},
++    {"w25q128", 0x202018, 0, 256 * 1024, 64,},
++
++    {"m45pe80", 0x204014, 0, 64 * 1024, 16,},
++    {"m45pe16", 0x204015, 0, 64 * 1024, 32,},
++
++    {"w25qe80", 0x208014, 0, 64 * 1024, 16,},
++    {"w25qe16", 0x208015, 0, 64 * 1024, 32, SECT_4K,},
++
++    /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
++    {"w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K,},
++    {"w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K,},
++    {"w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K,},
++    {"w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K,},
++    {"w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K,},
++    {"w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K,},
++    {"w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K,},
++    {"w25p16", 0xef2015, 0, 64 * 1024, 32,},    //ratbert
++#endif
++};
++
++static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
++{
++    u8 id[4];
++    u32 jedec;
++    u32 tmp;
++    struct flash_info *info;
++    struct ftspi020_cmd spi_cmd;
++    struct spi_transfer t;
++    struct spi_message m;
++
++    pr_debug("%s: %s\n", dev_name(&spi->dev), __func__);
++
++    spi_message_init(&m);
++    memset(&t, 0, (sizeof t));
++
++    t.tx_buf = &spi_cmd;
++    t.bits_per_word = 8;
++    spi_message_add_tail(&t, &m);
++
++    memset(&spi_cmd, 0, sizeof(struct ftspi020_cmd));
++    spi_cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++    spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    spi_cmd.data_cnt = 4;
++    spi_cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_RDID);
++    spi_cmd.write_en = FTSPI020_CMD3_READ;
++
++    spi_cmd.rx_buf = &id;
++    spi_sync(spi, &m);
++
++    if (m.status < 0) {
++        printk(KERN_ERR "%s: error %d reading JEDEC ID\n", dev_name(&spi->dev), m.actual_length);
++        return NULL;
++    }
++
++    jedec = id[0];
++    jedec = jedec << 8;
++    jedec |= id[1];
++    jedec = jedec << 8;
++    jedec |= id[2];
++
++    pr_debug("SPI flash id[0] = %x, id[1] = %x, id[2] = %x\n", id[0], id[1], id[2]);
++    for (tmp = 0, info = common_spi_flash_data;
++         tmp < ARRAY_SIZE(common_spi_flash_data); tmp++, info++) {
++        if (info->jedec_id == jedec)
++            return info;
++    }
++
++    dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
++    return NULL;
++}
++
++static int partition_check(struct mtd_partition *partitions, sys_header_v2_t *sys_hdr, int page_size, int chip_size)
++{
++    int i, num = 0;
++    int j, A_begin, A_end, B_begin, B_end;
++
++	//block alignment check
++    for(i = 0; i < ARRAY_SIZE(sys_hdr->image); i++){
++        
++        if(sys_hdr->image[i].size == 0)
++    	    continue;
++
++        if(sys_hdr->image[i].addr % page_size){
++    	    printk(KERN_WARNING "Warning............partition %d addr 0x%x not block alignment, one block = 0x%x\n", i, sys_hdr->image[i].addr, page_size);
++    	    partitions[num].offset = BLOCK_ALIGN(sys_hdr->image[i].addr, page_size);
++        } else {
++       	    partitions[num].offset = sys_hdr->image[i].addr;
++       	}
++
++        if(sys_hdr->image[i].size % page_size){
++    	    printk(KERN_WARNING "Warning............partition %d size 0x%x not block alignment, one block = 0x%x\n", i, sys_hdr->image[i].size, page_size);
++    	    partitions[num].size = BLOCK_ALIGN(sys_hdr->image[i].size, page_size);
++        } else {
++      	    partitions[num].size = sys_hdr->image[i].size;
++      	}
++
++        partitions[num].name = sys_hdr->image[i].name;
++	//printk("p[%d] offset = 0x%x, size = 0x%x, name = %s\n", num, (u32)partitions[num].offset, (u32)partitions[num].size, partitions[num].name);
++        num++;
++    }
++
++    //overlap check
++    for(i = 0; i < (num - 1); i++){
++        A_begin = sys_hdr->image[i].addr;
++        A_end = A_begin + sys_hdr->image[i].size;
++	    //printk("A %x,%x\n",A_begin,A_end);
++			
++        for(j = (i + 1); j < num; j++){
++            B_begin = sys_hdr->image[j].addr;
++	        B_end = B_begin + sys_hdr->image[j].size;
++		    //printk("B %x,%x\n",B_begin,B_end);
++				      
++	        /* A_end between B_end and B_begin */
++	        if((B_end >= A_end) && (A_end > B_begin))
++	      	    goto check_fail;
++	        /* A_begin between B_end and B_begin */
++	        if((B_end > A_begin) && (A_begin >= B_begin))
++	      	    goto check_fail;
++	        /* B between A */
++	        if((A_end >= B_end) && (B_begin >= A_begin))
++	      	    goto check_fail;	      	      	
++	    }
++    }
++    
++#ifdef CONFIG_PLATFORM_GM8210
++    if(sys_hdr->addr != 0) {
++        partitions[num].offset = sys_hdr->addr;
++        partitions[num].size = sys_hdr->size;
++        partitions[num].name = sys_hdr->name;
++        num++;        
++    }
++#endif 
++    
++    /* total flash map to last MTD
++     */
++    partitions[num].offset = 0;
++    partitions[num].size = chip_size;
++
++    partitions[num].name = "ALL";
++    num++;
++    return num;
++    
++check_fail:
++    printk(KERN_WARNING "Warning ============> partition %d overlap with %d\n", i, j);
++    return num;
++}
++
++/*
++ * 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 common_spi_flash_probe(struct spi_device *spi)
++{
++    struct flash_platform_data *data;
++    struct common_spi_flash *flash;
++    struct flash_info *info;
++    struct mtd_partition *parts = NULL;
++    int nr_parts = 0;
++    size_t retlen[1], i;
++
++    pr_debug("%s: %s\n", dev_name(&spi->dev), __func__);
++
++    /* 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 = common_spi_flash_data;
++             i < ARRAY_SIZE(common_spi_flash_data); i++, info++) {
++            if (strcmp(data->type, info->name) == 0)
++                break;
++        }
++
++        /* unrecognized chip? */
++        if (i == ARRAY_SIZE(common_spi_flash_data)) {
++            printk(KERN_ERR "%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->spi = spi;
++    mutex_init(&flash->lock);
++    dev_set_drvdata(&spi->dev, flash);
++
++    if (data && data->name)
++        flash->mtd.name = "nor-flash";//u-boot commandline
++    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 = common_spi_flash_erase;
++    flash->mtd.read = common_spi_flash_read;
++    flash->mtd.write = common_spi_flash_write;
++    flash->mode_3_4 = info->mode_3_4;
++    flash->flash_type = info->flash_type;
++
++    if (flash->mode_3_4 == 3){
++        OPCODE_READ_COMMAND = OPCODE_FAST_READ_DUAL;//0x0B
++        OPCODE_WRITE_COMMAND = 0x02;
++        OPCODE_ERASE_COMMAND = 0xD8;
++    } else {
++        switch (flash->flash_type){
++            case 1:	//winbond
++                OPCODE_READ_COMMAND = OPCODE_FAST_READ_DUAL;//0x0B
++                OPCODE_WRITE_COMMAND = 0x02;
++                OPCODE_ERASE_COMMAND = 0xD8;
++                break;
++            case 2:	//MXIC
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)                
++                if (platform_spi_four_byte_mode()) {	//3 byte mode
++                    OPCODE_READ_COMMAND = OPCODE_FAST_READ_DUAL;//0x0B
++                    OPCODE_WRITE_COMMAND = 0x02;
++                    OPCODE_ERASE_COMMAND = 0xD8;
++                } else {	//4 byte mode
++                    OPCODE_READ_COMMAND = 0x0C;//0x3C
++                    OPCODE_WRITE_COMMAND = 0x12;
++                    OPCODE_ERASE_COMMAND = 0xDC;
++                }
++                break;
++#else
++                OPCODE_READ_COMMAND = 0x0B;
++                OPCODE_WRITE_COMMAND = 0x02;
++                OPCODE_ERASE_COMMAND = 0xD8;                
++#endif                
++            case 3:	//EON, ESMT, spansion, GD
++                OPCODE_READ_COMMAND = 0x0B;
++                OPCODE_WRITE_COMMAND = 0x02;
++                OPCODE_ERASE_COMMAND = 0xD8;
++                break;                
++            case 4:	//Micron
++                OPCODE_READ_COMMAND = 0x0C;
++                OPCODE_WRITE_COMMAND = 0x12;
++                OPCODE_ERASE_COMMAND = 0xD8;
++                break; 
++            default:
++                OPCODE_READ_COMMAND = 0x0B;
++                OPCODE_WRITE_COMMAND = 0x02;
++                OPCODE_ERASE_COMMAND = 0xD8;
++                break;
++        }
++        change_4b(flash, 1);
++    }
++#ifdef CONFIG_SPI_QUAD_MODE
++    flash_set_quad_enable(flash);
++#endif
++
++    /* prefer "small sector" erase if possible */
++    if (info->flags & SECT_4K) {
++        flash->erase_opcode = OPCODE_SE;
++        flash->mtd.erasesize = 4096;
++        printk(KERN_INFO "ERASE SECTOR 4K\n");
++    } else if (info->flags & SECT_64K) {
++        flash->erase_opcode = OPCODE_ERASE_COMMAND;
++        flash->mtd.erasesize = 64 * 1024;
++        printk(KERN_INFO "ERASE SECTOR 64K\n");
++    } else {
++        flash->erase_opcode = OPCODE_CHIP_ERASE;
++        flash->mtd.erasesize = flash->mtd.size;
++    }
++
++    dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name, (int)(flash->mtd.size / 1024));
++
++    pr_debug("mtd .name = %s, .size = 0x%.8x (%uMiB) "
++             ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
++             flash->mtd.name,
++             (int)flash->mtd.size, (int)(flash->mtd.size / (1024 * 1024)),
++             (int)flash->mtd.erasesize, (int)(flash->mtd.erasesize / 1024),
++             flash->mtd.numeraseregions);
++
++    if (flash->mtd.numeraseregions)
++        for (i = 0; i < flash->mtd.numeraseregions; i++)
++            pr_debug("mtd.eraseregions[%d] = { .offset = 0x%.8x, "
++                     ".erasesize = 0x%.8x (%uKiB), "
++                     ".numblocks = %d }\n",
++                     i, (u32) flash->mtd.eraseregions[i].offset,
++                     (int)flash->mtd.eraseregions[i].erasesize,
++                     (int)(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).
++     */
++
++    /* read system header
++     */
++    flash->sys_hdr = kzalloc(sizeof(struct sys_header_v2), GFP_KERNEL);
++
++    if (flash->sys_hdr == NULL) {
++        printk(KERN_ERR "Warning............SPI: can't alloc memory");
++        return -ENOMEM;
++    }
++
++    if (common_spi_flash_read
++        (&flash->mtd, 0x0, sizeof(struct sys_header_v2), retlen, (u_char *) flash->sys_hdr) < 0)
++        printk(KERN_ERR "SPI: read system header fail!");
++
++    //printk("addr=%x, size=%x\n",flash->sys_hdr->image[0].addr, flash->sys_hdr->image[0].size);//???
++    if (flash->sys_hdr->image[0].size == 0) {
++        printk(KERN_WARNING "Not find partition message, use default setting\n");
++
++        flash->sys_hdr->image[0].name[0] = 'a'; //???
++        flash->sys_hdr->image[0].addr = 0x20000;
++        flash->sys_hdr->image[0].size = 0x30000;
++
++        flash->sys_hdr->image[1].name[0] = 'u';
++        flash->sys_hdr->image[1].addr = 0x700000;
++        flash->sys_hdr->image[1].size = 0x100000;
++
++        flash->sys_hdr->image[2].name[0] = 'r';
++        flash->sys_hdr->image[2].addr = 0x00000;
++        flash->sys_hdr->image[2].size = 0x10000;
++
++        for (i = 3; i < 10; i++) {
++            flash->sys_hdr->image[i].addr = 0;
++            flash->sys_hdr->image[i].size = 0;
++        }
++    }
++    nr_parts =
++        partition_check(ftspi020_partition_info, flash->sys_hdr, sizeof(struct sys_header_v2),
++                        flash->mtd.size);
++    parts = ftspi020_partition_info;
++
++    if (nr_parts <= 0 && data && data->parts) {
++        parts = data->parts;
++        nr_parts = data->nr_parts;
++    }
++
++    if (nr_parts > 0) {
++        for (i = 0; i < nr_parts; i++) {
++            pr_debug("partitions[%d] = "
++                     "{.name = %s, .offset = 0x%.8x, "
++                     ".size = 0x%.8x (%uKiB) }\n",
++                     i, parts[i].name,
++                     (u32) parts[i].offset, (int)parts[i].size, (int)(parts[i].size / 1024));
++        }
++    }
++    return mtd_device_parse_register(&flash->mtd, part_probes, 0, parts, nr_parts);
++}
++
++static int __devexit common_spi_flash_remove(struct spi_device *spi)
++{
++    struct common_spi_flash *flash = dev_get_drvdata(&spi->dev);
++    int status;
++
++    /* Clean up MTD stuff. */
++    status = mtd_device_unregister(&flash->mtd);
++    if (status == 0) {
++        kfree(flash->sys_hdr);
++        kfree(flash);
++    }
++    return 0;
++}
++
++static struct spi_driver common_spi_flash_driver = {
++    .driver = {
++               .name = SPI_NAME,
++               .bus = &spi_bus_type,
++               .owner = THIS_MODULE,
++               },
++    .probe = common_spi_flash_probe,
++    .remove = __devexit_p(common_spi_flash_remove),
++
++    /* REVISIT: many of these chips have deep power-down modes, which
++     * should clearly be entered on suspend() to minimize power use.
++     * And also when they're otherwise idle...
++     */
++};
++
++static int __init common_spi_flash_init(void)
++{
++    /* add spi device here, when add corresponding spi driver, they will bind together
++     */
++    spi_register_board_info(spi_devs_info, ARRAY_SIZE(spi_devs_info));
++
++    return spi_register_driver(&common_spi_flash_driver);
++}
++
++static void common_spi_flash_exit(void)
++{
++    spi_unregister_driver(&common_spi_flash_driver);
++}
++
++module_init(common_spi_flash_init);
++module_exit(common_spi_flash_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Mike Lavender");
++MODULE_DESCRIPTION("MTD SPI driver for SPI flash chips");
+diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
+index 6c5c431c..2215896d 100644
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -392,6 +392,12 @@ config MTD_H720X
+ 	  This enables access to the flash chips on the Hynix evaluation boards.
+ 	  If you have such a board, say 'Y'.
+ 
++config MTD_GM
++	tristate "GM NOR flash mappings"
++	depends on ARM && MTD_CFI
++	help
++	  This enables access to the NOR flash on the GM board.
++
+ # This needs CFI or JEDEC, depending on the cards found.
+ config MTD_PCI
+ 	tristate "PCI MTD driver"
+diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
+index 68a9a91d..2f5a8423 100644
+--- a/drivers/mtd/maps/Makefile
++++ b/drivers/mtd/maps/Makefile
+@@ -57,3 +57,4 @@ obj-$(CONFIG_MTD_VMU)		+= vmu-flash.o
+ obj-$(CONFIG_MTD_GPIO_ADDR)	+= gpio-addr-flash.o
+ obj-$(CONFIG_MTD_LATCH_ADDR)	+= latch-addr-flash.o
+ obj-$(CONFIG_MTD_LANTIQ)	+= lantiq-flash.o
++obj-$(CONFIG_MTD_GM)            += cpe_flash.o
+diff --git a/drivers/mtd/maps/cpe_flash.c b/drivers/mtd/maps/cpe_flash.c
+new file mode 100644
+index 00000000..339abb0d
+--- /dev/null
++++ b/drivers/mtd/maps/cpe_flash.c
+@@ -0,0 +1,249 @@
++/*
++ * Flash on CPE mx29lv
++ *
++ * $Id: cpe-flash.c,v
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/pmu.h>
++#include <asm/io.h>
++
++static struct mtd_info *mymtd = NULL;
++
++#define BUSWIDTH_8BIT   1
++#define BUSWIDTH_16BIT  2
++
++#if defined(CONFIG_PLATFORM_GM8181) || defined(CONFIG_PLATFORM_GM8210_M)
++struct map_info physmap_map = {
++		.name =		"GM 8-bit flash device",
++		.bankwidth = BUSWIDTH_8BIT,
++};
++#else
++struct map_info physmap_map = {
++		.name =		"GM 16-bit flash device",
++		.bankwidth = BUSWIDTH_16BIT,
++};
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8181) || defined(CONFIG_PLATFORM_GM8126)
++struct mtd_partition flash_parts[] = {
++
++	{
++		.name =		"BurnIn",	// for system usage
++		.offset	=	0x0,		// Burn-in ,start addr MTD_PA_BASE
++		.size =		0x100000	// 1MB
++	},	
++	{
++		.name =		"User",		// free for use
++		.offset =	0x100000,	// start addr MTD_PA_BASE + 0x100000
++		.size =		0x100000	// 1MB
++	},
++	{
++		.name =		"UBoot",	// for system usage
++		.offset	=	0x200000,	// start addr MTD_PA_BASE + 0x200000
++		.size =		0x40000	    // 256K
++	},
++	{
++		.name =		"Linux",	// for system usage
++		.offset	=	0x240000,	// Kernel/Root FS ,start addr MTD_PA_BASE + 0x240000
++		.size =		0xDC0000	// 13.75MB
++	}
++};
++#elif defined(CONFIG_PLATFORM_GM8210_M)
++extern int platform_check_nandc(void);
++struct mtd_partition flash_parts[] = {
++    {
++     .name = "Linux Section",           
++     .offset = 0x500000,
++     .size = 0x500000},
++    {
++     .name = "User Section",            
++     .offset = 0xF00000,
++     .size = 0x100000},
++    {
++     .name = "UBoot Section",         
++     .offset = 0,         
++     .size = 0x40000},
++    {
++     .name = "Slave Section",         
++     .offset = 0xA0000,          
++     .size = 0x60000},
++    {
++     .name = "Audio Section",        
++     .offset = 0x60000,         
++     .size = 0x40000},          
++    {
++     .name = "CFG Section",           // for MAC usage
++     .offset = 0x40000,
++     .size = 0x20000},  
++};
++
++struct mtd_partition big_flash_parts[] = {
++    {
++     .name = "Linux Section",           
++     .offset = 0x500000,
++     .size = 0x500000},
++    {
++     .name = "User Section",            
++     .offset = 0x1F00000,
++     .size = 0x100000},
++    {
++     .name = "Loader Section",
++     .offset = 0x1000,
++     .size = 0x5000},
++    {
++     .name = "UBoot Section",         
++     .offset = 0,         
++     .size = 0x22000},
++    {
++     .name = "Slave Section",         
++     .offset = 0x6A000,          
++     .size = 0x64000},
++    {
++     .name = "Audio Section",        
++     .offset = 0x2A000,         
++     .size = 0x24000},          
++    {
++     .name = "CFG Section",           // for MAC usage
++     .offset = 0x22000,
++     .size = 0x20000}, 
++};
++#define BIG_PARTITION_COUNT (sizeof(big_flash_parts)/sizeof(struct mtd_partition))
++
++#endif /* mtd_partition */
++
++#define PARTITION_COUNT (sizeof(flash_parts)/sizeof(struct mtd_partition))
++
++#ifdef CONFIG_PLATFORM_GM8181	
++static pmuReg_t pmu_reg[] = {
++    {0x50, 0x3, 0x3, 0, 0}, 
++};
++
++static pmuRegInfo_t pmu_reg_info = {
++    DRV_NAME, 
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_PLL1,
++    &pmu_reg[0]
++};
++#endif
++
++static int __init init_flagadm(void)
++{
++	int mode = 0;
++	unsigned int FLASH_SIZE = 0, FLASH_PA_ADDR = 0, FLASH_VA_ADDR = 0;
++
++#if defined(CONFIG_PLATFORM_GM8181)
++	//calculate flash size, if you use 2 chip or 1 chip is not flash, you can define the size directly
++	value = *(volatile unsigned int *)(SRAM_FTSMC010_VA_BASE);	
++	i = (value & 0xF0) >> 4;    //read BNK_SIZE
++	if (i >= 11)
++		FLASH_SIZE = 1 << (i + 4);
++	else
++		FLASH_SIZE = 1 << (i + 20);
++
++	FLASH_SIZE = FLASH_SIZE * (1 << (value & 0x3));
++
++	/* 00: GPIO[7:6]/SMC pin-out, 10: NAND pin out */
++  if (ftpmu010_register_reg(&pmu_reg_info) < 0) {
++      printk("SMC: %s fail \n", __FUNCTION__);
++      return -1;
++  }
++  ftpmu010_write_reg(mac_fd, 0x50, 0, 0x3);	
++  	
++	FLASH_PA_ADDR = (*(volatile unsigned int *)AHBC_FTAHBC010_PA_BASE) & 0x000FFFFF;
++	FLASH_VA_ADDR = MTD_VA_BASE;
++
++	mode = (*((unsigned int *)SRAM_FTSMC010_VA_BASE) & 0x3);
++	    
++#elif defined(CONFIG_PLATFORM_GM8210_M)	
++	unsigned int value = 0, i = 0;
++	unsigned int smc_va_base_addr, tmp_base_addr;
++	
++	if (platform_check_flash_type() < 1){
++		printk("Pin mux for SPI/NAND Flash\n");
++   	return -ENXIO;
++	}
++	//calculate flash size, if you use 2 chip or 1 chip is not flash, you can define the size directly
++	smc_va_base_addr = (unsigned int)ioremap_nocache(SMC_FTSMC010_PA_BASE, SMC_FTSMC010_PA_SIZE);
++	value = *(volatile unsigned int *)(smc_va_base_addr);	
++	i = (value & 0xF0) >> 4;    //read BNK_SIZE
++	if (i >= 11)
++		FLASH_SIZE = 1 << (i + 4);
++	else
++		FLASH_SIZE = 1 << (i + 20);
++
++  FLASH_SIZE = FLASH_SIZE * (1 << (value & 0x3));
++
++  tmp_base_addr = (unsigned int)ioremap_nocache(AHBC_FTAHBC020_PA_BASE, AHBC_FTAHBC020_PA_SIZE);
++  FLASH_PA_ADDR = (*(volatile unsigned int *)(tmp_base_addr + 0x10)) & 0xFFF00000;
++  FLASH_VA_ADDR = (unsigned int)ioremap_nocache(FLASH_PA_ADDR, FLASH_SIZE);
++
++	mode = value & 0x3;
++	      
++#endif /* CONFIG_PLATFORM_GM8181 */
++
++	printk(KERN_NOTICE "Flash device: SIZE 0x%x at ADDR 0x%x\n",
++			FLASH_SIZE, FLASH_PA_ADDR);
++
++	physmap_map.phys = FLASH_PA_ADDR;
++	physmap_map.size = FLASH_SIZE;
++
++  if((mode & 0x3) == 0)
++   	   printk("Flash is 8 bit mode\n");
++  else if ((mode & 0x3) == 1)
++     printk("Flash is 16 bit mode\n");
++  else
++     printk("This Flash mode not support\n");
++
++  printk("MTD: Init %s: (size=%dMB) start at address=0x%x\n", physmap_map.name, (FLASH_SIZE/1024)/1024, FLASH_VA_ADDR);
++	physmap_map.virt = (void __iomem *)FLASH_VA_ADDR;
++
++	if (!physmap_map.virt) {
++		printk("MTD: ioremap fail\n");
++		return -EIO;
++	}
++
++	simple_map_init(&physmap_map);
++	
++	mymtd = do_map_probe("cfi_probe", &physmap_map);
++	if (mymtd) {
++		mymtd->owner = THIS_MODULE;
++#ifdef CONFIG_PLATFORM_GM8210_M
++		if(FLASH_SIZE > (16 * 1024 * 1024))
++			mtd_device_register(mymtd, big_flash_parts, BIG_PARTITION_COUNT);
++		else
++			mtd_device_register(mymtd, flash_parts, PARTITION_COUNT);
++#else		
++		mtd_device_register(mymtd, flash_parts, PARTITION_COUNT);
++#endif	
++		printk("MTD flash device initialized\n");
++		return 0;
++	}
++	else
++		printk("MTD flash device initialized fail\n");
++
++	return -ENXIO;
++}
++
++static void __exit cleanup_flagadm(void)
++{
++	if (mymtd) {
++		mtd_device_unregister(mymtd);
++		map_destroy(mymtd);
++	}
++	if (physmap_map.virt) {
++		physmap_map.virt = 0;
++	}
++}
++
++module_init(init_flagadm);
++module_exit(cleanup_flagadm);
++
++MODULE_AUTHOR("GM Corp.");
++MODULE_LICENSE("GM License");
+diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
+index af659123..29f8601a 100644
+--- a/drivers/mtd/mtdblock.c
++++ b/drivers/mtd/mtdblock.c
+@@ -110,6 +110,53 @@ static int erase_write (struct mtd_info *mtd, unsigned long pos,
+ 	return 0;
+ }
+ 
++int erase_write_block0 (struct mtd_info *mtd, unsigned long pos,
++			int len, const char *buf)
++{
++	struct erase_info erase;
++	DECLARE_WAITQUEUE(wait, current);
++	wait_queue_head_t wait_q;
++	size_t retlen;
++	int ret;
++
++	/*
++	 * First, let's erase the flash block.
++	 */
++
++	init_waitqueue_head(&wait_q);
++	erase.mtd = mtd;
++	erase.callback = erase_callback;
++	erase.addr = pos;
++	erase.len = mtd->erasesize;
++	erase.priv = (u_long)&wait_q;
++
++	set_current_state(TASK_INTERRUPTIBLE);
++	add_wait_queue(&wait_q, &wait);
++
++	ret = mtd_erase(mtd, &erase);
++	if (ret) {
++		set_current_state(TASK_RUNNING);
++		remove_wait_queue(&wait_q, &wait);
++		printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] "
++				     "on \"%s\" failed\n",
++			pos, len, mtd->name);
++		return ret;
++	}
++
++	schedule();  /* Wait for erase to finish. */
++	remove_wait_queue(&wait_q, &wait);
++
++	/*
++	 * Next, write the data to flash.
++	 */
++
++	ret = mtd_write(mtd, pos, len, &retlen, buf);
++	if (ret)
++		return ret;
++	if (retlen != len)
++		return -EIO;
++	return 0;
++}
+ 
+ static int write_cached_data (struct mtdblk_dev *mtdblk)
+ {
+diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
+index a3d44c34..d9056048 100644
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -30,9 +30,14 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/err.h>
++#include <linux/sched.h>
+ 
+ #include "mtdcore.h"
+ 
++#ifdef CONFIG_MTD_NAND_FTSPINAND020
++#define CONFIG_NAND_DISTRUB
++#endif
++
+ /* Our partition linked list */
+ static LIST_HEAD(mtd_partitions);
+ static DEFINE_MUTEX(mtd_partitions_mutex);
+@@ -51,6 +56,173 @@ struct mtd_part {
+  */
+ #define PART(x)  ((struct mtd_part *)(x))
+ 
++#ifdef CONFIG_NAND_DISTRUB
++extern int read_ecc_limit;
++
++static void erase_callback(struct erase_info *done)
++{
++	wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
++	wake_up(wait_q);
++}
++
++/* mode: 0 is read, 1 is write */
++int swap_block(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, char mode, const u_char *buf)
++{
++	unsigned char *block_mem, *block_mem_tmp;
++	loff_t start_addr, block_size = mtd->erasesize, page_size = mtd->writesize;
++	struct erase_info erase;
++	DECLARE_WAITQUEUE(wait, current);
++	wait_queue_head_t wait_q;
++	int res = 0, i, offset;
++	size_t rrn = *retlen;
++
++	start_addr = (int)from - ((int)from % (int)block_size);
++	block_mem = kzalloc(block_size, GFP_KERNEL);
++
++	//printk("addr = 0x%x, 0x%x, 0x%x\n", (int)start_addr, (int)from, start_addr);
++	if(mode) {
++		if(start_addr != from) {
++			/* read block data */
++			res = mtd_read(mtd, start_addr, from - start_addr, &rrn, block_mem);
++			if(res)
++				goto swap_err;			
++		}
++		/* data we want to write */
++		offset = (int)from % (int)block_size;
++		memcpy(block_mem + offset, buf, len);
++
++		/* mark block bad */
++		res = mtd_block_markbad(mtd, start_addr);
++		if(res)
++			goto swap_err;
++	} else {
++		/* read one block data */
++		res = mtd_read(mtd, start_addr, block_size, &rrn, block_mem);
++		if(res)
++			goto swap_err;
++	}
++
++	/* erase block */
++	//printk("erase addr = 0x%x\n", (unsigned int)start_addr);
++	init_waitqueue_head(&wait_q);
++	erase.mtd = mtd;
++	erase.callback = erase_callback;
++	erase.addr = (unsigned long)start_addr;
++	erase.len = (unsigned long)block_size;
++	erase.priv = (u_long)&wait_q;
++
++	set_current_state(TASK_INTERRUPTIBLE);
++	add_wait_queue(&wait_q, &wait);
++
++	res = mtd_erase(mtd, &erase);
++
++	schedule();  /* Wait for erase to finish. */
++	remove_wait_queue(&wait_q, &wait);
++
++	if(res)
++		goto swap_err;
++
++	/* write block */
++	block_mem_tmp = block_mem;
++
++	for(i = 0; i < ((int)block_size / (int)page_size); i++) {
++		//printk("addr = 0x%x, 0x%x\n", (unsigned int)start_addr, *(unsigned int *)block_mem_tmp);
++		res = mtd_write(mtd, start_addr, page_size, &rrn, block_mem_tmp);
++		if(res)
++			goto swap_err;
++
++		start_addr += page_size;
++		block_mem_tmp += page_size;
++		
++		if(mode && (start_addr > from))
++			break;
++	}
++
++swap_err:
++	kfree(block_mem);
++	return res;
++}
++
++int mtd_ftl_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
++		u_char *buf)
++{
++	loff_t start_addr, block_size = mtd->erasesize;
++	size_t read_len;
++	u_char *buf_tmp;
++	int res = 0;
++
++	start_addr = (int)from % (int)block_size;
++	buf_tmp = buf;
++	while(len > 0) {    
++    	read_ecc_limit = 0;
++
++		if ((start_addr + len) > block_size) {
++			printk("read %d....................\n", (int)(start_addr + len));
++			read_len = block_size - start_addr;
++			res = mtd_read(mtd, from, read_len, retlen, buf_tmp);
++			from += read_len;
++			buf_tmp += (u_char)read_len;
++			len -= read_len;
++			start_addr = 0;
++		} else {
++			res = mtd_read(mtd, from, len, retlen, buf_tmp);
++			len = 0;
++		}
++
++		/* can't recovery */
++		if (unlikely(res))
++			break;
++
++		if (read_ecc_limit) {
++			printk("NAND read recover for ECC issue...\n");
++			res = swap_block(mtd, from, len, retlen, 0, NULL);
++			if(res)
++				break;
++		}
++	}
++
++	return res;
++}
++
++int mtd_ftl_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
++               const u_char *buf)
++{
++	int res = 0;
++
++	res = mtd_write(mtd, to, len, retlen, buf);
++	if(!res)
++		goto write_exit;
++
++	printk("\nwrite recover addr = 0x%x, len = 0x%x\n", (int)to, (int)len);
++	
++	res = swap_block(mtd, to, len, retlen, 1, buf);
++
++write_exit:
++	return res;
++}
++
++int mtd_ftl_erase(struct mtd_info *mtd, struct erase_info *instr) 
++{
++	int res = 0;
++
++	res = mtd_erase(mtd, instr);
++	if(!res)
++		goto erase_exit;
++
++	printk("\nerase recover addr = 0x%x\n", (int)instr->addr);
++
++	/* mark block bad */
++	res = mtd_block_markbad(mtd, instr->addr);
++	if(res)
++		goto erase_exit;
++
++	res = mtd_erase(mtd, instr);
++
++erase_exit:
++	return res;
++}
++
++#endif
+ 
+ /*
+  * MTD methods which simply translate the effective address and pass through
+@@ -70,7 +242,14 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
+ 		len = 0;
+ 	else if (from + len > mtd->size)
+ 		len = mtd->size - from;
+-	res = mtd_read(part->master, from + part->offset, len, retlen, buf);
++
++#ifdef CONFIG_NAND_DISTRUB
++	if (mtd->type == MTD_NANDFLASH)
++		res = mtd_ftl_read(part->master, from + part->offset, len, retlen, buf);
++	else
++#endif
++		res = mtd_read(part->master, from + part->offset, len, retlen, buf);
++
+ 	if (unlikely(res)) {
+ 		if (mtd_is_bitflip(res))
+ 			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
+@@ -186,7 +365,13 @@ static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
+ 		len = 0;
+ 	else if (to + len > mtd->size)
+ 		len = mtd->size - to;
+-	return mtd_write(part->master, to + part->offset, len, retlen, buf);
++
++#ifdef CONFIG_NAND_DISTRUB
++	if (mtd->type == MTD_NANDFLASH)
++		return mtd_ftl_write(part->master, to + part->offset, len, retlen, buf);
++	else
++#endif
++		return mtd_write(part->master, to + part->offset, len, retlen, buf);
+ }
+ 
+ static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
+@@ -251,7 +436,12 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
+ 	if (instr->addr >= mtd->size)
+ 		return -EINVAL;
+ 	instr->addr += part->offset;
+-	ret = mtd_erase(part->master, instr);
++#ifdef CONFIG_NAND_DISTRUB
++	if (mtd->type == MTD_NANDFLASH)
++		ret = mtd_ftl_erase(part->master, instr);
++	else
++#endif
++		ret = mtd_erase(part->master, instr);
+ 	if (ret) {
+ 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
+ 			instr->fail_addr -= part->offset;
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 31b034b7..f6404aa8 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -184,6 +184,62 @@ config MTD_NAND_PPCHAMELEONEVB
+ 	depends on PPCHAMELEONEVB && BROKEN
+ 	help
+ 	  This enables the NAND flash driver on the PPChameleon EVB Board.
++	  
++config MTD_NAND_FTNANDC023
++	tristate "NAND Flash NANDC023 support for GM SoC"
++	depends on ARCH_GM || ARCH_GM_DUO
++	help
++	  This enable the NAND flash controller on the GM SoC
++
++config NAND_USE_AHBDMA
++	bool "Use AHB DMA transfer"
++	depends on MTD_NAND_FTNANDC023
++	help
++	  Use AHB DMA to transfer data instead of PIO
++
++config NAND_USE_AXIDMA
++	bool "Use AXI DMA transfer"
++	depends on MTD_NAND_FTNANDC023
++	help
++	  Use AXI DMA to transfer data instead of PIO
++
++config MTD_NAND_FTNANDC024V2
++	tristate "NAND Flash NANDC024 v2 support for GM SoC"
++	depends on ARCH_GM
++	help
++	  This enable the NAND flash controller on the GM SoC
++
++config NAND_V2_USE_AHBDMA
++	bool "Use AHB DMA transfer"
++	depends on MTD_NAND_FTNANDC024V2 && !MMC_SDHCI
++	help
++	  Use AHB DMA to transfer data instead of PIO
++
++config MTD_NAND_FTSPINAND020
++	tristate "SPI NAND Flash support for GM SoC"
++	depends on ARCH_GM || ARCH_GM_SMP
++	help
++	  This enable the SPI flash controller on the GM SoC
++
++config SPI_NAND_USE_AHBDMA
++	bool "Use AHB DMA transfer"
++	depends on MTD_NAND_FTSPINAND020
++	help
++	  Use AHB DMA to transfer data instead of PIO
++
++config FTNANDC023_DEBUG
++	int "FTNANDC023 driver debugging verbosity (0 = quiet, 2 = noisy)"
++	depends on MTD_NAND_FTNANDC023
++	range 0 2
++	default "0"
++	help
++	  print debug information for FTNANDC023
++
++config GPIO_WP
++	bool "Use GPIO to control write protect"
++	depends on MTD_NAND_FTNANDC023
++	help
++	  Use GPIO to control write protect
+ 
+ config MTD_NAND_S3C2410
+ 	tristate "NAND Flash support for Samsung S3C SoCs"
+diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
+index 618f4ba2..621abd99 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -7,7 +7,13 @@ obj-$(CONFIG_MTD_NAND_ECC)		+= nand_ecc.o
+ obj-$(CONFIG_MTD_NAND_BCH)		+= nand_bch.o
+ obj-$(CONFIG_MTD_NAND_IDS)		+= nand_ids.o
+ obj-$(CONFIG_MTD_SM_COMMON) 		+= sm_common.o
+-
++obj-$(CONFIG_MTD_NAND_FTNANDC023) 	+= ftnandc023v2_nand.o
++obj-$(CONFIG_MTD_NAND_FTNANDC024V2) 	+= ftnandc024v2_nand.o
++ifeq ($(CONFIG_PLATFORM_GM8220),y)
++obj-$(CONFIG_MTD_NAND_FTSPINAND020) 	+= ftspi020_nand_v2.o
++else
++obj-$(CONFIG_MTD_NAND_FTSPINAND020) 	+= ftspi020_nand.o
++endif
+ obj-$(CONFIG_MTD_NAND_CAFE)		+= cafe_nand.o
+ obj-$(CONFIG_MTD_NAND_SPIA)		+= spia.o
+ obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o
+diff --git a/drivers/mtd/nand/ftnandc023v2_nand.c b/drivers/mtd/nand/ftnandc023v2_nand.c
+new file mode 100644
+index 00000000..618ae48a
+--- /dev/null
++++ b/drivers/mtd/nand/ftnandc023v2_nand.c
+@@ -0,0 +1,2520 @@
++/*
++ * FTNANDC023 NAND driver
++ *
++ * 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 <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/vmalloc.h>
++#include <linux/dma-mapping.h>
++#include <linux/jiffies.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/board.h>
++#include <mach/ftpmu010.h>
++#include <mach/fmem.h>
++#include <linux/gpio.h>
++#include "ftnandc023v2_nand.h"
++#include <linux/delay.h>
++/*
++ * Local function or variables declaration
++ */
++//#define CONFIG_NAND_USE_AXIDMA
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++#include <linux/dmaengine.h>
++
++#ifdef CONFIG_NAND_USE_AHBDMA
++#include <mach/ftdmac020.h>
++#else
++#include <mach/ftdmac030.h>
++#endif
++
++/////GM8126/////
++#ifdef CONFIG_PLATFORM_GM8126
++#define AHBMASTER_R_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_R_DST   FTDMA020_AHBMASTER_0
++#define AHBMASTER_W_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_W_DST   FTDMA020_AHBMASTER_0
++#define DMA_NANDC_REQ    9
++#endif
++
++/////GM8210/////
++#ifdef CONFIG_PLATFORM_GM8210
++#ifdef CONFIG_NAND_USE_AXIDMA
++#define DMA_NANDC_REQ    2 
++#else
++#define AHBMASTER_R_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_R_DST   FTDMA020_AHBMASTER_0
++#define AHBMASTER_W_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_W_DST   FTDMA020_AHBMASTER_0
++#define DMA_NANDC_REQ    2
++#endif
++
++#endif
++
++/////GM8287/////
++#ifdef CONFIG_PLATFORM_GM8287
++#define AHBMASTER_R_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_R_DST   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_SRC   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_DST   FTDMA020_AHBMASTER_0
++#define DMA_NANDC_REQ    2
++#endif
++
++static void ftnandc023_dma_callback(void *param);
++static volatile unsigned int trigger_flag = 0;
++static wait_queue_head_t nand023_queue;
++#endif 
++
++#define PORTING 
++static int ftnandc023v2_block_markbad(struct mtd_info *mtd, loff_t ofs);
++int ftnandc_read_bbt(struct mtd_info *mtd, loff_t offs);
++static unsigned int ftnandc023v2_get_blockbase(struct mtd_info *mtd, unsigned int base_addr);
++static int nand_fd;
++static int avail_oob_sz = 0;
++
++/*
++ * Macro definitions
++ */
++#define DEFAULT_BLOCK_SIZE  0x20000 
++#define MTD_CFG_SZ          (6 * DEFAULT_BLOCK_SIZE)	//2 block + reserved
++
++#define AHB_Memory_8KByte   (1 << 4)
++#define CONFIG_FTNANDC023_START_CHANNEL     0
++#define BLOCK_ALIGN(base, blk_shift) ((((base) + (0x1 << (blk_shift)) - 1) >> (blk_shift)) << (blk_shift))
++
++#ifdef CONFIG_GPIO_WP
++//#define GPIO_PIN	28
++//#define PIN_NAME	"gpio28"
++#define GPIO_PIN        ((32*2)+30) 
++#define PIN_NAME        "gpio2_30" 
++#endif
++
++extern int root_mtd_num;
++//=============================================================================
++// System Header, size = 512 bytes
++//=============================================================================
++
++#ifdef CONFIG_PLATFORM_GM8126 
++
++static struct mtd_partition PORTING ftnandc023_partition_info[] = {
++    {.name = "Linux Section"},
++    {.name = "User Section",.size = MTDPART_SIZ_FULL},
++    {.name = "Loader Section"},
++    {.name = "Burin Section"},
++    {.name = "UBoot Section"},
++    {.name = "CFG Section"},
++};
++enum { MTD_PART_LINUX, MTD_PART_USER, MTD_PART_LOADER, MTD_PART_BURNIN, MTD_PART_UBOOT,
++        MTD_PART_CFG };
++
++static int  ref_count = 0;
++
++int platform_select_pinmux(int fd, int chip){
++    int ret = 0;
++    volatile int i;
++    
++    if (chip >= 0) {
++        if (ref_count == 0) {
++    	    if (ftpmu010_request_pins(fd, 0x6C, (0x1 << 22), 1) < 0) {
++    		    printk("Warning............NAND request pin failed\n");
++    		    return ret;
++    	    }
++            
++            /* the delay is used to prevent data in the bus from incomplete */
++            for (i = 0; i < 1000; i++) {}            
++            
++            ftpmu010_write_reg(fd, 0x6C, (0x0 << 22), (0x1 << 22));
++        }
++        ref_count ++;
++    }
++    else {
++        ref_count -- ;
++        if (ref_count == 0) {
++            /* chip unselect, the delay is used to prevent data in the bus from incomplete */
++            for (i = 0; i < 1000; i++) {}
++            //ftpmu010_del_lockbits(fd, 0x6C, (0x1 << 22));
++
++            ftpmu010_write_reg(fd, 0x6C, (0x1 << 22), (0x1 << 22)); //to SD
++	    ftpmu010_release_pins(fd, 0x6C, (0x1 << 22));
++        }
++    }
++    
++    return ret;
++}
++
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x38, (0x1 << 5), (0x1 << 5), (0x0 << 5), (0x1 << 5)},   /* clock gate */
++    {0x50, (0x3 << 14),(0x3 << 14),(0x3 << 14),(0x3 << 14)},  /* NAND_BUSY pin with UART2 */
++    {0x5C, 0x0FFFFFFF, 0x0FFFFF00, 0x05555555, 0x0FFFFFFF},   /* pinMux with GPIO/SD */
++    {0x6C, (0x3 << 21),(0x0 << 21),(0x0 << 21),(0x1 << 21)},  /* pinMux with SD */
++    //{0x6C, (0x7 << 20),(0x0 << 21),(0x3 << 20),(0x3 << 20)},  /* pinMux with SD */
++};
++
++static pmuRegInfo_t	pmu_reg_info = {
++    "NANDC023",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++#define MTD_LINUX_SZ        (20 << 20)  //20M bytes
++#define IMAGE_MAGIC         0x805A474D
++
++typedef struct sys_header {	
++    char signature[8];          /* Signature is "GM8126" */
++    unsigned int bootm_addr;    /* default Image offset to load by nandboot */
++    unsigned int burnin_addr;   /* burn-in image address */
++    unsigned int uboot_addr;    /* uboot address */
++    unsigned int linux_addr;    /* linux image address */
++    unsigned int reserved1[7];  /* unused */
++    struct {
++        unsigned int nand_numblks;      //number of blocks in chip
++        unsigned int nand_numpgs_blk;   //how many pages in a block
++        unsigned int nand_pagesz;       //real size in bytes                        
++        unsigned int nand_sparesz_inpage;       //64bytes for 2k, ...... needed for NANDC023
++        unsigned int nand_numce;        //how many CE in chip
++        unsigned int nand_status_bit;
++        unsigned int nand_cmmand_bit;
++        unsigned int nand_ecc_capability;
++        unsigned int nand_ecc_base;     //0/1 indicates 512/1024 bytes      
++        unsigned int reserved_1;
++        unsigned int reserved_2;
++        unsigned int nand_row_cycle;
++        unsigned int nand_col_cycle;
++        unsigned int reserved[1];
++    } nandfixup;
++    unsigned int reserved2[100];        // unused
++    unsigned char last_511[4];  // byte510:0x55, byte511:0xAA
++} sys_header_t;
++
++/* Image header , 512 bytes */
++typedef struct nand_img_header {
++    unsigned int magic;         /* Image header magic number (0x805A474D) */
++    unsigned int chksum;        /* Image CRC checksum */
++    unsigned int size;          /* Image size */
++    unsigned int unused;
++    unsigned char name[80];     /* Image name */
++    unsigned char reserved[160 + 256];  /* Reserved for future */
++} img_hdr_t;
++
++#else
++
++static struct mtd_partition PORTING ftnandc023_partition_info[10];
++
++int platform_select_pinmux(int fd, int chip){
++    return 0;
++}
++
++#ifdef CONFIG_PLATFORM_GM8210
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x28, (0x1 << 18), (0x1 << 18), (0x0 << 18), (0x1 << 18)},   /* frequency setting */
++    {0x5C, 0x08000000, 0x08000000, 0x08000000, 0x08000000},   /* pinMux with GPIO, release 1~3 for other function */
++    {0x68, 0x3C000000, 0x3C000000, 0, 0x3C000000},   /* Schmitt trigger */
++#ifdef CONFIG_NAND_USE_AXIDMA
++    {0xA4, (0x1 << 27), (0x1 << 27), (0x1 << 27), (0x1 << 27)},   /* DMA ack selection */
++#endif    
++    {0xB4, (0x1 << 11), (0x1 << 11), (0x0 << 11), (0x1 << 11)},   /* AHB clock gate */
++};
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8287
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x28, (0x1 << 18), (0x1 << 18), (0x0 << 18), (0x1 << 18)},   /* frequency setting */
++    {0x5C, (0x1F << 27), (0x1F << 27), (0xB << 27), (0x1F << 27)},   /* pinMux */
++    {0xB4, (0x1 << 18), (0x1 << 18), (0x0 << 18), (0x1 << 18)},   /* AHB clock gate */
++};
++#endif
++
++static pmuRegInfo_t	pmu_reg_info = {
++    "NANDC023",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++#define MTD_LOGO_SZ         (4 << 20)  //4M bytes
++#define MTD_LINUX_SZ        (30 << 20)  //30M bytes
++
++typedef struct sys_header {	
++    char signature[8];          /* Signature is "GM8xxx" */
++    unsigned int bootm_addr;    /* Image offset to load by spiboot */
++    unsigned int bootm_size;
++    unsigned int bootm_reserved;
++
++    struct {
++        unsigned int addr;          /* image address */
++        unsigned int size;          /* image size */
++        unsigned char name[8];      /* image name */
++        unsigned int reserved[1];
++    } image[10];
++        
++    struct {
++        unsigned int nand_numblks;      //number of blocks in chip
++        unsigned int nand_numpgs_blk;   //how many pages in a block
++        unsigned int nand_pagesz;       //real size in bytes                        
++        unsigned int nand_sparesz_inpage;       //64bytes for 2k, ...... needed for NANDC023
++        unsigned int nand_numce;        //how many CE in chip
++        unsigned int nand_status_bit;
++        unsigned int nand_cmmand_bit;
++        unsigned int nand_ecc_capability;
++        unsigned int nand_ecc_base;     //0/1 indicates 512/1024 bytes      
++        unsigned int nand_sparesz_insect;
++        unsigned int reserved_1;
++        unsigned int nand_row_cycle;    //1 for 1 cycle ...
++        unsigned int nand_col_cycle;    //1 for 1 cycle ...
++        unsigned int reserved[1];
++    } nandfixup;
++    unsigned int reserved2[58];        // unused
++    unsigned char last_511[4];  // byte510:0x55, byte511:0xAA
++} sys_header_t;
++#endif
++//=============================================================================
++// BI table, size = 1024 bytes
++//=============================================================================
++typedef struct bi_table {
++    /* This array size is related to USB_BUFF_SZ defined in usb_scsi.h */
++    unsigned int bi_status[256];        //each bit indicates a block. 1 for good, 0 for bad
++} bi_table_t;
++
++struct ftnandc023_nand_data {
++    struct nand_chip chip;
++    struct mtd_info mtd;
++    void __iomem *io_base;
++    int sel_chip;
++    int cur_cmd;
++    int page_addr;
++    int column;
++    int byte_ofs;
++    u32 *buf;
++    struct device *dev;
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)   
++    struct dma_chan             *dma_chan;
++    dma_cap_mask_t              cap_mask;
++#ifdef CONFIG_PLATFORM_GM8126    
++    struct ftdmac020_dma_slave  dma_slave_config;
++#else
++#ifdef CONFIG_NAND_USE_AXIDMA
++    struct ftdmac030_dma_slave  dma_slave_config;
++#else 
++    struct ftdmac020_dma_slave  dma_slave_config;   
++#endif    
++#endif    
++    dma_cookie_t                cookie;
++    dma_addr_t mem_dmaaddr;
++    dma_addr_t nand_dmaaddr;
++    unsigned char *mem_dmabuf;
++    unsigned char *sg_dmabuf;
++#endif    
++    dma_addr_t syshd_dmaaddr;
++    dma_addr_t bitab_dmaaddr;
++    int cur_chan;
++    int valid_chip[MAX_CHANNEL];
++    int scan_state;
++    int flash_type;
++    int large_page;
++    sys_header_t *sys_hdr;      /* system header */
++    bi_table_t *bi_table;       /* bad block table next to sys_hdr */
++    int (*write_oob) (struct mtd_info * mtd, const u_char * buf, int len);
++    int (*read_oob) (struct mtd_info * mtd, u_char * buf);
++    int (*write_page) (struct mtd_info * mtd, const uint8_t * buf);
++    int (*read_page) (struct mtd_info * mtd, u_char * buf);
++};
++
++#ifdef CONFIG_MTD_NAND_FTNANDC023
++static int startchn = CONFIG_FTNANDC023_START_CHANNEL;
++#else
++static int startchn = 0;
++module_param(startchn, int, 0644);
++#endif
++
++static int eccbasft;
++static int spare;
++static int usecrc;
++static int useecc;
++static int legacy;
++
++#define	max_chip_size	(2048 * 16)     //2048MB NAND
++static unsigned int page_map[max_chip_size] = { };
++
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++static const char *part_probes[] = { "cmdlinepart", NULL };
++#endif
++
++#ifndef CONFIG_PLATFORM_GM8126
++static int partition_check(struct mtd_partition *partitions, struct ftnandc023_nand_data *data, int block_size)
++{
++    int i, num = 0;
++    sys_header_t *sys_hdr;
++    
++    sys_hdr = data->sys_hdr;
++#if defined(CONFIG_GM8210_FPGA) || defined(CONFIG_FPGA)
++    partitions[0].name = 'a';
++    partitions[0].offset = 0x140000;
++    partitions[0].size = 0x200000;
++    
++    partitions[1].name = 'b';
++    partitions[1].offset = 0x500000;
++    partitions[1].size = 0x200000;
++    
++    num = 2;    
++#else
++    for(i = 0; i < ARRAY_SIZE(ftnandc023_partition_info); i++){    
++    	if(sys_hdr->image[i].size == 0)
++    	    continue;
++
++        partitions[num].offset = sys_hdr->image[i].addr;
++        partitions[num].size = sys_hdr->image[i].size;
++        partitions[num].name = sys_hdr->image[i].name;
++        
++        if(sys_hdr->image[i].addr % block_size){
++    	    printk("Warning... partition %d addr 0x%x not block alignment, one block = 0x%x\n", i, sys_hdr->image[i].addr, block_size);
++    	    partitions[i].offset = BLOCK_ALIGN(sys_hdr->image[i].addr, block_size);
++        }
++        if(sys_hdr->image[i].size % block_size){
++    	    printk("Warning... partition %d size 0x%x not block alignment, one block = 0x%x\n", i, sys_hdr->image[i].size, block_size);
++    	    partitions[i].size = BLOCK_ALIGN(sys_hdr->image[i].size, block_size);
++        } 
++        num++;   
++    }
++
++    for(i = 0; i < ARRAY_SIZE(ftnandc023_partition_info); i++){
++        DBGLEVEL2(ftnandc023_dbg("partation %d addr = 0x%x, size = 0x%x, name = %s\n", i, sys_hdr->image[i].addr, sys_hdr->image[i].size, sys_hdr->image[i].name));
++    }
++    
++    for(i = 0; i < (num - 1); i++)
++    	if(partitions[i + 1].offset >= partitions[i].offset)
++	        if(partitions[i + 1].offset - partitions[i].offset < (2 * block_size)){
++	            printk("Warning... Block reserve for bad issue between partition %d with %d is not enough\n", i, i + 1);
++	            printk("partition %d addr = 0x%x, %d addr = 0x%x\n", i, (u32)partitions[i].offset, i + 1, (u32)partitions[i + 1].offset);
++	        }    	
++#endif    
++    return num;
++}
++#endif
++
++/* tWH, tWP, tREH, tREA, tRP, tWB, tRB, tWHR, tWHR2, tRHW, tRR, tAR,
++ * tADL, tRHZ, tCCS, tCS, tCLS, tCLR, tALS, tCALS2, tCWAW, tWPRE,
++ * tRPRE, tWPST, tRPST, tWPSTH, tRPSTH, tDQSHZ, tCAD, tDSL
++ * tDSH, tDQSL, tDQSH, tCKWR, tWRCK
++ */
++static struct ftnandc023_chip_timing PORTING chip_timing =
++    { 10, 12, 10, 20, 12, 100, 0, 60, 0, 100, 20, 10,
++    100, 100, 0, 20, 12, 10, 12, 0, 0, 0,
++    0, 0, 0, 0, 0, 0, 0, 0,
++    0, 0, 0, 0, 0
++};
++
++static struct resource ftnandc023_resource[] = {
++    [0] = {
++           .start = NAND_FTNAND023_PA_BASE,     /* Register Base address */
++           .end = NAND_FTNAND023_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = NANDDP_FTNAND023_PA_BASE,   /* BMC buffer or Data Port access */
++           .end = NANDDP_FTNAND023_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [2] = {
++           .start = NAND_FTNAND023_IRQ,
++           .end = NAND_FTNAND023_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static struct nand_ecclayout nand_hw_eccoob = {
++    .eccbytes = 0,
++    .eccpos = {0},
++    .oobfree = {
++                {.offset = 0,
++                 .length = 64}}
++};
++
++static uint8_t ftnandc023_bbt_pattern[] = { 'B', 'b', 't', '0' };
++static uint8_t ftnandc023_mirror_pattern[] = { '1', 't', 'b', 'B' };
++
++static struct nand_bbt_descr ftnandc023_bbt_mirror_descr = {
++    .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++        | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++    .offs = 0,
++    .len = 4,
++    .veroffs = 4,
++    .maxblocks = 4,
++    .pattern = ftnandc023_mirror_pattern
++};
++
++static struct nand_bbt_descr ftnandc023_bbt_main_descr = {
++    .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++        | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++    .offs = 0,
++    .len = 4,
++    .veroffs = 4,
++    .maxblocks = 4,
++    .pattern = ftnandc023_bbt_pattern
++};
++
++static uint8_t ftnandc023_scan_ff_pattern[] = { 0xff, 0xff, 0xff, 0xff };
++
++static struct nand_bbt_descr ftnandc023_largepage_flashbased = {
++    .options = NAND_BBT_SCAN2NDPAGE,
++    .offs = 0,
++    .len = 4,
++    .pattern = ftnandc023_scan_ff_pattern
++};
++
++static void ftnandc023_regdump(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 val;
++
++    printk(KERN_INFO "===================================\n");
++    val = readl(data->io_base + ECC_INTR_STATUS);
++    printk(KERN_INFO "ECC intr sts(0x%2x): 0x%08x\n", ECC_INTR_STATUS, val);
++    val = readl(data->io_base + DEV_BUSY);
++    printk(KERN_INFO "Device busy(0x%2x): 0x%08x\n", DEV_BUSY, val);
++    val = readl(data->io_base + GENERAL_SETTING);
++    printk(KERN_INFO "General setting(0x%2x): 0x%08x\n", GENERAL_SETTING, val);
++    val = readl(data->io_base + MEM_ATTR_SET);
++    printk(KERN_INFO "Mem attr.(0x%2x): 0x%08x\n", MEM_ATTR_SET, val);
++    val = readl(data->io_base + INTR_STATUS);
++    printk(KERN_INFO "Intr sts(0x%2x): 0x%08x\n", INTR_STATUS, val);
++    val = readl(data->io_base + BMC_REGION_STATUS);
++    printk(KERN_INFO "BMC region sts(0x%2x): 0x%08x\n", BMC_REGION_STATUS, val);
++    printk(KERN_INFO "===================================\n");
++}
++
++int show_one_time = 1;
++static inline void ftnandc023_set_row_col_addr(struct ftnandc023_nand_data *data)
++{
++    int val;
++
++    val = readl(data->io_base + MEM_ATTR_SET);
++    /* if NAND be write before, ROM CODE will set correct row/col cycle, not need to set again */
++#if defined(CONFIG_GM8210_FPGA) || defined(CONFIG_FPGA)    
++    val &= ~(0x7 << 12);
++    if (data->large_page)
++    	val |= (ATTR_ROW_CYCLE(1) | ATTR_COL_CYCLE(1));//row 1G set 2, 2G set 3
++	else
++		val |= (ATTR_ROW_CYCLE(1) | ATTR_COL_CYCLE(0));
++#endif
++	if(show_one_time) {
++		printk("NAND Row cycle = %d, Col cycle = %d\n", ((val >> 13) & 0x3) + 1, ((val >> 12) & 0x1) + 1);
++		show_one_time = 0;
++	}
++    writel(val, data->io_base + MEM_ATTR_SET);
++}
++
++/* low enable write protect, high disable write protect */
++void write_protect(int mode)
++{
++#ifdef CONFIG_GPIO_WP
++		if(mode)
++			gpio_direction_output(GPIO_PIN, 0);
++		else
++			gpio_direction_output(GPIO_PIN, 1);
++#endif
++}
++
++static void ftnandc023_soft_reset(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    unsigned long timeo = jiffies;
++    u32 val = 0;
++
++    timeo += HZ;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    writel(1, data->io_base + GLOBAL_RESET);
++    while (time_before(jiffies, timeo)) {
++    	val = readl(data->io_base + GLOBAL_RESET);
++    	if(!val)
++    		break;
++    }
++    if(val)
++    	printk("Reset channel timeout!\n");
++
++    platform_select_pinmux(nand_fd, -1);
++}
++
++static int ftnandc023_nand_check_cmdq(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    unsigned long timeo = jiffies;
++    u32 status;
++    int ret;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    ret = -EIO;
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        status = readl(data->io_base + CMDQUEUE_STATUS);
++        if ((status & CMDQUEUE_STATUS_FULL(data->cur_chan)) == 0) {
++            ret = 0;
++            break;
++        }
++        cond_resched();
++    }
++    
++		platform_select_pinmux(nand_fd, -1);
++    return ret;
++}
++
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++static int ftnandc023_dma_wait(struct mtd_info *mtd)
++{
++    int ret = -1;
++  
++    ret = wait_event_timeout(nand023_queue, trigger_flag == 1, 10 * HZ);
++    if (ret == 0) {
++    	printk("nand023 dma queue wake up timeout signal arrived\n");
++    	return -1;
++    }
++
++    trigger_flag = 0; 
++    
++    return 0;
++}
++#endif
++
++void ecc_handle(struct mtd_info *mtd)
++{
++		struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 val;
++    unsigned long timeo = jiffies;
++    
++    //step 2
++    val = readl(data->io_base + BMC_REGION_STATUS);
++    if((val & (1 << 8)) != 0)
++    	return;
++    //step 4
++    writel(data->sel_chip + 1, data->io_base + REGION_SW_RESET);
++    //step 5
++    writel(1, data->io_base + AHB_RESET);
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++    	val = readl(data->io_base + AHB_RESET);
++    	if(!val)
++    		break;
++    }
++    if(val)
++    	printk("Reset AHB slave timeout!\n");
++   
++    //step 7
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++    	val = readl(data->io_base + DEV_BUSY);
++    	if(val)
++    		break;
++    }
++    if(!val)
++    	printk("Wait channel ready timeout!\n");
++    
++    //step 9	
++    //ftnandc023_soft_reset(mtd);    
++}
++
++static int ftnandc023_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    unsigned long timeo = jiffies;
++    int ret, state = chip->state;
++    u32 status = 0;
++    int i, check_flag = 0, prog_flag = 0;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    ret = NAND_STATUS_FAIL;
++    timeo += HZ;
++
++    while (time_before(jiffies, timeo)) {
++        status = readl(data->io_base + INTR_STATUS);
++        /* Clear interrupt instantly, since we already keep IS to status */
++        writel(status, data->io_base + INTR_STATUS);
++
++            if (unlikely(status & STATUS_FAIL(data->cur_chan))) {
++                printk(KERN_ERR "NAND: STATUS FAIL(0x%x, off 0x178 = 0x%x)!\n", status,
++                       readl(data->io_base + READ_STATUS0));
++                ftnandc023_soft_reset(mtd);
++                goto out;
++            }
++
++        if (status & STATUS_CMD_COMPLETE(data->cur_chan)) {
++            //clear status error
++            status = readl(data->io_base + ECC_INTR_STATUS);
++            if (unlikely(status & ECC_ERR_FAIL(data->cur_chan)))
++            		writel(ECC_ERR_FAIL(data->cur_chan), data->io_base + ECC_INTR_STATUS);
++		            		
++            if (state == FL_READING) {
++                if (unlikely(status & STATUS_CRC_FAIL(data->cur_chan))) {
++                    if(data->page_addr != 1) {
++                    	if(data->buf != NULL) {/* only read OOB for filesystem */
++		                    for (i = 0; i < (mtd->writesize >> 2); i++) {
++		                    	if (*(data->buf + i) != 0xFFFFFFFF) {
++		                    		ret = NAND_STATUS_FAIL;
++		                    		check_flag = prog_flag = 1;
++		                    		printk(KERN_ERR "CRC err\n");
++			                      mtd->ecc_stats.failed++;
++			                      goto out;                    		
++		                    	}
++                            }
++                        }
++                    }
++                }
++
++                if (unlikely(status & ECC_ERR_FAIL(data->cur_chan))) {
++                    if(data->page_addr != 1){
++	                    if (check_flag) {
++	                    		if(prog_flag){
++		                        ret = NAND_STATUS_FAIL;
++		                        printk(KERN_ERR "ECC err\n");
++		                        ecc_handle(mtd);
++		                        //printk("addr = 0x%x, data = 0x%x, base = 0x%x\n", (u32)(data->buf + i), *(data->buf + i),(u32)data->buf);
++		                        mtd->ecc_stats.failed++;
++		                        goto out;
++	                      	}
++	                    } else {
++	                    		if(data->buf != NULL) {/* only read OOB for filesystem */
++				                    for (i = 0; i < (mtd->writesize >> 2); i++) {
++				                    	if (*(data->buf + i) != 0xFFFFFFFF){
++    				                        ret = NAND_STATUS_FAIL;
++    				                        printk(KERN_ERR "ECC err\n");
++    				                        ecc_handle(mtd);
++    				                        //printk("addr = 0x%x, data = 0x%x, base = 0x%x\n", (u32)(data->buf + i), *(data->buf + i),(u32)data->buf);
++    				                        mtd->ecc_stats.failed++;
++    				                        goto out;
++    				                    }
++                                    }
++                                }
++	                    }
++                  	}
++                }
++            }
++            ret = NAND_STATUS_READY;
++            goto out;
++
++        }
++
++        cond_resched();
++    }
++
++    printk("nand wait time out, status = 0x%x\n", status);
++    ftnandc023_regdump(mtd);
++  out:
++
++  	write_protect(1);
++  	platform_select_pinmux(nand_fd, -1);
++    return ret;
++}
++
++/* The unit of Hclk is MHz, and the unit of Time is ns.
++ * We desire to calculate N to satisfy N*(1/Hclk) > Time given Hclk and Time
++ * ==> N > Time * Hclk
++ * ==> N > Time * 10e(-9) * Hclk *10e(6)        --> take the order out
++ * ==> N > Time * Hclk * 10e(-3)
++ * ==> N > Time * Hclk / 1000
++ * ==> N = (Time * Hclk + 999) / 1000
++ */
++static void ftnandc023_calc_timing(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    uint16_t tWH, tWP, tREH, tRES, tBSY, tBUF1;
++    uint16_t tBUF2, tBUF3, tBUF4, t1, tPRE, tRLAT;
++    uint16_t tPST, tPSTH, tCAD, tCS, tCKWR;
++    int i;
++    struct ftnandc023_chip_timing *p;
++    u32 HCLK, timing[4];
++
++    /*
++     * The default value is slow and it should be enough for use.
++     */
++    return;
++
++    //HCLK = a320_get_ahb_clk() * 2 / 1000000;
++    HCLK = ftpmu010_get_attr(ATTR_TYPE_AHB) / 1000000;
++#if defined (CONFIG_FTNANDC023_MICRON_29F32G08CBABB)
++    if (data->flash_type == ONFI)
++        p = &sync_timing;
++    else
++#endif
++        p = &chip_timing;
++
++    tWH = (p->tWH * HCLK + 999) / 1000;
++    if (tWH >= 1)
++        tWH--;
++
++    tWP = (p->tWP * HCLK + 999) / 1000;
++    if (tWP >= 1)
++        tWP--;
++
++    tREH = (p->tREH * HCLK + 999) / 1000;
++    if (tREH >= 1)
++        tREH--;
++
++    tRES = max(p->tREA, p->tRP);
++    tRES = (tRES * HCLK + 999) / 1000;
++    if (tRES >= 1)
++        tRES--;
++
++    tRLAT = tREH + tRES + 1;
++
++    tBSY = max(p->tWB, p->tRB);
++    tBSY = (tBSY * HCLK + 999) / 1000;
++    if (tBSY >= 2)
++        tBSY--;
++
++    tBUF1 = max(p->tADL, p->tCCS);
++    tBUF1 = (tBUF1 * HCLK + 999) / 1000;
++    if (tBUF1 >= 2)
++        tBUF1--;
++
++    tBUF2 = max(p->tAR, p->tRR);
++    tBUF2 = max(tBUF2, p->tCLR);
++    tBUF2 = (tBUF2 * HCLK + 999) / 1000;
++    if (tBUF2 >= 2)
++        tBUF2--;
++
++    tBUF3 = max(p->tRHW, p->tRHZ);
++    tBUF3 = max(tBUF3, p->tDQSHZ);
++    tBUF3 = (tBUF3 * HCLK + 999) / 1000;
++    if (tBUF3 >= 2)
++        tBUF3--;
++
++    tBUF4 = p->tWHR;
++    tBUF4 = (tBUF4 * HCLK + 999) / 1000;
++    if (tBUF4 >= 2)
++        tBUF4--;
++
++    if (data->flash_type == TOGGLE) {
++        t1 = max(p->tCLS, p->tALS);
++        t1 = max(t1, p->tCS);
++        t1 -= p->tWP;
++    } else {
++        t1 = max((uint16_t) (p->tCALS2 - p->tWP), p->tCWAW);
++    }
++    t1 = (t1 * HCLK + 999) / 1000;
++    if (t1 >= 1)
++        t1--;
++
++    tPRE = max(p->tWPRE, p->tRPRE);
++    tPRE = (tPRE * HCLK + 999) / 1000;
++    if (tPRE >= 1)
++        tPRE--;
++
++    tPST = max(p->tWPST, p->tRPST);
++    tPST = (tPST * HCLK + 999) / 1000;
++    if (tPST >= 1)
++        tPST--;
++
++    if (data->flash_type == TOGGLE)
++        tPSTH = max(p->tWPSTH, p->tRPSTH);
++    else
++        tPSTH = p->tDQSHZ;
++    tPSTH = (tPSTH * HCLK + 999) / 1000;
++    if (tPSTH >= 1)
++        tPSTH--;
++
++    tCAD = p->tCAD;
++    tCAD = (tCAD * HCLK + 999) / 1000;
++    if (tCAD >= 1)
++        tCAD--;
++
++    tCS = p->tCS;
++    tCS = (tCS * HCLK + 999) / 1000;
++    if (tCS >= 1)
++        tCS--;
++
++    if (data->flash_type == TOGGLE) {
++        tCKWR = max(p->tDSL, p->tDSH);
++        tCKWR = max(tCKWR, p->tDQSL);
++        tCKWR = max(tCKWR, p->tDQSH);
++    } else {
++        tCKWR = max(p->tCKWR, p->tWRCK);
++    }
++    tCKWR = (tCKWR * HCLK + 999) / 1000;
++    if (tCKWR >= 1)
++        tCKWR--;
++
++    timing[0] = (tWH << 24) | (tWP << 16) | (tREH << 8) | tRES;
++    timing[1] = (tRLAT << 16) | (tBSY << 8) | t1;
++    timing[2] = (tBUF4 << 24) | (tBUF3 << 16) | (tBUF2 << 8) | tBUF1;
++    timing[3] = (tPRE << 28) | (tPST << 24) | (tPSTH << 16) | (tCAD << 8) | (tCS << 5) | tCKWR;
++
++    printk("AC Timing 0:0x%08x\n", timing[0]);
++    printk("AC Timing 1:0x%08x\n", timing[1]);
++    printk("AC Timing 2:0x%08x\n", timing[2]);
++    printk("AC Timing 3:0x%08x\n", timing[3]);
++
++    for (i = 0; i < MAX_CHANNEL; i++) {
++        writel(timing[0], data->io_base + FL_AC_TIMING0(i));
++        writel(timing[1], data->io_base + FL_AC_TIMING1(i));
++        writel(timing[2], data->io_base + FL_AC_TIMING2(i));
++        writel(timing[3], data->io_base + FL_AC_TIMING3(i));
++    }
++}
++
++static uint32_t ftnandc023_onfi_get_feature(struct mtd_info *mtd, int chn, int ce, int type)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6, val;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    ftnandc023_set_row_col_addr(data);
++
++    /* 0x1 is Timing mode feature address */
++    writel(0x1, data->io_base + CMDQUEUE1(chn));
++
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(type);
++    cq6 |= CMD_START_CE(ce) | CMD_BYTE_MODE | CMD_SPARE_NUM(3);
++    cq6 |= CMD_INDEX(ONFI_FIXFLOW_GETFEATURE);
++    ftnandc023_nand_check_cmdq(mtd);
++    writel(cq6, data->io_base + CMDQUEUE6(chn));
++
++    ftnandc023_nand_wait(mtd, chip);
++    val = readl(data->io_base + SPARE_SRAM + (chn << 10)
++                + (ce << 6));
++
++		platform_select_pinmux(nand_fd, -1);
++
++    return val;
++}
++
++static void ftnandc023_onfi_set_feature(struct mtd_info *mtd, int chn, int ce)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++
++    ftnandc023_set_row_col_addr(data);
++
++    /* 0x11 means Timing mode 1 and Synchronous DDR */
++    writel(0x11, data->io_base + SPARE_SRAM + (chn << 10) + (ce << 6));
++
++    /* 0x1 is Timing mode feature address */
++    writel(0x1, data->io_base + CMDQUEUE1(chn));
++
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(0);
++    cq6 |= CMD_START_CE(ce) | CMD_BYTE_MODE | CMD_SPARE_NUM(3);
++    cq6 |= CMD_INDEX(ONFI_FIXFLOW_SETFEATURE);
++    ftnandc023_nand_check_cmdq(mtd);
++    writel(cq6, data->io_base + CMDQUEUE6(chn));
++    ftnandc023_nand_wait(mtd, chip);
++
++    platform_select_pinmux(nand_fd, -1);
++}
++
++static int ftnandc023_onfi_sync(struct mtd_info *mtd)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc023_nand_data *data = p->priv;
++    u32 val;
++    int i, j, ret = -1;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    for (i = startchn; i < MAX_CHANNEL; i++) {
++        for (j = 0; j < data->valid_chip[i]; j++) {
++            val = ftnandc023_onfi_get_feature(mtd, i, j, 0);
++            printk("onfi feature for channel %d, CE %d: 0x%x\n", i, j, val);
++        }
++    }
++    for (i = startchn; i < MAX_CHANNEL; i++) {
++        for (j = 0; j < data->valid_chip[i]; j++) {
++            ftnandc023_onfi_set_feature(mtd, i, j);
++        }
++    }
++    for (i = startchn; i < MAX_CHANNEL; i++) {
++        for (j = 0; j < data->valid_chip[i]; j++) {
++            val = ftnandc023_onfi_get_feature(mtd, i, j, 3);
++            printk("onfi feature for channel %d, CE %d: 0x%x\n", i, j, val);
++            if (val != 0x1111) {
++                goto out;
++            }
++        }
++    }
++    ret = 0;
++
++  out:
++  	platform_select_pinmux(nand_fd, -1);
++    return ret;
++}
++
++static int ftnandc023_available_oob(struct mtd_info *mtd)
++{
++    int ret = 0;
++    int tmp, eccbyte;
++
++    if (useecc < 0)
++        goto out;
++    if (usecrc != 0)
++        usecrc = 1;
++    else
++        usecrc = 0;
++
++    eccbyte = (useecc * 14) / 8;
++    if (((useecc * 14) % 8) != 0)
++        eccbyte++;
++    tmp = (eccbyte * (mtd->writesize >> eccbasft)) + (usecrc << 1) * (mtd->writesize >> eccbasft);
++
++        /*----------------------------------------------------------
++	 * YAFFS require 16 bytes OOB without ECC, 28 bytes with
++	 * ECC enable.
++	 * BBT require 5 bytes for Bad Block Table marker.
++	 */
++#ifdef CONFIG_YAFFS_FS
++    if (spare - tmp >= 16) {
++        ret = spare - tmp;
++        printk(KERN_INFO "NAND(YAFFS): avaliable OOB is %d byte.\n", ret);
++    } else {
++        printk(KERN_INFO
++               "NAND: Not enough OOB:%d bytes(YAFFS requires 16 bytes without software ECC, "
++               "28 bytes with ECC enable), try to reduce ECC correction bits.\n", spare - tmp);
++    }
++#else
++    ret = spare - tmp;
++    printk(KERN_INFO "Avaliable OOB is %d byte(%d per sector).\n", ret,
++           ret / (mtd->writesize >> eccbasft));
++#endif
++  out:
++    return ret;
++}
++
++static uint8_t ftnandc023_read_byte(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    uint32_t lv;
++    uint8_t b = 0;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    switch (data->cur_cmd) {
++    case NAND_CMD_READID:
++        lv = readl(data->io_base + SPARE_SRAM + (data->cur_chan << 10)
++                   + (data->sel_chip << 6));
++        b = (lv >> data->byte_ofs) & 0xFF;
++        data->byte_ofs += 8;
++        if (data->byte_ofs == 32)
++            data->byte_ofs = 0;
++        break;
++    case NAND_CMD_STATUS:
++        lv = readl(data->io_base + READ_STATUS0);
++        lv = lv >> (data->cur_chan * 8);
++        b = (lv & 0xFF);
++        /* FIXME: status seems has problem, workaround here */
++        b |= NAND_STATUS_WP;
++        break;
++    }
++		platform_select_pinmux(nand_fd, -1);
++    return b;
++}
++
++static int ftnandc023_nand_read_oob_lp(struct mtd_info *mtd, u_char * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++    int status = 0, i, j;
++    u8 *p;
++
++    p = buf;
++
++    platform_select_pinmux(nand_fd, 0);
++    ftnandc023_set_row_col_addr(data);
++
++    writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++    writel(CMD_COUNT(mtd->writesize >> eccbasft), data->io_base + CMDQUEUE5(data->cur_chan));
++
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    cq6 |= CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) | CMD_INDEX(LARGE_FIXFLOW_READOOB);
++    status = ftnandc023_nand_check_cmdq(mtd);
++    if (status < 0)
++        goto out;
++    writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++
++    if (ftnandc023_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out;
++    }
++
++    for (i = 0; i < (mtd->writesize >> eccbasft); i++) {
++        for (j = 0; j < (spare + 1); j++) {
++            *(p++) =
++                readb(data->io_base + SPARE_SRAM + (data->cur_chan << 10) +
++                      (data->sel_chip << 6) + i * (64 / (mtd->writesize >> eccbasft)) + j);
++        }
++    }
++
++    for (i = avail_oob_sz; i < mtd->oobsize; i++)
++        *(p++) = 0xFF;          /* clear */
++  out:
++  	platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc023_nand_read_oob_sp(struct mtd_info *mtd, u_char * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++    int i, status = 0;
++
++    platform_select_pinmux(nand_fd, 0);
++    ftnandc023_set_row_col_addr(data);
++
++    writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++    writel(CMD_COUNT(1), data->io_base + CMDQUEUE5(data->cur_chan));
++
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    cq6 |= CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) | CMD_INDEX(SMALL_FIXFLOW_READOOB);
++    status = ftnandc023_nand_check_cmdq(mtd);
++    if (status < 0)
++        goto out;
++    writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++
++    if (ftnandc023_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out;
++    }
++
++    for (i = 0; i < mtd->oobsize; i++) {
++        *(buf + i) = readb(data->io_base + SPARE_SRAM + (data->cur_chan << 10) +
++                           (data->sel_chip << 6) + i);
++    }
++  out:
++  	platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc023_nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page,
++                                        int sndcmd)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    data->page_addr = page;
++
++    return data->read_oob(mtd, chip->oob_poi);
++}
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++
++static int setup_dma(struct ftnandc023_nand_data *data, int direct)
++{
++    struct dma_slave_config *common;
++    
++    data->dma_slave_config.id = -1;
++    data->dma_slave_config.handshake = DMA_NANDC_REQ;//enable
++
++    common = &data->dma_slave_config.common;
++    
++#ifdef CONFIG_NAND_USE_AHBDMA    
++    if (eccbasft > 9)
++    	data->dma_slave_config.src_size = FTDMAC020_BURST_SZ_256;//256x4=1024
++    else
++    	data->dma_slave_config.src_size = FTDMAC020_BURST_SZ_128;//128x4=512
++    
++    if(direct == DMA_DEV_TO_MEM){
++        data->dma_slave_config.src_sel = AHBMASTER_R_SRC;
++        data->dma_slave_config.dst_sel = AHBMASTER_R_DST;
++    }else{
++        data->dma_slave_config.src_sel = AHBMASTER_W_SRC;
++        data->dma_slave_config.dst_sel = AHBMASTER_W_DST;
++    }
++#else
++    common->src_maxburst = 128;
++    common->dst_maxburst = 128;
++#endif
++     
++    if(direct == DMA_MEM_TO_DEV){
++     	common->src_addr = data->mem_dmaaddr;    
++    	common->dst_addr = data->nand_dmaaddr;   
++    }else{
++     	common->src_addr = data->nand_dmaaddr;    
++    	common->dst_addr = data->mem_dmaaddr;     
++    }
++
++    common->dst_addr_width = 4;
++    common->src_addr_width = 4;
++    common->direction = direct;
++
++    return dmaengine_slave_config(data->dma_chan, common);//step 2
++}
++
++static int nand_dma_start(struct ftnandc023_nand_data *data, size_t len, int direct)
++{
++	int ret;
++	enum dma_ctrl_flags flags;
++	struct dma_async_tx_descriptor *desc;
++
++	ret = setup_dma(data, direct);
++	if (ret){
++	    printk("Nand setup dma fail\n");
++	    return ret;
++	}
++
++	flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++
++	desc = dmaengine_prep_slave_single(data->dma_chan, (void *)data->sg_dmabuf, len, direct, flags);//step 3
++			    
++	if (!desc){
++	    printk("Error dma parameter\n");
++	    return ret;
++	}	
++
++	desc->callback = ftnandc023_dma_callback;
++        desc->callback_param = &data;
++        data->cookie = dmaengine_submit(desc);	//step 4
++	dma_async_issue_pending(data->dma_chan);//step 5
++	
++	return 0;
++}
++#endif
++
++static int calc_new_page(struct mtd_info *mtd, int page_addr)
++{
++    unsigned int start_addr, end_addr, check_addr, tmp_addr, bad_num = 0;
++    unsigned int block_page_num = mtd->erasesize / mtd->writesize;
++    struct nand_chip *chip = mtd->priv;
++    
++    if (root_mtd_num != 0xFFFF) {// is squashfs
++        start_addr = ftnandc023_partition_info[root_mtd_num].offset;
++        end_addr = ftnandc023_partition_info[root_mtd_num].size + start_addr;
++        //printk("squash start addr = 0x%x, end addr = 0x%x\n", start_addr, end_addr); 
++
++        check_addr = page_addr * mtd->writesize;
++        
++        if((check_addr >= start_addr) && (check_addr < end_addr)) {
++            tmp_addr = start_addr;
++            
++            /* have bad block between start to here? */
++            while (check_addr >= tmp_addr) {
++                if(ftnandc_read_bbt(mtd, (loff_t) tmp_addr) != 0) {
++                    bad_num++;
++                    //printk("<ba=0x%x>", tmp_addr);
++                }
++
++                tmp_addr += (0x1 << chip->bbt_erase_shift);
++            }
++            
++            /* move n good block */
++            if(bad_num) {
++                //printk("<br0x%x,bad=%d>",page_addr,bad_num);
++                while(bad_num) {
++                    //printk("<tmp_page = 0x%x>", tmp_addr / mtd->writesize);
++                    if(ftnandc_read_bbt(mtd, (loff_t) tmp_addr) == 0)
++                        bad_num--;
++    
++                    tmp_addr += (0x1 << chip->bbt_erase_shift);
++                    page_addr += block_page_num;                    
++                }
++                //printk("<ar0x%x>\n",page_addr);
++            }                        
++        }
++    }
++
++    return page_addr;
++}
++
++static int ftnandc023_nand_read_page_lp(struct mtd_info *mtd, u_char * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++    u32 *lbuf, val = 0;
++    int status = 0;
++    int i, j;
++    u8 *p;
++
++    DBGLEVEL2(ftnandc023_dbg
++              ("r:page = 0x%x, size = %d, data->column = %d\n", data->page_addr, mtd->writesize,
++               data->column));
++    lbuf = (u32 *) buf;
++
++    data->page_addr = calc_new_page(mtd, data->page_addr);
++   
++    platform_select_pinmux(nand_fd, 0);
++    if(data->page_addr == 1){//BI table
++    	val = readl(data->io_base + ECC_CONTROL);
++    	if(!(val & (1 << 8)))
++    		printk("### Warning, ECC not enable! ###\n");
++    	writel(val & (~(1 << 8)), data->io_base + ECC_CONTROL);
++    }
++    ftnandc023_set_row_col_addr(data);
++    writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++    writel(CMD_COUNT(mtd->writesize >> eccbasft) | (data->column / mtd->writesize),
++           data->io_base + CMDQUEUE5(data->cur_chan));
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    cq6 |= CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) | CMD_INDEX(LARGE_FIXFLOW_PAGEREAD);
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    cq6 |= (1 << 4);	//enable handshake
++#endif
++    status = ftnandc023_nand_check_cmdq(mtd);
++    if (status < 0)
++        goto out;
++
++    writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    status = nand_dma_start(data, mtd->writesize, DMA_DEV_TO_MEM);
++    if (status < 0) {
++        printk("nand dma read page lp fail\n");
++        goto out;
++    }
++
++    ftnandc023_dma_wait(mtd);
++    
++    memcpy(buf, data->mem_dmabuf, mtd->writesize);   
++#else                     
++    for (i = 0; i < mtd->writesize; i += 4)
++        *lbuf++ = *(volatile unsigned *)(data->chip.IO_ADDR_R);
++#endif
++
++    if (ftnandc023_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out;
++    }
++
++    p = chip->oob_poi;
++    if (p) {
++        for (i = 0; i < (mtd->writesize >> eccbasft); i++) {
++            for (j = 0; j < (spare + 1); j++) {
++                *(p++) =
++                    readb(data->io_base + SPARE_SRAM + (data->cur_chan << 10) +
++                          (data->sel_chip << 6) + i * (64 / (mtd->writesize >> eccbasft)) + j);
++            }
++        }
++    }
++
++    /* clear to default value */
++    if (p) {
++        for (i = avail_oob_sz; i < mtd->oobsize; i++) {
++            *(p++) = 0xFF;
++        }
++    }
++  out:
++    if((data->page_addr == 1) && (val & (1 << 8)))//BI table
++    	writel(val, data->io_base + ECC_CONTROL);
++
++  	platform_select_pinmux(nand_fd, -1);
++
++    return status;
++}
++
++static int ftnandc023_nand_read_page_sp(struct mtd_info *mtd, u_char * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++    u32 *lbuf;
++    int status = 0;
++    int i;
++
++    lbuf = (u32 *) buf;
++
++    platform_select_pinmux(nand_fd, 0);
++    ftnandc023_set_row_col_addr(data);
++
++    writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++    writel(CMD_COUNT(1) | (data->column / mtd->writesize),
++           data->io_base + CMDQUEUE5(data->cur_chan));
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    cq6 |= CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) | CMD_INDEX(SMALL_FIXFLOW_PAGEREAD);
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    cq6 |= (1 << 4);	//enable handshake
++#endif
++    status = ftnandc023_nand_check_cmdq(mtd);
++    if (status < 0)
++        goto out;
++    writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    status = nand_dma_start(data, mtd->writesize, DMA_DEV_TO_MEM);
++    if (status < 0) {
++        printk("nand dma read page sp fail\n");
++        goto out;
++    }
++    ftnandc023_dma_wait(mtd);
++    memcpy(buf, data->mem_dmabuf, mtd->writesize);
++#else
++    for (i = 0; i < mtd->writesize; i += 4)
++        *lbuf++ = *(volatile unsigned *)(data->chip.IO_ADDR_R);
++#endif
++    if (ftnandc023_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out;
++    }
++
++    for (i = 0; i < mtd->oobsize; i++) {
++        *(chip->oob_poi + i) = readb(data->io_base + SPARE_SRAM + (data->cur_chan << 10) +
++                                     (data->sel_chip << 6) + i);
++    }
++
++  out:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc023_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, int page)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    data->buf = (u32 *) buf;
++
++    return data->read_page(mtd, buf);
++}
++
++static int ftnandc023_nand_write_oob_lp(struct mtd_info *mtd, const u_char * buf, int len)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++    int status = 0, i, j;
++    u8 *p;
++
++#if 0
++    {
++        u8 oob_buf[64] = { 0xAB };
++        if (ftnandc023_nand_read_oob_lp(mtd, oob_buf) < 0)
++            return -1;
++
++        for (i = 0; i < avail_oob_sz; i++)
++            printk("0x%x ", oob_buf[i]);
++        printk("\n");
++
++        platform_select_pinmux(nand_fd, 0);
++        write_protect(0);
++        goto out;
++    }
++#else
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++
++    //have be write by write page with spare
++    if (page_map[data->page_addr / 32] & (1 << (data->page_addr % 32))) 
++        goto out;
++#endif
++    ftnandc023_set_row_col_addr(data);
++
++    p = (u8 *) buf;
++
++    for (i = 0; i < (mtd->writesize >> eccbasft); i++) {
++        for (j = 0; j < (spare + 1); j++) {
++            writeb(*(p++),
++                   data->io_base + SPARE_SRAM + (data->cur_chan << 10) +
++                   (data->sel_chip << 6) + i * (64 / (mtd->writesize >> eccbasft)) + j);
++        }
++    }
++
++    writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++    writel(CMD_COUNT(mtd->writesize >> eccbasft), data->io_base + CMDQUEUE5(data->cur_chan));
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    cq6 |= CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) | CMD_INDEX(LARGE_FIXFLOW_WRITEOOB);
++    status = ftnandc023_nand_check_cmdq(mtd);
++    if (status < 0) {
++        printk("cmdq status error\n");
++        goto out;
++    }
++    writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++
++    if (ftnandc023_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        printk("wait error\n");
++        goto out;
++    }
++  out:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc023_nand_write_oob_sp(struct mtd_info *mtd, const u_char * buf, int len)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++    int i, status = 0;
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++    ftnandc023_set_row_col_addr(data);
++
++    for (i = 0; i < len; i++)
++        writeb(*(buf + i),
++               data->io_base + SPARE_SRAM + (data->cur_chan << 10) + (data->sel_chip << 6) + i);
++
++    writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++    writel(CMD_COUNT(1), data->io_base + CMDQUEUE5(data->cur_chan));
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    cq6 |= CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) | CMD_INDEX(SMALL_FIXFLOW_WRITEOOB);
++    status = ftnandc023_nand_check_cmdq(mtd);
++    if (status < 0)
++        goto out;
++    writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++
++    if (ftnandc023_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out;
++    }
++  out:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc023_nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    DBGLEVEL2(ftnandc023_dbg("write oob only to page = 0x%x\n", page));
++    data->page_addr = page;
++
++    return data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++}
++
++static int ftnandc023_nand_write_page_lp(struct mtd_info *mtd, const uint8_t * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++    int i, j;
++    u32 *lbuf;
++    int status = 0;
++    u8 *p;
++
++    DBGLEVEL2(ftnandc023_dbg
++              ("w:page = 0x%x, size = %d, data->column = %d\n", data->page_addr, mtd->writesize,
++               data->column));
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++    p = chip->oob_poi;
++
++    if (p != NULL) {
++        for (i = 0; i < (mtd->writesize >> eccbasft); i++) {
++            for (j = 0; j < (spare + 1); j++) {
++                writeb(*(p++),
++                       data->io_base + SPARE_SRAM + (data->cur_chan << 10) +
++                       (data->sel_chip << 6) + i * (64 / (mtd->writesize >> eccbasft)) + j);
++            }
++        }
++    }
++
++    lbuf = (u32 *) buf;
++
++    ftnandc023_set_row_col_addr(data);
++
++    writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++    writel(CMD_COUNT(mtd->writesize >> eccbasft) | (data->column / mtd->writesize),
++           data->io_base + CMDQUEUE5(data->cur_chan));
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    cq6 |= CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) | CMD_INDEX(LARGE_FIXFLOW_PAGEWRITE);
++
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    cq6 |= (1 << 4);	//enable handshake
++#endif
++    status = ftnandc023_nand_check_cmdq(mtd);
++    if (status < 0)
++        goto out;
++    writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    memcpy(data->mem_dmabuf, buf, mtd->writesize);
++    
++    status = nand_dma_start(data, mtd->writesize, DMA_MEM_TO_DEV);
++    if (status < 0) {
++        printk("nand dma write page lp fail\n");
++        goto out;
++    }
++    ftnandc023_dma_wait(mtd);
++#else
++    for (i = 0; i < mtd->writesize; i += 4)
++        *(volatile unsigned *)(data->chip.IO_ADDR_R) = *lbuf++;
++#endif
++    page_map[data->page_addr / 32] |= (1 << (data->page_addr % 32));
++
++    if (ftnandc023_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out;
++    }
++  out:
++    platform_select_pinmux(nand_fd, -1);
++
++    return status;
++}
++
++static int ftnandc023_nand_write_page_sp(struct mtd_info *mtd, const uint8_t * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6;
++    int i;
++    int status = 0;
++    u32 *lbuf;
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++
++    lbuf = (u32 *) buf;
++    for (i = 0; i < mtd->oobsize; i++)
++        writeb(*(chip->oob_poi + i),
++               data->io_base + SPARE_SRAM + (data->cur_chan << 10) + (data->sel_chip << 6) + i);
++
++    ftnandc023_set_row_col_addr(data);
++
++    writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++    writel(CMD_COUNT(1) | (data->column / mtd->writesize),
++           data->io_base + CMDQUEUE5(data->cur_chan));
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    cq6 |= CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) | CMD_INDEX(SMALL_FIXFLOW_PAGEWRITE);
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    cq6 |= (1 << 4);	//enable handshake
++#endif
++    status = ftnandc023_nand_check_cmdq(mtd);
++    if (status < 0)
++        goto out;
++    writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    memcpy(data->mem_dmabuf, buf, mtd->writesize);
++
++    status = nand_dma_start(data, mtd->writesize, DMA_MEM_TO_DEV);
++    if (status < 0) {
++        printk("nand dma write page sp fail\n");
++        goto out;
++    }
++    ftnandc023_dma_wait(mtd);
++#else
++    for (i = 0; i < mtd->writesize; i += 4)
++        *(volatile unsigned *)(data->chip.IO_ADDR_R) = *lbuf++;
++#endif
++    if (ftnandc023_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out;
++    }
++  out:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc023_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++                                      const uint8_t * buf, int page, int cached, int raw)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc023_nand_data *data = p->priv;
++    int status = 0;
++#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
++    u8 *vbuf;
++    int i;
++#endif
++    data->page_addr = page;
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++
++    status = data->write_page(mtd, buf);
++    if (status < 0)
++        goto out;
++
++#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
++    vbuf = vmalloc(mtd->writesize + mtd->oobsize);
++    memcpy(vbuf + mtd->writesize, chip->oob_poi, mtd->oobsize);
++
++    status = data->read_page(mtd, vbuf);
++    if (status < 0)
++        goto out;
++    for (i = 0; i < mtd->writesize; i++) {
++        if (*(buf + i) != *(vbuf + i)) {
++            printk(KERN_ERR "write verify failed at normal region..");
++            goto out_free;
++        }
++    }
++    for (i = 0; i < mtd->oobsize; i++) {
++        if (*(chip->oob_poi + i) != *(vbuf + mtd->writesize + i)) {
++            printk(KERN_ERR "write verify failed at oob region..\n");
++            goto out_free;
++        }
++    }
++
++  out_free:
++    vfree(vbuf);
++#endif
++  out:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static void ftnandc023_nand_write_page_lowlevel(struct mtd_info *mtd,
++                                                struct nand_chip *chip, const uint8_t * buf)
++{
++}
++
++static void ftnandc023_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
++                                    int column, int page_addr)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    u32 cq6, tmp, i;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    cq6 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    data->cur_cmd = command;
++    if (page_addr != -1)
++        data->page_addr = page_addr;
++    if (column != -1)
++        data->column = column;
++    switch (command) {
++    case NAND_CMD_READID:
++        /* read ID use sector mode, can't use page mode */
++        tmp = readl(data->io_base + SPARE_REGION_ACCESS);
++        writel(tmp & ~(1 << 0), data->io_base + SPARE_REGION_ACCESS);
++        
++        data->byte_ofs = 0;
++        cq6 |= CMD_START_CE(data->sel_chip) | CMD_BYTE_MODE | CMD_SPARE_NUM(4);
++        if (data->large_page)
++            cq6 |= CMD_INDEX(LARGE_FIXFLOW_READID);
++        else
++            cq6 |= CMD_INDEX(SMALL_FIXFLOW_READID);
++        writel(CMD_COUNT(1), data->io_base + CMDQUEUE5(data->cur_chan));
++        ftnandc023_nand_check_cmdq(mtd);
++        writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++
++        ftnandc023_nand_wait(mtd, chip);
++        
++        tmp &= ~SPARE_PAGE_MODE(1);//PC tool use sector mode and enable CRC to r/w page
++        tmp |= SPARE_PROT_EN(1);
++        
++        writel(tmp, data->io_base + SPARE_REGION_ACCESS);
++        break;
++    case NAND_CMD_RESET:
++        cq6 |= CMD_START_CE(data->sel_chip);
++        if (data->large_page) {
++            if (data->flash_type == 3)
++                cq6 |= CMD_INDEX(ONFI_FIXFLOW_SYNCRESET);
++            else
++                cq6 |= CMD_INDEX(LARGE_FIXFLOW_RESET);
++        } else {
++            cq6 |= CMD_INDEX(SMALL_FIXFLOW_RESET);
++        }
++        ftnandc023_nand_check_cmdq(mtd);
++        writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++
++        ftnandc023_nand_wait(mtd, chip);
++        break;
++    case NAND_CMD_STATUS:
++        writel(CMD_COUNT(1), data->io_base + CMDQUEUE5(data->cur_chan));
++        cq6 |= CMD_START_CE(data->sel_chip);
++        if (data->large_page)
++            cq6 |= CMD_INDEX(LARGE_FIXFLOW_READSTATUS);
++        else
++            cq6 |= CMD_INDEX(SMALL_FIXFLOW_READSTATUS);
++        ftnandc023_nand_check_cmdq(mtd);
++        writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++
++        ftnandc023_nand_wait(mtd, chip);
++        break;
++    case NAND_CMD_ERASE1:
++    		write_protect(0);
++        DBGLEVEL2(ftnandc023_dbg("erase page: 0x%x\n", data->page_addr));
++
++        if ((data->page_addr / 32) >= max_chip_size)
++            printk("=========== Please improve max_chip_size ==========\n");
++        //erase one block = N pages
++         
++        tmp = (data->mtd.erasesize / data->mtd.writesize);
++       
++        if (tmp <= 32) {
++            for (i = 0; i < tmp; i++)
++                page_map[data->page_addr / 32] &= ~(1 << (i % 32));
++        } else
++            for (i = 0; i < tmp / 32; i++)
++                page_map[(data->page_addr / 32) + i] = 0;
++
++        writel(data->page_addr, data->io_base + CMDQUEUE1(data->cur_chan));
++        writel(CMD_COUNT(1), data->io_base + CMDQUEUE5(data->cur_chan));
++        if (data->large_page) {
++            ftnandc023_set_row_col_addr(data);
++            cq6 |= CMD_INDEX(LARGE_FIXFLOW_ERASE);
++        } else {
++            ftnandc023_set_row_col_addr(data);
++            cq6 |= CMD_INDEX(SMALL_FIXFLOW_ERASE);
++        }
++        cq6 |= CMD_START_CE(data->sel_chip) | CMD_SCALE(1);
++        ftnandc023_nand_check_cmdq(mtd);
++        writel(cq6, data->io_base + CMDQUEUE6(data->cur_chan));
++        break;
++    case NAND_CMD_ERASE2:
++    case NAND_CMD_PAGEPROG:
++    case NAND_CMD_SEQIN:
++        break;
++    }
++		
++		platform_select_pinmux(nand_fd, -1);
++}
++
++/*
++ * Currently, we have pin mux with SD card
++ */
++static void ftnandc023_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc023_nand_data *data = p->priv;
++    int chn = 0;
++
++    //DBGLEVEL2(ftnandc023_dbg("chip = %d, ", chip));
++    if (data->scan_state != 1) {
++        while (chip != -1) {
++            if (chip < data->valid_chip[chn]) {
++                break;
++            } else {
++                chip = chip - data->valid_chip[chn];
++                chn++;
++            }
++        }
++        data->cur_chan = chn;
++    }
++#ifdef CONFIG_FTNANDC023_HYNIX_HY27US08561A
++    if (chip == 1)
++        data->sel_chip = 2;
++    else if (chip == 2)
++        data->sel_chip = 1;
++    else
++        data->sel_chip = chip;
++#else
++    data->sel_chip = chip;
++#endif
++
++    //DBGLEVEL2(ftnandc023_dbg("==>chan = %d, ce = %d\n", data->cur_chan, data->sel_chip));
++}
++
++/*
++ * Probe for the NAND device.
++ */
++static int __devinit ftnandc023_nand_probe(struct platform_device *pdev)
++{
++    struct ftnandc023_nand_data *data;
++    struct mtd_partition *partitions;
++    int res, chipnum, size;
++    int i, type, free_oob_sz;
++#ifndef CONFIG_PLATFORM_GM8126
++    int partitions_num;
++#endif     
++    u32 val, tmp;
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    dma_cap_mask_t mask;
++#endif    
++    res = chipnum = size = type = 0;
++    /* Allocate memory for the device structure (and zero it) */
++    data = kzalloc(sizeof(struct ftnandc023_nand_data), GFP_KERNEL);
++    if (!data) {
++        dev_err(&pdev->dev, "failed to allocate device structure.\n");
++        res = -ENOMEM;
++        goto out;
++    }
++
++    data->io_base = ioremap_nocache(pdev->resource[0].start,
++                            pdev->resource[0].end - pdev->resource[0].start + 1);
++    printk("NAND reg mapping to addr = 0x%x, phy = 0x%x\n", (u32)data->io_base, (u32)pdev->resource[0].start);
++    if (data->io_base == NULL) {
++        dev_err(&pdev->dev, "ioremap failed for register.\n");
++        res = -EIO;
++        goto out_free_data;
++    }
++    
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    data->nand_dmaaddr = pdev->resource[1].start;
++#else
++    data->chip.IO_ADDR_R = ioremap_nocache(pdev->resource[1].start,
++                                   pdev->resource[1].end - pdev->resource[1].start + 1);
++    //printk("NAND data port mapping to addr = 0x%x, phy = 0x%x\n", (u32)data->chip.IO_ADDR_R, (u32)pdev->resource[1].start);                                   
++    if (data->chip.IO_ADDR_R == NULL) {
++        dev_err(&pdev->dev, "ioremap failed for data port.\n");
++        res = -EIO;
++        goto out_no_ior;
++    }
++  
++#endif
++
++    /* The following setting was done in nsboot already. Actually it don't need to be 
++     * configured again. 
++     */
++    writel(REPORT_ADDR_EN | BUSY_RDY_LOC(6) | CMD_STS_LOC(0) | CE_NUM(0),
++           data->io_base + GENERAL_SETTING);
++
++    /* Currently, it is fixed in LEGACY_LARGE
++     */
++    legacy = LEGACY_LARGE;
++    val = readl(data->io_base + MEM_ATTR_SET);
++    spare = (val >> 16) & 0x3FF;
++    val = readl(data->io_base + ECC_CORRECT_BITREG1);
++#ifdef CONFIG_PLATFORM_GM8126
++    useecc = (val & 0x1F) + 1;
++#else
++    useecc = (val & 0x3F) + 1;
++#endif 
++    eccbasft = ((val >> 16) & 0x1) ? 10 : 9;
++    val = readl(data->io_base + GENERAL_SETTING);
++    usecrc = ((val >> 16) & 0x1) ? 0 : 1;
++    data->flash_type = 0;
++    data->large_page = 1;
++
++        /*-----------------------------------------------------------
++	 * For ONFI or Toggle High Speed Flash, need to adjust delay.
++	 */
++    if (data->flash_type > LEGACY_LARGE) {
++        val = readl(data->io_base + DQS_DELAY);
++        val &= ~0x1F;
++        val |= 10;
++        writel(val, data->io_base + DQS_DELAY);
++    }
++    
++    val = readl(data->io_base + MEM_ATTR_SET);
++
++    data->chip.priv = data;
++    data->mtd.priv = &data->chip;
++    data->mtd.owner = THIS_MODULE;
++    data->mtd.name = "nand-flash";//u-boot commandline
++    data->dev = &pdev->dev;
++    data->chip.IO_ADDR_W = data->chip.IO_ADDR_R;
++    data->chip.select_chip = ftnandc023_nand_select_chip;
++    data->chip.cmdfunc = ftnandc023_nand_cmdfunc;
++    data->chip.read_byte = ftnandc023_read_byte;
++    data->chip.write_page = ftnandc023_nand_write_page;
++    data->chip.waitfunc = ftnandc023_nand_wait;
++    data->chip.block_markbad = ftnandc023v2_block_markbad;
++    data->chip.chip_delay = 0;
++    //data->chip.options = NAND_BBT_USE_FLASH | NAND_NO_SUBPAGE_WRITE | NAND_OWN_BUFFERS;
++    data->chip.options = NAND_NO_SUBPAGE_WRITE | NAND_OWN_BUFFERS;      /* remove NAND_BBT_USE_FLASH */
++
++    platform_set_drvdata(pdev, data);
++
++    data->scan_state = 1;
++
++        /*--------------------------------------------------------
++	 * ONFI flash must work in Asynch mode for READ ID command.
++	 * Switch it back to Legacy.
++	 */
++    if (data->flash_type == ONFI) {
++        type = data->flash_type;
++        data->flash_type = 0;
++    }
++    /* Scan to find existance of the device */
++    for (i = startchn; i < MAX_CHANNEL; i++) {
++        //printk(KERN_INFO "NAND: Scan Channel %d...\n", i);
++
++        data->cur_chan = i;
++        if (!nand_scan_ident(&data->mtd, MAX_CE, NULL)) {
++            if ((0xFFFFFFFF - size) > (data->mtd.size)
++                && ((chipnum + data->chip.numchips) <= NAND_MAX_CHIPS)) {
++                data->valid_chip[i] = data->chip.numchips;
++                chipnum += data->chip.numchips;
++                size += (chipnum * data->chip.chipsize);
++            } else {
++                printk(KERN_INFO "Can not accept more flash chips.\n");
++                break;
++            }
++        }
++    }
++
++    if (chipnum == 0) {
++        res = -ENXIO;
++        goto out_unset_drv;
++    }
++
++    data->chip.numchips = chipnum;
++    data->mtd.size = size;
++    data->scan_state = 0;
++
++    data->chip.ecc.layout = &nand_hw_eccoob;
++    data->chip.bbt_td = &ftnandc023_bbt_main_descr;
++    data->chip.bbt_md = &ftnandc023_bbt_mirror_descr;
++    data->chip.badblock_pattern = &ftnandc023_largepage_flashbased;
++
++    /* check spare size */
++    if (spare != (data->mtd.writesize >> 5)) {
++        printk("Warning............NAND: the spare size %d(%d) is wrong! \n", data->mtd.writesize >> 5, spare);
++        res = -ENODEV;
++    }
++
++    if (data->mtd.writesize == 2048)
++        tmp = 1;
++    else if (data->mtd.writesize == 4096)
++        tmp = 2;
++    else if (data->mtd.writesize == 8192)
++        tmp = 3;
++    else
++        tmp = -1;
++
++    /* check page size */
++    if (tmp != (val & 0x3)) {
++        printk("Warning............NAND: the page size %d is wrong! \n", data->mtd.writesize);
++        res = -ENODEV;
++    }
++
++    /* check block size */
++    tmp = (data->mtd.erasesize / data->mtd.writesize) - 1;
++    if (tmp != ((val >> 2) & 0x3FF)) {
++        printk("Warning............NAND: the block size %d is wrong! \n", data->mtd.erasesize);
++        res = -ENODEV;
++    }
++
++    data->chip.buffers = kmalloc(data->mtd.writesize + (spare << 2), GFP_KERNEL);
++    if (!data->chip.buffers) {
++        dev_err(&pdev->dev, "failed to allocate chip buffers.\n");
++        res = -ENOMEM;
++        goto out_unset_drv;
++    }
++
++    data->chip.ecc.mode = NAND_ECC_HW;
++        
++    data->chip.ecc.size = data->mtd.writesize;
++    data->chip.ecc.bytes = 0;
++    data->chip.ecc.read_page = ftnandc023_nand_read_page;
++    data->chip.ecc.write_page = ftnandc023_nand_write_page_lowlevel;
++    data->chip.ecc.read_oob = ftnandc023_nand_read_oob_std;
++    data->chip.ecc.write_oob = ftnandc023_nand_write_oob_std;
++    data->chip.ecc.read_page_raw = ftnandc023_nand_read_page;
++
++    if (data->large_page) {
++        data->read_page = ftnandc023_nand_read_page_lp;
++        data->write_page = ftnandc023_nand_write_page_lp;
++        data->read_oob = ftnandc023_nand_read_oob_lp;
++        data->write_oob = ftnandc023_nand_write_oob_lp;
++    } else {
++        data->read_page = ftnandc023_nand_read_page_sp;
++        data->write_page = ftnandc023_nand_write_page_sp;
++        data->read_oob = ftnandc023_nand_read_oob_sp;
++        data->write_oob = ftnandc023_nand_write_oob_sp;
++    }
++
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    dma_cap_set(DMA_SLAVE, data->cap_mask);
++    
++#ifdef CONFIG_NAND_USE_AHBDMA
++    printk("use AHB DMA mode\n");    
++    {
++    	struct ftdmac020_dma_slave slave;
++    	memset(&slave, 0, sizeof(slave));
++    	data->dma_chan = dma_request_channel(data->cap_mask, ftdmac020_chan_filter, (void *)&slave);//step 1
++    }
++#else
++    ftpmu010_write_reg(nand_fd, 0xA4, (0x0 << 27), (0x1 << 27));
++    printk("use AXI DMA mode\n");
++    {
++    	struct ftdmac030_dma_slave slave;
++    	memset(&slave, 0, sizeof(slave));
++    	data->dma_chan = dma_request_channel(data->cap_mask, ftdmac030_chan_filter, (void *)&slave);//step 1
++    }  
++#endif
++
++    if (!data->dma_chan){
++        dev_err(&pdev->dev, "DMA channel allocation failed\n");
++        res = -ENODEV;
++        goto out_free_buf;
++    }
++    printk("Nand get DMA channel %d\n", data->dma_chan->chan_id);
++
++    data->mem_dmabuf = dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->mem_dmaaddr, GFP_KERNEL);
++//printk("vir=%x, phy=%x\n",data->mem_dmabuf,data->mem_dmaaddr);
++    if (!data->mem_dmabuf) {
++        res = -ENOMEM;
++        goto out_free_dma;
++    }
++    data->sg_dmabuf = dma_to_virt(&pdev->dev, data->mem_dmaaddr);
++      
++    //printk("sg mem pa = 0x%x, va = 0x%x\n", (u32)data->mem_dmaaddr, (u32)data->sg_dmabuf);
++
++#else
++    printk("use PIO mode\n");    
++#endif
++
++    /* read the system header first 
++     */
++    if (1) {
++        /* first disble ecc due to potential different ecc capability 
++         */
++        unsigned int usr_base;
++        
++#ifdef CONFIG_PLATFORM_GM8126 
++        unsigned int blk_base, cfg_base;       
++        img_hdr_t *img_hdr;
++#endif
++        
++        /* read system header 
++         */
++        //data->sys_hdr = kzalloc(data->mtd.writesize, GFP_KERNEL);
++        data->sys_hdr = dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->syshd_dmaaddr, GFP_KERNEL);
++        if (data->sys_hdr == NULL) {
++            printk("Warning............NAND: no memory");
++            return -ENOMEM;
++        }
++        data->page_addr = 0;
++        data->chip.oob_poi = data->chip.buffers->databuf + data->mtd.writesize;
++
++        if (data->read_page(&data->mtd, (u_char *) data->sys_hdr) < 0) {
++            printk("Warning............NAND: read system header fail!");
++            return -ENODEV;
++        }
++
++        /* read bad block table 
++         */  
++        //data->bi_table = kzalloc(data->mtd.writesize, GFP_KERNEL);
++        data->bi_table = dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->bitab_dmaaddr, GFP_KERNEL);
++        if (data->bi_table == NULL) {
++            printk("Warning............NAND: no table memory");
++            return -ENOMEM;
++        }
++        /* the bi table is next to system header */
++        data->page_addr += 1;
++#if 0//debug
++        memset(data->bi_table, 0xFF, 1024);
++#else        
++        if (data->read_page(&data->mtd, (u_char *) data->bi_table) < 0) {
++            printk("Warning............NAND: read bad block table fail!");
++            return -ENODEV;
++        }
++#endif
++            
++#ifdef CONFIG_PLATFORM_GM8126 
++        blk_base = ftnandc023v2_get_blockbase(&data->mtd, data->sys_hdr->linux_addr);        
++        data->page_addr = blk_base >> data->chip.page_shift;
++
++        img_hdr = kmalloc(data->mtd.writesize, GFP_KERNEL);
++        if (img_hdr == NULL)
++            printk("Warning............NAND: allocate memory fail!");
++
++        if (data->read_page(&data->mtd, (u_char *) img_hdr) < 0)
++            printk("Warning............NAND: read bad block table fail!");
++
++        if (img_hdr->magic != IMAGE_MAGIC) {
++            printk("NAND:The expected magic number is 0x%x, but we got 0x%x \n",
++                   IMAGE_MAGIC, img_hdr->magic);
++            printk("Warning............wrong magic number!");
++        }
++#endif
++        partitions = ftnandc023_partition_info;
++        
++#ifndef CONFIG_PLATFORM_GM8126
++
++        partitions_num = partition_check(partitions, data, data->mtd.writesize); 
++#else 
++        /* 
++         * arrange the MTD partition, PORTING 
++         */ 
++        /* loader, nsboot.bin */
++        partitions[MTD_PART_LOADER].offset =
++            ftnandc023v2_get_blockbase(&data->mtd, (1 << data->chip.bbt_erase_shift));
++            
++        /* uboot */
++        partitions[MTD_PART_UBOOT].offset =
++            ftnandc023v2_get_blockbase(&data->mtd, data->sys_hdr->uboot_addr);  
++        /* burn-in */
++        partitions[MTD_PART_BURNIN].offset =
++            ftnandc023v2_get_blockbase(&data->mtd, data->sys_hdr->burnin_addr);
++            
++        /* cfg */
++        cfg_base = data->sys_hdr->linux_addr - MTD_CFG_SZ;
++        partitions[MTD_PART_CFG].offset = ftnandc023v2_get_blockbase(&data->mtd, cfg_base);
++
++        if (partitions[MTD_PART_CFG].offset <= partitions[MTD_PART_UBOOT].offset + (2 * DEFAULT_BLOCK_SIZE))
++            printk("Warning............NAND: uboot space %#x is too small!\n",
++                  data->sys_hdr->linux_addr - data->sys_hdr->uboot_addr); 
++                  
++        /* linux */
++        partitions[MTD_PART_LINUX].offset =
++            ftnandc023v2_get_blockbase(&data->mtd, data->sys_hdr->linux_addr); 
++            
++        /* 
++         * calculate every partition's MTD size
++         */            
++        /* loader */
++        partitions[MTD_PART_LOADER].size =
++            partitions[MTD_PART_BURNIN].offset - partitions[MTD_PART_LOADER].offset;
++        /* burn-in */
++        partitions[MTD_PART_BURNIN].size =
++            partitions[MTD_PART_UBOOT].offset - partitions[MTD_PART_BURNIN].offset;
++        /* uboot */
++        partitions[MTD_PART_UBOOT].size =
++            partitions[MTD_PART_CFG].offset - partitions[MTD_PART_UBOOT].offset;
++        /* cfg */
++        partitions[MTD_PART_CFG].size =
++            partitions[MTD_PART_LINUX].offset - partitions[MTD_PART_CFG].offset;
++            
++        /* sanity check to see if the space is big enough (including header) */
++        if ((img_hdr->size + data->mtd.writesize + (8 * DEFAULT_BLOCK_SIZE)) > MTD_LINUX_SZ)
++            printk("Warning............NAND: please redefine MTD_LINUX_SZ: %#x \n", MTD_LINUX_SZ);  
++            
++        /* linux, image header + image size */
++        partitions[MTD_PART_LINUX].size = BLOCK_ALIGN(MTD_LINUX_SZ, data->chip.bbt_erase_shift);                      
++#endif
++
++        /* 
++         * calculate the mtd of user configuration base
++         */
++        /* user partition */         
++#ifndef CONFIG_PLATFORM_GM8126 
++        usr_base = data->sys_hdr->image[partitions_num].addr + data->sys_hdr->image[partitions_num].size + (2 * data->mtd.writesize);
++        partitions[partitions_num].offset = ftnandc023v2_get_blockbase(&data->mtd, usr_base);
++#else         
++        usr_base = partitions[MTD_PART_LINUX].offset + partitions[MTD_PART_LINUX].size;
++        partitions[MTD_PART_USER].offset = ftnandc023v2_get_blockbase(&data->mtd, usr_base);
++        
++        kfree(img_hdr);        
++#endif        
++        /* restore the orginal setting */
++        data->page_addr = 0;
++    }
++
++    avail_oob_sz = i = ftnandc023_available_oob(&data->mtd);
++    /* default value */
++    free_oob_sz = 3 /* bytes */  * (data->mtd.writesize >> eccbasft);
++#ifdef CONFIG_YAFFS_FS
++    free_oob_sz = 16;
++#endif
++    if (likely(i >= free_oob_sz)) {
++        if (i > 64)
++            data->mtd.oobsize = 64;
++        else
++            data->mtd.oobsize = i;
++        data->chip.ecc.layout->oobfree[0].length = data->mtd.oobsize;
++    } else {
++        printk("NAND: oob size is too small! \n");
++        res = -ENXIO;
++        goto out_unset_drv;
++    }
++
++    printk("NAND Chip: oobsize:%#x, pagesize:%#x, blocksize:%#x, chipsize:%#x, "
++           "ECC capbility is %d bits, CRC protection is %s\n",
++           (int)spare, (int)data->mtd.writesize, (int)data->mtd.erasesize, (int)data->chip.chipsize,
++           useecc, usecrc ? "enabled" : "disabled");
++
++#if 1                           /* Harry, in MTD utility, the oobsize should be multiple of 64. We should be on the way. */
++    data->mtd.oobsize = spare;
++    spare = (avail_oob_sz / (data->mtd.writesize >> eccbasft)) - 1;
++#else
++    printk("NAND: total oobsize: %d\n", data->mtd.oobsize);
++    spare = (data->mtd.oobsize / (data->mtd.writesize >> eccbasft)) - 1;
++    printk("NAND: oobsize per sector: %d\n", spare + 1);
++#endif
++    /* Scan bad block and create bbt table
++     */
++    nand_scan_tail(&data->mtd);
++
++        /*----------------------------------------------------------
++	 * ONFI synch mode means High Speed. If fails to change to
++	 * Synch mode, then use flash as Async mode(Normal speed) and
++	 * use LEGACY_LARGE fix flow.
++	 */
++    if (type == ONFI) {
++        if (ftnandc023_onfi_sync(&data->mtd) == 0)
++            data->flash_type = ONFI;
++        else
++            data->flash_type = 0;
++    }
++
++    ftnandc023_calc_timing(&data->mtd);
++#ifndef CONFIG_PLATFORM_GM8126
++    res = mtd_device_parse_register(&data->mtd, NULL, 0, partitions, partitions_num);
++#else    
++    res = mtd_device_parse_register(&data->mtd, NULL, 0, partitions, ARRAY_SIZE(ftnandc023_partition_info));
++#endif    
++    if (!res)
++        return res;
++
++    nand_release(&data->mtd);
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++  out_free_dma:
++    if(data->dma_chan)
++    	dma_release_channel(data->dma_chan);
++  out_free_buf:
++#endif
++    kfree(data->chip.buffers);
++
++  out_unset_drv:
++    platform_set_drvdata(pdev, NULL);
++
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    if(data->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->mem_dmabuf, data->mem_dmaaddr);
++#else
++  out_no_ior:
++    iounmap(data->chip.IO_ADDR_R);
++#endif
++    iounmap(data->io_base);
++  out_free_data:
++    if (data->sys_hdr)
++        kfree(data->sys_hdr);
++    if (data->bi_table)
++        kfree(data->bi_table);
++    kfree(data);
++  out:
++    return res;
++}
++
++/*
++ * @consult with bad block table about this block is good or bad.
++ *
++ * @ftnandc_read_bbt(struct mtd_info *mtd, loff_t offs)
++ * @param mtd: MTD device structure
++ * @param offs: block base address
++ * @return: 1 for bad block, 0 for good block
++*/
++int ftnandc_read_bbt(struct mtd_info *mtd, loff_t offs)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    unsigned int *bi_table = (unsigned int *)data->bi_table;
++    int quotient, remainder, blk_id, result;
++
++    blk_id = offs >> chip->bbt_erase_shift;
++    quotient = blk_id >> 5;
++    remainder = blk_id & 0x1F;
++    result = (bi_table[quotient] >> remainder) & 0x1;
++    
++    if (result == 1)
++        return 0;               /* good */
++
++    return 1;                   /* bad */
++}
++
++unsigned char spare_buf[64] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7
++															,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7
++															,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7
++															,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7};
++
++extern int erase_write_block0 (struct mtd_info *mtd, unsigned long pos, int len, const char *buf);
++/**
++ * ftnandc023v2_default_block_markbad - mark a block bad
++ * @mtd:	MTD device structure
++ * @ofs:	offset from device start
++ *
++ * This is the default implementation, which can be overridden by
++ * a hardware specific driver.
++*/
++static int ftnandc023v2_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc023_nand_data *data = chip->priv;
++	unsigned int *bi_table = (unsigned int *)data->bi_table;
++	int ret = 0;
++	int quotient, remainder, blk_id, result;
++	size_t retlen;
++
++    printk("markbad, addr = 0x%x\n", (int)ofs);
++
++	/* Get block number */
++	blk_id = (int)(ofs >> chip->bbt_erase_shift);
++	if (data->bi_table){
++	    blk_id = ofs >> chip->bbt_erase_shift;
++	    quotient = blk_id >> 5;
++	    remainder = blk_id & 0x1F;
++    	result = (bi_table[quotient] >> remainder) & 0x1;
++    	//printk("BI table %dth, bit %d, data = 0x%x, result = %d\n", quotient, remainder, bi_table[quotient], result);
++    	if (result == 0)/* bad block, not need to do it */
++      	return 0;               
++	    
++	    bi_table[quotient] &= ~(1 << remainder);/* Write the block mark. */
++	    blk_id <<= 1;
++	    //printk("blk_id %dth, data = 0x%x, result = %x\n", blk_id, chip->bbt[blk_id >> 3], (0x3 << (blk_id & 0x06)));
++	    chip->bbt[blk_id >> 3] |= (0x3 << (blk_id & 0x06));	 	    
++	}
++
++	ret = erase_write_block0(mtd, 0, mtd->writesize, (const uint8_t *)data->sys_hdr);
++	if (ret < 0)
++		printk("Markbad Step 1 Error\n");
++
++	ret = mtd_write(mtd, mtd->writesize, mtd->writesize, &retlen, (const uint8_t *)bi_table);
++	if (ret < 0)
++		printk("Markbad Step 2 Error\n");
++
++	return ret;
++}
++
++/*
++ * @get block baseaddr. It skips the bad block as well.
++ *
++ * @ftnandc023v2_get_blockbase(struct mtd_info *mtd, unsigned int base_addr)
++ * @param mtd: MTD device structure
++ * @param base_addr: liner base address
++ * @return: good block address
++*/
++unsigned int ftnandc023v2_get_blockbase(struct mtd_info *mtd, unsigned int base_addr)
++{
++    struct nand_chip *chip = mtd->priv;
++    unsigned int block_base;
++
++    block_base = BLOCK_ALIGN(base_addr, chip->bbt_erase_shift);
++
++    while (ftnandc_read_bbt(mtd, (loff_t) block_base) != 0)        /* find good block */
++        block_base += (0x1 << chip->bbt_erase_shift);   //move to next block
++
++    return block_base;
++}
++
++/*
++ * Remove a NAND device.
++ */
++static int __devexit ftnandc023_nand_remove(struct platform_device *pdev)
++{
++    struct ftnandc023_nand_data *data = platform_get_drvdata(pdev);
++
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    if(data->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->mem_dmabuf, data->mem_dmaaddr);
++    if(data->dma_chan)
++    	dma_release_channel(data->dma_chan);
++#endif
++    if(data->sys_hdr)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->sys_hdr, data->syshd_dmaaddr);
++    if(data->bi_table)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->bi_table, data->bitab_dmaaddr);
++    nand_release(&data->mtd);
++    iounmap(data->io_base);
++    kfree(data->chip.buffers);
++    kfree(data);
++
++    return 0;
++}
++
++static void ftnandc023_release(struct device *dev)
++{
++}
++
++static u64 ftnandc023_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftnandc023_device = {
++    .name = "ftnandc023_nand",
++    .id = -1,
++    .num_resources = ARRAY_SIZE(ftnandc023_resource),
++    .resource = ftnandc023_resource,
++    .dev = {
++            .dma_mask = &ftnandc023_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            .release = ftnandc023_release,
++            },
++};
++
++static struct platform_driver ftnandc023_nand_driver = {
++    .probe = ftnandc023_nand_probe,
++    .remove = __devexit_p(ftnandc023_nand_remove),
++    .driver = {
++               .name = "ftnandc023_nand",
++               .owner = THIS_MODULE,
++               },
++};
++
++static int __init ftnandc023_nand_init(void)
++{
++    int ret = 0;
++    
++#ifdef CONFIG_PLATFORM_GM8210
++		fmem_pci_id_t pci_id;
++		fmem_cpu_id_t cpu_id;
++		fmem_get_identifier(&pci_id, &cpu_id);
++		if((cpu_id != FMEM_CPU_FA726) || (pci_id != FMEM_PCI_HOST))
++			return 0;
++#endif
++    /* check if the system is running NAND system 
++     */   
++#if defined(CONFIG_PLATFORM_GM8210) || defined(CONFIG_PLATFORM_GM8126) || defined(CONFIG_PLATFORM_GM8287)
++    if (platform_check_flash_type() != 0){
++        printk("Not for NAND pin mux\n");
++        return 0;
++    }
++#endif
++
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    init_waitqueue_head(&nand023_queue);
++#endif    
++    /* Register PMU and turn on gate clock
++     */
++    nand_fd = ftpmu010_register_reg(&pmu_reg_info);
++    if (nand_fd < 0) {
++        printk("Warning............NANDC: register PMU fail");
++        ret = -ENODEV;
++    }
++
++#ifdef CONFIG_GPIO_WP
++    if ((ret = gpio_request(GPIO_PIN, PIN_NAME)) != 0) {
++        printk("gpio request fail\n");
++        return ret;
++    }
++    printk("register GPIO for NAND write protect\n");
++#endif
++
++    if (platform_device_register(&ftnandc023_device)) {
++        printk(KERN_ERR "device register failed\n");
++        ret = -ENODEV;
++    }
++    if (platform_driver_register(&ftnandc023_nand_driver)) {
++        printk(KERN_ERR "driver register failed\n");
++        ret = -ENODEV;
++    }
++    return ret;
++}
++
++static void __exit ftnandc023_nand_exit(void)
++{
++    /* check if the system is running NAND system 
++     */
++#if defined(CONFIG_PLATFORM_GM8210) || defined(CONFIG_PLATFORM_GM8126) || defined(CONFIG_PLATFORM_GM8287)
++    if (platform_check_flash_type() != 0)
++        return;
++#endif
++    /* Deregister PMU
++     */
++    ftpmu010_deregister_reg(nand_fd);
++
++    platform_driver_unregister(&ftnandc023_nand_driver);
++    platform_device_unregister(&ftnandc023_device);
++}
++
++#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++/*
++ * @callback function from DMAC module
++ *
++ * @ftnandc023_dma_callback int func(int ch, u16 int_status, void *data)
++ * @param ch is used to indicate DMA channel
++ * @param int_status indicates the interrupt status of DMA controller
++ * @param data indicates the private data
++ * @return: none
++*/
++void ftnandc023_dma_callback(void *param)
++{
++    //printk("%s\n", __func__);
++
++    trigger_flag = 1;
++    wake_up(&nand023_queue);
++
++    return;
++}
++#endif
++
++module_init(ftnandc023_nand_init);
++module_exit(ftnandc023_nand_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Te-Chen Ying");
++MODULE_DESCRIPTION("FTNANDC023 V2.0 NAND driver");
++MODULE_ALIAS("platform:ftnandc023_nand");
+diff --git a/drivers/mtd/nand/ftnandc023v2_nand.h b/drivers/mtd/nand/ftnandc023v2_nand.h
+new file mode 100644
+index 00000000..3eb62490
+--- /dev/null
++++ b/drivers/mtd/nand/ftnandc023v2_nand.h
+@@ -0,0 +1,215 @@
++/* general register difinition */
++#define ECC_CONTROL			0x8
++#define	  ECC_ERR_MASK(x)		(x << 0)
++#define	  ECC_EN(x)			(x << 8)
++#define	  ECC_BASE			(1 << 16)
++#define	  ECC_NO_PARITY			(1 << 17)
++#define ECC_THRES_BITREG1		0x10
++#define	ECC_THRES_BITREG2		0x14
++#define ECC_CORRECT_BITREG1		0x18
++#define	ECC_CORRECT_BITREG2		0x1C
++#define	ECC_INTR_EN			0x20
++#define	  ECC_INTR_THRES_HIT		(1 << 1)
++#define	  ECC_INTR_CORRECT_FAIL		(1 << 0)
++#define	ECC_INTR_STATUS			0x24
++#define	  ECC_ERR_THRES_HIT(x)		(1 << (8 + x))
++#define	  ECC_ERR_FAIL(x)		(1 << x)
++#define	DEV_BUSY			0x100
++#define GENERAL_SETTING			0x104
++#define	  CE_NUM(x)			(x << 24)
++#define	  BUSY_RDY_LOC(x)		(x << 12)
++#define	  CMD_STS_LOC(x)		(x << 8)
++#define	  REPORT_ADDR_EN		(1 << 4)
++#define	  WRITE_PROTECT			(1 << 2)
++#define	  DATA_INVERSE			(1 << 1)
++#define	  DATA_SCRAMBLER		(1 << 0)
++#define MEM_ATTR_SET			0x108
++#define	  ATTR_COL_CYCLE(x)		(x << 12)
++#define	  ATTR_ROW_CYCLE(x)		(x << 13)
++#define	SPARE_REGION_ACCESS		0x10C
++#define	  SPARE_PAGE_MODE(x)		(x << 0)
++#define	  SPARE_PROT_EN(x)		(x << 8)
++
++#define	FL_AC_TIMING0(x)		(0x110 + (x << 3))
++#define	FL_AC_TIMING1(x)		(0x114 + (x << 3))
++#define FL_AC_TIMING2(x)		(0x190 + (x << 3))
++#define FL_AC_TIMING3(x)		(0x194 + (x << 3))
++#define INTR_ENABLE             0x150
++#define STS_FAIL_INT_EN(x)      (0x1 << x)
++#define CRC_FAIL_INT_EN(x)      (0x1 << (x + 8))
++#define INTR_STATUS			0x154
++#define	  STATUS_CMD_COMPLETE(x)	(1 << (16 + x))
++#define	  STATUS_CRC_FAIL(x)		(1 << (8 + x))
++#define	  STATUS_FAIL(x)		(1 << x)
++#define READ_STATUS0			0x178
++#define CMDQUEUE_STATUS			0x200
++#define	  CMDQUEUE_STATUS_FULL(x)	(1 << (8 + x))
++
++#define	CMDQUEUE1(x)			(0x300 + (x << 5))
++#define	CMDQUEUE2(x)			(0x304 + (x << 5))
++#define	CMDQUEUE3(x)			(0x308 + (x << 5))
++#define	CMDQUEUE4(x)			(0x30C + (x << 5))
++#define	CMDQUEUE5(x)			(0x310 + (x << 5))
++#define	  CMD_COUNT(x)			(x << 16)
++#define	CMDQUEUE6(x)			(0x314 + (x << 5))
++#define	  CMD_COMPLETE_EN		(1 << 0)
++#define	  CMD_WAIT_EN			(1 << 1)
++#define	  CMD_SCALE(x)			(x << 2)
++#define	  CMD_INDEX(x)			(x << 8)
++#define	  CMD_SPARE_NUM(x)		(x << 18)
++#define	  CMD_BYTE_MODE			(1 << 26)
++#define	  CMD_START_CE(x)		(x << 27)
++#define	  CMD_FLASH_TYPE(x)		(x << 30)
++
++#define	BMC_REGION_STATUS		0x400
++#define	REGION_SW_RESET		0x428
++#define AHB_SLAVEPORT_SIZE		0x508
++#define	GLOBAL_RESET			0x50C
++#define	AHB_RESET			0x510
++#define DQS_DELAY			0x518
++#define	SPARE_SRAM			0x1000
++
++/* FIX_FLOW_INDEX for small page */
++#define		SMALL_FIXFLOW_READSTATUS	0x29
++#define		SMALL_FIXFLOW_READID		0x1B
++#define		SMALL_FIXFLOW_RESET		0x21
++#define		SMALL_FIXFLOW_READOOB		0x39
++#define		SMALL_FIXFLOW_PAGEREAD		0x2E
++#define		SMALL_FIXFLOW_PAGEWRITE		0x5C
++#define		SMALL_FIXFLOW_WRITEOOB		0x67
++#define		SMALL_FIXFLOW_ERASE		0xA9
++
++/* FIX_FLOW_INDEX for large page */
++#define		LARGE_FIXFLOW_READID		0x4F
++#define		LARGE_FIXFLOW_RESET		0x55
++#define		LARGE_FIXFLOW_READSTATUS	0x93
++#define		LARGE_FIXFLOW_READOOB		0x3A
++#define		LARGE_FIXFLOW_PAGEREAD		0x44
++#define		LARGE_FIXFLOW_PAGEWRITE		0x25
++#define		LARGE_FIXFLOW_WRITEOOB		0x30
++#define		LARGE_FIXFLOW_ERASE		0x58
++
++/* TBD */
++#ifdef NAND023_V11
++#undef LARGE_FIXFLOW_READID
++#define LARGE_FIXFLOW_READID    0x51
++#undef LARGE_FIXFLOW_RESET
++#define LARGE_FIXFLOW_RESET     0x57
++#undef LARGE_FIXFLOW_READSTATUS
++#define LARGE_FIXFLOW_READSTATUS    0x63
++#undef LARGE_FIXFLOW_READOOB
++#define LARGE_FIXFLOW_READOOB   0x20
++#undef LARGE_FIXFLOW_PAGEREAD
++#define LARGE_FIXFLOW_PAGEREAD  0x00
++#undef LARGE_FIXFLOW_WRITEOOB
++#define LARGE_FIXFLOW_WRITEOOB  0x44
++#undef LARGE_FIXFLOW_ERASE
++#define LARGE_FIXFLOW_ERASE     0x82
++#undef LARGE_FIXFLOW_PAGEWRITE
++#define LARGE_FIXFLOW_PAGEWRITE 0x0F    //pagewrite with spare
++#endif
++
++/* FIX_FLOW_INDEX for ONFI change mode */
++#define		ONFI_FIXFLOW_GETFEATURE		0x34B
++#define		ONFI_FIXFLOW_SETFEATURE		0x352
++#define		ONFI_FIXFLOW_SYNCRESET		0x33A
++
++#define		MAX_CE				1   //4
++#define		MAX_CHANNEL			1   //2
++//#define		NAND_USE_AHBDMA_CHANNEL		0
++
++#ifdef MODULE
++#undef CONFIG_MTD_NAND_FTNANDC023
++#define CONFIG_FTNANDC023_USE_DMA
++
++/* ONFI 2.0 4K MLC */
++#undef CONFIG_FTNANDC023_MICRON_29F32G08CBABB
++/* Toggle 8K MLC*/
++#undef CONFIG_FTNANDC023_SAMSUNG_K9HDGD8X5M
++/* 2K SLC */
++#undef CONFIG_FTNANDC023_SAMSUNG_K9F4G08U0A
++/* 8K MLC */
++#undef CONFIG_FTNANDC023_TOSHIBA_TH58NVG5D2ETA20
++/* 4K MLC */
++#undef CONFIG_FTNANDC023_MICRON_29F16G08MAA
++/* 512B SLC */
++#undef CONFIG_FTNANDC023_HYNIX_HY27US08561A
++/* 4K MLC */
++#undef CONFIG_FTNANDC023_SAMSUNG_K9LBG08U0M
++#endif
++
++#ifndef CONFIG_FTNANDC023_DEBUG
++#define CONFIG_FTNANDC023_DEBUG			0
++#endif
++#if CONFIG_FTNANDC023_DEBUG > 0
++#define ftnandc023_dbg(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__);
++#else
++#define ftnandc023_dbg(fmt, ...) do {} while (0);
++#endif
++
++#if CONFIG_FTNANDC023_DEBUG > 0
++#define DBGLEVEL1(x)	x
++#else
++#define DBGLEVEL1(x)
++#endif
++
++#if CONFIG_FTNANDC023_DEBUG > 1
++#define DBGLEVEL2(x)	x
++#else
++#define DBGLEVEL2(x)
++#endif
++
++typedef enum {
++	LEGACY_SMALL = 0,
++	LEGACY_LARGE,
++	TOGGLE,
++	ONFI,
++} flashtype;
++
++struct ftnandc023_nandchip_attr {
++	char *name;
++	int sparesize;
++	int pagesize;
++	int blocksize;	
++	int flashsize;
++	flashtype legacy;
++};
++
++struct ftnandc023_chip_timing {
++	uint16_t		tWH;
++	uint16_t		tWP;
++	uint16_t		tREH;
++	uint16_t		tREA;
++	uint16_t		tRP;
++	uint16_t		tWB;
++	uint16_t		tRB;
++	uint16_t		tWHR;
++	uint16_t		tWHR2;
++	uint16_t		tRHW;
++	uint16_t		tRR;
++	uint16_t		tAR;
++	uint16_t		tADL;
++	uint16_t		tRHZ;
++	uint16_t		tCCS;
++	uint16_t		tCS;
++	uint16_t		tCLS;
++	uint16_t		tCLR;
++	uint16_t		tALS;
++	uint16_t		tCALS2;
++	uint16_t		tCWAW;
++	uint16_t		tWPRE;
++	uint16_t		tRPRE;
++	uint16_t		tWPST;
++	uint16_t		tRPST;
++	uint16_t		tWPSTH;
++	uint16_t		tRPSTH;
++	uint16_t		tDQSHZ;
++	uint16_t		tCAD;
++	uint16_t		tDSL;
++	uint16_t		tDSH;
++	uint16_t		tDQSL;
++	uint16_t		tDQSH;
++	uint16_t		tCKWR;
++	uint16_t		tWRCK;
++};
++
+diff --git a/drivers/mtd/nand/ftnandc024v2_nand.c b/drivers/mtd/nand/ftnandc024v2_nand.c
+new file mode 100644
+index 00000000..8dfab420
+--- /dev/null
++++ b/drivers/mtd/nand/ftnandc024v2_nand.c
+@@ -0,0 +1,3036 @@
++/*
++ * FTnandc024 NAND driver
++ *
++ * 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 <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/vmalloc.h>
++#include <linux/dma-mapping.h>
++#include <linux/jiffies.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <mach/platform/platform_io.h>
++#include <mach/ftpmu010.h>
++#include <linux/gpio.h>
++#include "ftnandc024v2_nand.h"
++#include <linux/delay.h>
++/*
++ * Local function or variables declaration
++ */
++//#undef CONFIG_NAND_V2_USE_AHBDMA//???
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++#include <linux/dmaengine.h>
++
++#ifdef CONFIG_NAND_V2_USE_AHBDMA
++#include <mach/ftdmac020.h>
++#else
++#include <mach/ftdmac030.h>
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8139
++#define AHBMASTER_R_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_R_DST   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_SRC   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_DST   FTDMA020_AHBMASTER_0
++#define DMA_NANDC_REQ    2 
++#endif
++
++static void ftnandc024_dma_callback(void *param);
++static volatile unsigned int trigger_flag = 0;
++static wait_queue_head_t nand024_queue;
++struct ftnandc024_nand_data;
++static int nand_dma_start(struct ftnandc024_nand_data *data, size_t len, int direct);
++#endif 
++
++#define PORTING 
++static int ftnandc024v2_block_markbad(struct mtd_info *mtd, loff_t ofs);
++static unsigned int ftnandc024v2_get_blockbase(struct mtd_info *mtd, unsigned int base_addr);
++static int nand_fd;
++
++/*
++ * Macro definitions
++ */
++#define DEFAULT_BLOCK_SIZE  0x20000 
++#define MTD_CFG_SZ          (6 * DEFAULT_BLOCK_SIZE)	//2 block + reserved
++
++#define AHB_Memory_8KByte   (1 << 4)
++#define CONFIG_FTnandc024_START_CHANNEL     0
++#define BLOCK_ALIGN(base, blk_shift) ((((base) + (0x1 << (blk_shift)) - 1) >> (blk_shift)) << (blk_shift))
++
++#ifdef CONFIG_GPIO_WP
++//#define GPIO_PIN	28
++//#define PIN_NAME	"gpio28"
++#define GPIO_PIN        ((32*2)+30) 
++#define PIN_NAME        "gpio2_30" 
++#endif
++
++extern int root_mtd_num;
++//=============================================================================
++// System Header, size = 512 bytes
++//=============================================================================
++static struct ftnandc024_nandchip_attr nand_attr[] = {
++	/* 
++ 	 * Manufacturer ID, spare size, ECC bits, ECC base shift, 
++ 	 * ECC for spare, Block Boundary, Protect Spare, legacy flash
++ 	 * */
++	{"Micron 29F16G08MAA", 
++          218, 8, 9, 4, 128, 1, LEGACY_FLASH},	/* 4K MLC */
++	{"Samsung K9F4G08U0A", 
++          64, 6, 9, 1, 64, 1, LEGACY_FLASH},	/* 2K SLC */
++	{"Samsung K9F1G08U0D", 
++          64, 6, 9, 1, 64, 1, LEGACY_FLASH},	/* 2K SLC */
++	{"Hynix HY27US08561A", 
++          16, 3, 9, 1, 32, 1, LEGACY_FLASH},	/* 512B SLC */
++};
++
++static int eccbasft, spare, protect_spare, useecc, useecc_spare, block_boundary;
++
++static struct mtd_partition PORTING ftnandc024_partition_info[20];
++
++static int ref_count = 0;
++/*
++ * @the purpose of this function is used to switch the pinmux
++ *
++ * @int platform_select_pinmux(int fd)
++ * @param : fd 
++ * @return: 0 for success, < 0 for fail.
++ */
++static int platform_select_pinmux(int fd, int chip)
++{
++    int ret = 0;
++    volatile int i;
++
++#if defined(CONFIG_PLATFORM_GM8139)  
++    if (chip >= 0) {
++        if (ref_count == 0) {
++            
++    		if (ftpmu010_request_pins(fd, 0x28, (0xF << 7), 1) < 0) {
++    			printk("Warning ===============> NAND request pin failed\n");
++    		}
++       
++            /* the delay is used to prevent data in the bus from incomplete */
++            for (i = 0; i < 1000; i++) {}            
++            
++            ftpmu010_write_reg(fd, 0x58, (0xA << 0), (0xF << 0));
++            ftpmu010_write_reg(fd, 0x58, (0xAAA << 6), (0xFFF << 6));
++            ftpmu010_write_reg(fd, 0x58, (0xA << 24), (0xF << 24));
++            ftpmu010_write_reg(fd, 0x64, (0x3 << 12), (0x3 << 12));
++        }
++        ref_count ++;
++    }
++    else {
++        ref_count -- ;
++        if (ref_count == 0) {
++            /* chip unselect, the delay is used to prevent data in the bus from incomplete */
++            for (i = 0; i < 1000; i++) {}
++
++	        ftpmu010_release_pins(fd, 0x28, (0xF << 7));
++        }
++    }  
++#endif    
++    return ret;
++}
++int ftnandc_read_bbt(struct mtd_info *mtd, loff_t offs);
++
++#ifdef CONFIG_PLATFORM_GM8139
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    //{0x28, (0x1 << 6), (0x1 << 6), (0x0 << 6), (0x1 << 6)},   /* frequency setting */
++    {0x54, (0x3F << 26), (0x3F << 26), (0x2A << 26), (0x3F << 26)},   /* pinMux */
++    {0x58, (0xF << 0), (0xF << 0), (0xA << 0), (0xF << 0)},   /* pinMux bit 0~3 */    
++    {0x58, (0xFFF << 6), (0xFFF << 6), (0xAAA << 6), (0xFFF << 6)},	/* pinMux bit 6~17 */
++    {0x58, (0xF << 24), (0xF << 24), (0xA << 24), (0xF << 24)},	/* pinMux bit 24~27 */
++    {0x64, (0x3 << 12), (0x3 << 12), (0x3 << 12), (0x3 << 12)},		/* pinMux */
++    {0xB4, (0x1 << 16), (0x1 << 16), (0x0 << 16), (0x1 << 16)},   /* AHB clock gate */
++};
++#endif
++
++static pmuRegInfo_t	pmu_reg_info = {
++    "nandc024",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++#define MTD_LOGO_SZ         (4 << 20)  //4M bytes
++#define MTD_LINUX_SZ        (30 << 20)  //30M bytes
++
++typedef struct nand024_sys_header {	
++    char signature[8];          /* Signature is "GM8xxx" */
++    unsigned int bootm_addr;    /* Image offset to load by spiboot */
++    unsigned int bootm_size;
++    unsigned int bootm_reserved;
++
++    struct {
++        unsigned int addr;          /* image address */
++        unsigned int size;          /* image size */
++        unsigned char name[8];      /* image name */
++        unsigned int reserved[1];
++    } image[10];
++        
++    struct {
++        unsigned int nand_numblks;      //number of blocks in chip
++        unsigned int nand_numpgs_blk;   //how many pages in a block
++        unsigned int nand_pagesz;       //real size in bytes                        
++        unsigned int nand_sparesz_inpage;       //64bytes for 2k, ...... needed for nandc024
++        unsigned int nand_numce;        //how many CE in chip
++        unsigned int nand_status_bit;
++        unsigned int nand_cmmand_bit;
++        unsigned int nand_ecc_capability;
++        unsigned int nand_ecc_base;     //0/1 indicates 512/1024 bytes      
++        unsigned int nand_sparesz_insect;
++        unsigned int reserved_1;
++        unsigned int nand_row_cycle;    //1 for 1 cycle ...
++        unsigned int nand_col_cycle;    //1 for 1 cycle ...
++        unsigned int reserved[1];
++    } nandfixup;
++    unsigned int reserved2[58];        // unused
++    unsigned char last_511[4];  // byte510:0x55, byte511:0xAA
++} nand024_sys_header_t;
++
++//=============================================================================
++// BI table, size = 1024 bytes
++//=============================================================================
++typedef struct bi_table {
++    /* This array size is related to USB_BUFF_SZ defined in usb_scsi.h */
++    unsigned int bi_status[256];        //each bit indicates a block. 1 for good, 0 for bad
++} bi_table_t;
++
++struct ftnandc024_nand_data {
++    struct nand_chip chip;
++    struct mtd_info mtd;
++    void __iomem *io_base;
++    int sel_chip;
++    int cur_cmd;
++    int page_addr;
++    int column;
++    int byte_ofs;
++    u32 *buf;
++    struct device *dev;
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)   
++    struct dma_chan             *dma_chan;
++    dma_cap_mask_t              cap_mask;
++#ifdef CONFIG_NAND_USE_AXIDMA
++    struct ftdmac030_dma_slave  dma_slave_config;
++#else 
++    struct ftdmac020_dma_slave  dma_slave_config;   
++#endif
++    dma_cookie_t                cookie;
++    dma_addr_t mem_dmaaddr;
++    dma_addr_t nand_dmaaddr;
++    unsigned char *mem_dmabuf; 
++    unsigned char *sg_dmabuf;   
++#endif    
++    dma_addr_t syshd_dmaaddr;
++    dma_addr_t bitab_dmaaddr; 
++    int cur_chan;
++    int valid_chip[MAX_CHANNEL];
++    int scan_state;
++    int cmd_status;
++    char flash_raw_id[5];
++    int flash_type;
++    int large_page;
++    nand024_sys_header_t *sys_hdr;      /* system header */
++    bi_table_t *bi_table;       /* bad block table next to sys_hdr */
++    int curr_param_group;
++    int (*write_oob) (struct mtd_info * mtd, const u_char * buf, int len);
++    int (*read_oob) (struct mtd_info * mtd, u_char * buf);
++    int (*write_page) (struct mtd_info * mtd, const uint8_t * buf);
++    int (*read_page) (struct mtd_info * mtd, u_char * buf);
++};
++
++#ifdef CONFIG_MTD_NAND_FTNANDC024
++static int startchn = CONFIG_FTnandc024_START_CHANNEL;
++#else
++static int startchn = 0;
++module_param(startchn, int, 0644);
++#endif
++
++#define	max_chip_size	(2048 * 16)     //2048MB NAND
++
++static int partition_check(struct mtd_partition *partitions, struct ftnandc024_nand_data *data, int block_size)
++{
++    int i, num = 0;
++    int j, A_begin, A_end, B_begin, B_end;
++    
++    nand024_sys_header_t *sys_hdr;
++    
++    sys_hdr = data->sys_hdr;
++
++	if(sys_hdr->image[0].size == 0){
++		printk("Not find partition message, use default setting\n");
++	    //maybe has bad block, we can change address
++	    partitions[0].name = "a";
++	    partitions[0].offset = 0x240000;
++	    partitions[0].size = 0x200000;
++	    
++	    partitions[1].name = "b";
++	    partitions[1].offset = 0x600000;
++	    partitions[1].size = 0x200000;
++	
++	    partitions[2].name = "c";
++	    partitions[2].offset = 0x0;
++	    partitions[2].size = 0x100000;
++	        
++	    num = 3;    
++	}else{
++	    for(i = 0; i < ARRAY_SIZE(ftnandc024_partition_info); i++){    
++	    	if(sys_hdr->image[i].size == 0)
++	    	    continue;
++	
++	        partitions[num].offset = sys_hdr->image[i].addr;
++	        partitions[num].size = sys_hdr->image[i].size;
++	        partitions[num].name = sys_hdr->image[i].name;
++	        
++	        if(sys_hdr->image[i].addr % block_size){
++	    	    printk("Warning... partition %d addr 0x%x not block alignment, one block = 0x%x\n", i, sys_hdr->image[i].addr, block_size);
++	    	    partitions[i].offset = BLOCK_ALIGN(sys_hdr->image[i].addr, block_size);
++	        }
++	        if(sys_hdr->image[i].size % block_size){
++	    	    printk("Warning... partition %d size 0x%x not block alignment, one block = 0x%x\n", i, sys_hdr->image[i].size, block_size);
++	    	    partitions[i].size = BLOCK_ALIGN(sys_hdr->image[i].size, block_size);
++	        } 
++	        num++;   
++	    }
++
++        /* nsboot image */
++        partitions[num].offset = sys_hdr->bootm_addr;
++        partitions[num].size = block_size;
++        partitions[num].name = "NSBOOT";        
++        num++;
++    		
++	    for(i = 0; i < ARRAY_SIZE(ftnandc024_partition_info); i++){
++	        DBGLEVEL2(ftnandc024_dbg("partation %d addr = 0x%x, size = 0x%x, name = %s\n", i, sys_hdr->image[i].addr, sys_hdr->image[i].size, sys_hdr->image[i].name));
++	    }
++	    
++	    for(i = 0; i < (num - 1); i++)
++	    	if(partitions[i + 1].offset >= partitions[i].offset)
++		        if(partitions[i + 1].offset - partitions[i].offset < (2 * block_size)){
++		            printk("Warning... Block reserve for bad issue between partition %d with %d is not enough\n", i, i + 1);
++		            printk("partition %d addr = 0x%x, %d addr = 0x%x\n", i, (u32)partitions[i].offset, i + 1, (u32)partitions[i + 1].offset);
++		        }
++	} 
++		
++		//overlap check
++    for(i = 0; i < (num - 2); i++){
++      A_begin = sys_hdr->image[i].addr;
++      A_end = A_begin + sys_hdr->image[i].size;
++			//printk("A %x,%x\n",A_begin,A_end);
++			
++			for(j = (i + 1); j < num; j++){
++	      B_begin = sys_hdr->image[j].addr;
++	      B_end = B_begin + sys_hdr->image[j].size;
++				//printk("B %x,%x\n",B_begin,B_end);
++				      
++	      /* A_end between B_end and B_begin */
++	      if((B_end >= A_end) && (A_end > B_begin))
++	      	goto check_fail;
++	      /* A_begin between B_end and B_begin */
++	      if((B_end > A_begin) && (A_begin >= B_begin))
++	      	goto check_fail;
++	      /* B between A */
++	      if((A_end >= B_end) && (B_begin >= A_begin))
++	      	goto check_fail;	      	      	
++			}
++    }
++    		   
++    return num;
++check_fail:
++		printk("Warning ============> partition %d overlap with %d\n", i, j);
++    return num;    
++}
++
++#if 0
++/* Note: The unit of tWPST/tRPST/tWPRE/tRPRE field of ftnandc024_chip_timing is ns.
++ *
++ * tWH, tCH, tCLH, tALH, tCALH, tWP, tREH, tCR, tRSTO, tREAID,
++ * tREA, tRP, tWB, tRB, tWHR, tWHR2, tRHW, tRR, tAR, tRC
++ * tADL, tRHZ, tCCS, tCS, tCS2, tCLS, tCLR, tALS, tCALS, tCAL2, tCRES, tCDQSS, tDBS, tCWAW, tWPRE,
++ * tRPRE, tWPST, tRPST, tWPSTH, tRPSTH, tDQSHZ, tDQSCK, tCAD, tDSL
++ * tDSH, tDQSL, tDQSH, tDQSD, tCKWR, tWRCK, tCK, tCALS2, tDQSRE, tWPRE2, tRPRE2, tCEH
++ 
++ */
++static struct ftnandc024_chip_timing chip_timing = {
++	10, 5, 5, 5, 0, 12, 10, 0, 0, 0,
++	20, 12, 100, 0, 60, 0, 100, 20, 10, 0,
++	70, 100, 0, 20, 0, 12, 10, 12, 0, 0, 0, 0, 0, 0, 0,
++	0, 0, 0, 0, 0, 0, 0, 0, 0,
++	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++#endif
++
++static struct resource ftnandc024_resource[] = {
++    [0] = {
++           .start = NAND_FTNAND024_PA_BASE,     /* Register Base address */
++           .end = NAND_FTNAND024_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = NANDDP_FTNAND024_PA_BASE,   /* BMC buffer or Data Port access */
++           .end = NANDDP_FTNAND024_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [2] = {
++           .start = NAND_FTNAND024_IRQ,
++           .end = NAND_FTNAND024_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static struct nand_ecclayout nand_hw_eccoob = {
++    .eccbytes = 0,
++    .eccpos = {0},
++    .oobfree = {
++                {.offset = 0,
++                 .length = 64}}
++};
++
++static uint8_t ftnandc024_bbt_pattern[] = { 'B', 'b', 't', '0' };
++static uint8_t ftnandc024_mirror_pattern[] = { '1', 't', 'b', 'B' };
++
++static struct nand_bbt_descr ftnandc024_bbt_mirror_descr = {
++    .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++        | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++    .offs = 0,
++    .len = 4,
++    .veroffs = 4,
++    .maxblocks = 4,
++    .pattern = ftnandc024_mirror_pattern
++};
++
++static struct nand_bbt_descr ftnandc024_bbt_main_descr = {
++    .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++        | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++    .offs = 0,
++    .len = 4,
++    .veroffs = 4,
++    .maxblocks = 4,
++    .pattern = ftnandc024_bbt_pattern
++};
++
++static uint8_t ftnandc024_scan_ff_pattern[] = { 0xff, 0xff, 0xff, 0xff };
++
++static struct nand_bbt_descr ftnandc024_largepage_flashbased = {
++    .options = NAND_BBT_SCAN2NDPAGE,
++    .offs = 0,
++    .len = 4,
++    .pattern = ftnandc024_scan_ff_pattern
++};
++
++static void ftnandc024_regdump(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	volatile u32 val;
++	u32 i;
++	
++	printk("===================================================\n");
++	printk("0x0000: ");
++	for(i = 0; i< 0x50; i=i+4){
++		if(i != 0 && (i%0x10)==0){
++			printk("\n");
++			printk("0x%04x: ", i);
++		}
++		val = readl(data->io_base + i);
++		printk("0x%08x ", val);
++	} 
++	for(i = 0x100; i< 0x1B0; i=i+4){
++		if(i != 0 && (i%0x10)==0){
++			printk("\n");
++			printk("0x%04x: ", i);
++		}
++		val = readl(data->io_base + i);
++		printk("0x%08x ", val);
++	} 
++	for(i = 0x200; i< 0x530; i=i+4){
++		if(i != 0 && (i%0x10)==0){
++			printk("\n");
++			printk("0x%04x: ", i);
++		}
++		val = readl(data->io_base + i);
++		printk("0x%08x ", val);
++	} 
++	printk("\n===================================================\n");
++}
++
++static inline void ftnandc024_set_row_col_addr(struct ftnandc024_nand_data *data, int row, int col)
++{
++    int val;
++
++    val = readl(data->io_base + MEM_ATTR_SET);
++    val &= ~(0x7 << 12);
++    val |= (ATTR_ROW_CYCLE(row) | ATTR_COL_CYCLE(col));
++
++    writel(val, data->io_base + MEM_ATTR_SET);
++}
++
++/* low enable write protect, high disable write protect */
++static void write_protect(int mode)
++{
++#ifdef CONFIG_GPIO_WP
++		if(mode)
++			gpio_direction_output(GPIO_PIN, 0);
++		else
++			gpio_direction_output(GPIO_PIN, 1);
++#endif
++}
++
++static int ftnandc024_nand_check_cmdq(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    unsigned long timeo = jiffies;
++    u32 status;
++    int ret;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    ret = -EIO;
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        status = readl(data->io_base + CMDQUEUE_STATUS);
++        if ((status & CMDQUEUE_STATUS_FULL(data->cur_chan)) == 0) {
++            ret = 0;
++            break;
++        }
++        cond_resched();
++    }
++    
++		platform_select_pinmux(nand_fd, -1);
++    return ret;
++}
++
++static int ftnandc024_issue_cmd(struct mtd_info *mtd, struct cmd_feature *cmd_f) {
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	int status;
++
++	status = ftnandc024_nand_check_cmdq(mtd);
++	if (status == 0) {
++		ftnandc024_set_row_col_addr(data, cmd_f->row_cycle, cmd_f->col_cycle);
++		
++		writel(cmd_f->cq1, data->io_base + CMDQUEUE1(data->cur_chan));
++		writel(cmd_f->cq2, data->io_base + CMDQUEUE2(data->cur_chan));
++		writel(cmd_f->cq3, data->io_base + CMDQUEUE3(data->cur_chan));
++		writel(cmd_f->cq4, data->io_base + CMDQUEUE4(data->cur_chan)); // Issue cmd
++
++		//printk("cmd = 0x%x\n", (cmd_f->cq4 >> 8) & 0x3FF);
++	}
++	return status;
++}
++/*
++static void ftnandc024_soft_reset(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    unsigned long timeo = jiffies;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    writel(1, data->io_base + GLOBAL_RESET);
++    
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        if (readl(data->io_base + GLOBAL_RESET) == 0)
++            break;
++    }
++    platform_select_pinmux(nand_fd, -1);
++}*/
++
++static void ftnandc024_fill_prog_flow(struct mtd_info *mtd, int *program_flow_buf, int buf_len)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	u8 *p = (u8 *)program_flow_buf;
++	
++	int i;
++	for(i = 0; i < buf_len; i++) {
++		writeb( *(p+i), data->io_base + PROGRAMMABLE_FLOW_CONTROL + i);
++	}
++}
++
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++static int ftnandc024_dma_wait(struct mtd_info *mtd)
++{
++    int ret = -1;
++  
++    ret = wait_event_timeout(nand024_queue, trigger_flag == 1, 10 * HZ);
++    if (ret < 0) {
++    	printk("nand024 dma queue wake up timeout signal arrived\n");
++    	return -1;
++    }
++
++    trigger_flag = 0; 
++    
++    return 0;
++}
++#endif
++
++static int ftnandc024_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++    struct ftnandc024_nand_data *data = chip->priv;
++
++    unsigned long timeo = jiffies;
++    int ret, state = chip->state;
++	volatile u32 intr_sts, ecc_intr_sts;
++	volatile u8 cmd_comp_sts, sts_fail_sts;
++	volatile u8 ecc_sts_for_data, ecc_hit_sts_for_data;
++	volatile u8 ecc_sts_for_spare, ecc_hit_sts_for_spare;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    ret = NAND_STATUS_FAIL;
++    timeo += 5 * HZ;
++
++
++	while (time_before(jiffies, timeo)) {//ecc error handle
++		intr_sts = readl(data->io_base + INTR_STATUS);
++		cmd_comp_sts = ((intr_sts & 0xFF0000) >> 16);
++
++		if (likely(cmd_comp_sts & (1 << (data->cur_chan)))) {
++			// Clear the intr status when the cmd complete occurs.
++			writel(intr_sts, data->io_base + INTR_STATUS);
++			
++			ret = NAND_STATUS_READY;
++			sts_fail_sts = (intr_sts & 0xFF);
++				
++			if (sts_fail_sts & (1 << (data->cur_chan))) {
++				printk(KERN_ERR "Warning, Card report status not stable@(pg_addr:0x%x), please use another page next time\n", data->page_addr);
++				data->cmd_status |= CMD_STATUS_FAIL;
++				ret = NAND_STATUS_FAIL;
++				//ftnandc024_soft_reset(mtd);
++			}
++			
++			ecc_intr_sts = readl(data->io_base + ECC_INTR_STATUS);
++			// Clear the ECC intr status
++			writel(ecc_intr_sts, data->io_base + ECC_INTR_STATUS);
++			//if(ecc_intr_sts)
++			//    printk("<ecc sts=0x%x, flow=0x%x>",ecc_intr_sts,state);	
++		
++			//if ((state == FL_READING) || (state == FL_READY)) {//???
++			if (state == FL_READY) {
++
++				// ECC failed on data		
++				ecc_sts_for_data = (ecc_intr_sts & 0xFF); 
++				if (ecc_sts_for_data & (1 << data->cur_chan)) {
++					data->cmd_status |= CMD_ECC_FAIL_ON_DATA;
++					//printk("CMD_ECC_FAIL_ON_DATA\n");
++					ret = NAND_STATUS_FAIL;
++				}
++				// Hit the ECC threshold
++				ecc_hit_sts_for_data = ((ecc_intr_sts & 0xFF00) >> 8);
++				if (ecc_hit_sts_for_data & (1 << data->cur_chan)) {
++				}
++				
++				ecc_sts_for_spare = ((ecc_intr_sts & 0xFF0000) >> 16); 
++				// ECC failed on spare	
++				if (ecc_sts_for_spare & (1 << data->cur_chan)) {
++					data->cmd_status |= CMD_ECC_FAIL_ON_SPARE;
++					//printk("CMD_ECC_FAIL_ON_SPARE\n");
++					ret = NAND_STATUS_FAIL;
++				}
++				// Hit the ECC threshold for spare
++				ecc_hit_sts_for_spare = ((ecc_intr_sts & 0xFF000000) >> 24);
++				if (ecc_hit_sts_for_spare & (1 << data->cur_chan)) {
++				}
++
++			}
++			goto out_wait;
++		}	
++		cond_resched();	
++	}
++
++    DBGLEVEL1(ftnandc024_dbg("nand wait time out\n"));
++    ftnandc024_regdump(mtd);
++  out_wait:
++
++  	write_protect(1);
++  	platform_select_pinmux(nand_fd, -1);
++    return ret;
++}
++
++static void ftnandc024_set_default_timing(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	int i;
++	u32 timing[4];
++
++	timing[0] = 0x0f1f0f1f;
++	timing[1] = 0x00007f7f;
++	timing[2] = 0x7f7f7f7f;
++	timing[3] = 0xff1f001f;
++
++	for (i = 0;i < MAX_CHANNEL;i++) {
++		writel(timing[0], data->io_base + FL_AC_TIMING0(i));
++		writel(timing[1], data->io_base + FL_AC_TIMING1(i));
++		writel(timing[2], data->io_base + FL_AC_TIMING2(i));
++		writel(timing[3], data->io_base + FL_AC_TIMING3(i));
++	}
++}
++
++static void ftnandc024_set_default_warmup_cyc(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	char val;
++	
++	val = readb(data->io_base + MEM_ATTR_SET2);
++	val &= (char)(~0xFF);
++	writeb(val, data->io_base + MEM_ATTR_SET2); 
++}
++
++/* The unit of Hclk is MHz, and the unit of Time is ns.
++ * We desire to calculate N to satisfy N*(1/Hclk) > Time given Hclk and Time
++ * ==> N > Time * Hclk
++ * ==> N > Time * 10e(-9) * Hclk *10e(6)        --> take the order out
++ * ==> N > Time * Hclk * 10e(-3)
++ * ==> N > Time * Hclk / 1000
++ * ==> N = (Time * Hclk + 999) / 1000
++ */
++static void ftnandc024_calc_timing(struct mtd_info *mtd)
++{
++#if 1//use low speed, use default timing
++    return;
++#else
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	int i;
++	int tWH, tWP, tREH, tRES, tBSY, tBUF1;
++	int tBUF2, tBUF3, tBUF4, tPRE, tRLAT, t1;
++	int tPST, tPSTH, tWRCK;
++
++	struct ftnandc024_chip_timing *p;
++	u32 CLK, timing[4];
++
++	CLK = ftpmu010_get_attr(ATTR_TYPE_AHB) / 1000000;
++	
++	tWH = tWP = tREH = tRES =  0;
++	tRLAT = tBSY = t1 = 0;
++	tBUF4 = tBUF3 = tBUF2 = tBUF1 = 0;
++	tPRE = tPST = tPSTH = tWRCK = 0;
++#if defined (CONFIG_FTNANDC024_MICRON_29F32G08CBABB)
++	if (data->flash_type == ONFI2)
++		p = &sync_timing;
++	else
++#endif
++		p = &chip_timing;
++
++	// tWH = max(tWH, tCH, tCLH, tALH)
++	tWH = max_4(p->tWH, p->tCH, (int)p->tCLH, (int)p->tALH);
++	tWH = (tWH * CLK) / 1000;
++	// tWP = tWP
++	tWP = (p->tWP * CLK) / 1000;
++	// tREH = tREH
++	tREH = (p->tREH * CLK) / 1000;
++	// tRES = max(tREA, tRSTO, tREAID)
++	tRES = max_3(p->tREA, p->tRSTO, (int)p->tREAID);
++	tRES = (tRES * CLK) / 1000;
++	// tRLAT < (tRES + tREH) + 2
++	tRLAT = tRES + tREH;
++	// t1 = max(tCS, tCLS, tALS) - tWP
++	t1 = max_3(p->tCS, p->tCLS, (int)p->tALS) - p->tWP;
++	if (t1 < 0)
++		t1 = 0;
++	else 
++		t1 = (t1 * CLK) / 1000;
++	// tPSTH(EBI setup time) = max(tCS, tCLS, tALS)
++	tPSTH = max_3(p->tCS, p->tCLS, (int)p->tALS);
++	tPSTH = (tPSTH * CLK) / 1000;
++	// tWRCK(EBI hold time) = max(tRHZ, tREH)
++	tWRCK = max_2(p->tRHZ, p->tREH);
++	tWRCK = (tWRCK * CLK) / 1000;
++		
++	// tBSY = max(tWB, tRB), min value = 1
++	tBSY = max_2(p->tWB, p->tRB);
++	tBSY = (tBSY * CLK) / 1000;
++	if(tBSY < 1)
++		tBSY = 1;
++	// tBUF1 = max(tADL, tCCS)
++	tBUF1 = max_2(p->tADL, (int)p->tCCS);
++	tBUF1 = (tBUF1 * CLK) / 1000;
++	// tBUF2 = max(tAR, tRR, tCLR, tCDQSS, tCRES, tCALS, tCALS2, tDBS)
++	tBUF2 = max_2(max_4(p->tAR, p->tRR, (int)p->tCLR, (int)p->tCDQSS),
++				max_4((int)p->tCRES, (int)p->tCALS, (int)p->tCALS2, (int)p->tDBS));
++	tBUF2 = (tBUF2 * CLK) / 1000;
++	// tBUF3 = max(tRHW, tRHZ, tDQSHZ)
++	tBUF3 = max_3(p->tRHW, p->tRHZ, (int)p->tDQSHZ);
++	tBUF3 = (tBUF3 * CLK) / 1000;
++	// tBUF4 = max(tWHR, tWHR2)
++	tBUF4 = max_2((int)p->tWHR, p->tWHR2);
++	tBUF4 = (tBUF4 * CLK) / 1000;
++	
++	timing[0] = (tWH << 24) | (tWP << 16) | (tREH << 8) | tRES;
++	timing[1] = (tRLAT << 16) | (tBSY << 8) | t1;
++	timing[2] = (tBUF4 << 24) | (tBUF3 << 16) | (tBUF2 << 8) | tBUF1;
++	timing[3] = (tPRE << 28) | (tPST << 24) | (tPSTH << 16) | tWRCK;
++
++	for (i = 0;i < MAX_CHANNEL;i++) {
++		writel(timing[0], data->io_base + FL_AC_TIMING0(i));
++		writel(timing[1], data->io_base + FL_AC_TIMING1(i));
++		writel(timing[2], data->io_base + FL_AC_TIMING2(i));
++		writel(timing[3], data->io_base + FL_AC_TIMING3(i));
++	}	
++
++	DBGLEVEL2(ftnandc024_dbg("AC Timing 0:0x%08x\n", timing[0]));
++	DBGLEVEL2(ftnandc024_dbg("AC Timing 1:0x%08x\n", timing[1]));
++	DBGLEVEL2(ftnandc024_dbg("AC Timing 2:0x%08x\n", timing[2]));
++	DBGLEVEL2(ftnandc024_dbg("AC Timing 3:0x%08x\n", timing[3]));
++#endif	
++}
++
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++static int ftnandc024_nand_dma_rd(struct mtd_info *mtd, uint8_t *buf) {
++    
++    struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++    int status = 0;
++    
++    status = nand_dma_start(data, mtd->writesize, DMA_DEV_TO_MEM);
++    if (status < 0) {
++        printk("nand dma read page lp fail\n");
++        goto out;
++    }
++
++    ftnandc024_dma_wait(mtd);
++    
++    memcpy(buf, data->mem_dmabuf, mtd->writesize);  
++ out: 
++    return status;
++}
++
++static int ftnandc024_nand_dma_wr(struct mtd_info *mtd, const uint8_t *buf) {
++
++    struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++    int status = 0;
++
++    memcpy(data->mem_dmabuf, buf, mtd->writesize);
++    
++    status = nand_dma_start(data, mtd->writesize, DMA_MEM_TO_DEV);
++    if (status < 0) {
++        printk("nand dma write page lp fail\n");
++        goto out;
++    }
++    ftnandc024_dma_wait(mtd);
++ out: 
++    return status;
++}
++#endif
++
++static int byte_rd(struct mtd_info *mtd, int real_pg, int col, int len, 
++				u_char *spare_buf) {
++	
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f = {0};
++	int status, i, tmp_col, tmp_len, cmd_len, ret;
++	u_char *buf;
++
++	ret = 0;
++	tmp_col = col;
++	tmp_len = len;
++
++	if(data->flash_type == TOGGLE1 || data->flash_type == TOGGLE2 ||
++		data->flash_type == ONFI2 || data->flash_type == ONFI3) {
++		if(col & 0x1) {
++			tmp_len += 2;
++			tmp_col --;
++		}
++		else if(tmp_len & 0x1) {
++			tmp_len ++;
++		}
++	}
++	
++	buf = (u_char *)vmalloc(tmp_len);
++	
++	for(i = 0; i < tmp_len; i += 32) {	
++		if(tmp_len - i >= 32)
++			cmd_len = 32;
++		else
++			cmd_len = tmp_len - i;
++			
++	    cmd_f.row_cycle = data->sys_hdr->nandfixup.nand_row_cycle - 1;
++	    cmd_f.col_cycle = data->sys_hdr->nandfixup.nand_col_cycle - 1;
++		cmd_f.cq1 = real_pg;
++		cmd_f.cq2 = 0;
++		cmd_f.cq3 = CMD_COUNT(1) | (tmp_col & 0xFF);
++		cmd_f.cq4 = CMD_COMPLETE_EN | CMD_BYTE_MODE |\
++				CMD_FLASH_TYPE(data->flash_type) |\
++				CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(cmd_len) |\
++				CMD_INDEX(LARGE_FIXFLOW_BYTEREAD);
++		#ifdef CONFIG_NAND_V2_USE_AHBDMA
++		cmd_f.cq4 |= CMD_DMA_HANDSHAKE_EN;
++		#endif
++	
++		status = ftnandc024_issue_cmd(mtd, &cmd_f);
++		if(status < 0) {
++			ret = 1;
++			break;
++		}
++		ftnandc024_nand_wait(mtd, chip);
++		memcpy(buf + i, data->io_base + SPARE_SRAM + (data->cur_chan << 5), cmd_len);
++		
++		tmp_col += cmd_len;
++	}
++
++	if(data->flash_type == TOGGLE1 || data->flash_type == TOGGLE2 ||
++		data->flash_type == ONFI2 || data->flash_type == ONFI3) {
++		if(col & 0x1)
++			memcpy(spare_buf, buf + 1, len);
++		else
++			memcpy(spare_buf, buf, len);
++	}
++	else
++		memcpy(spare_buf, buf, len);
++	
++	vfree(buf);
++	return ret;
++}
++
++static int rd_pg_w_oob(struct mtd_info *mtd, int real_pg, 
++					u_char *data_buf, u_char *spare_buf) {
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++	int status;
++	#ifndef CONFIG_NAND_V2_USE_AHBDMA
++	int i;
++	u32 *lbuf;
++	#endif
++
++	cmd_f.row_cycle = data->sys_hdr->nandfixup.nand_row_cycle - 1;
++	cmd_f.col_cycle = data->sys_hdr->nandfixup.nand_col_cycle - 1;
++	cmd_f.cq1 = real_pg;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(mtd->writesize >> eccbasft) | (data->column & 0xFF);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) |\
++			CMD_INDEX(LARGE_FIXFLOW_PAGEREAD_W_SPARE);
++	#ifdef CONFIG_NAND_V2_USE_AHBDMA
++	cmd_f.cq4 |= CMD_DMA_HANDSHAKE_EN;
++	#endif
++	
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if(status < 0)
++		return 1;
++
++	#ifdef CONFIG_NAND_V2_USE_AHBDMA
++	if(ftnandc024_nand_dma_rd(mtd, data_buf)) {
++		return 1;
++	}
++	#else
++	lbuf = (u32 *) data_buf;
++	for (i = 0; i < mtd->writesize; i += 4)
++		*lbuf++ = *(volatile unsigned *)(data->chip.IO_ADDR_R);
++	#endif
++	ftnandc024_nand_wait(mtd, chip);
++	memcpy(spare_buf, data->io_base + SPARE_SRAM + (data->cur_chan << 5), mtd->oobsize); 
++
++	return 0;
++
++}
++
++static int rd_pg_w_oob_sp(struct mtd_info *mtd, int real_pg, 
++					u_char *data_buf, u_char *spare_buf) {
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++	int status;
++	#ifndef CONFIG_NAND_V2_USE_AHBDMA
++	u32 *lbuf;
++	int i;
++	#endif
++
++	cmd_f.row_cycle = ROW_ADDR_2CYCLE;
++	cmd_f.col_cycle = COL_ADDR_1CYCLE;
++	cmd_f.cq1 = real_pg;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(1) | (data->column & 0xFF);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) |\
++			CMD_INDEX(SMALL_FIXFLOW_PAGEREAD);
++	#ifdef CONFIG_NAND_V2_USE_AHBDMA
++	cmd_f.cq4 |= CMD_DMA_HANDSHAKE_EN;
++	#endif
++
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if (status < 0)
++		return 1;
++
++	#ifdef CONFIG_NAND_V2_USE_AHBDMA
++	if(ftnandc024_nand_dma_rd(mtd, data_buf)) 
++		return 1;
++	
++	#else
++	lbuf = (u32 *)data_buf;
++	for (i = 0; i < mtd->writesize; i += 4)
++		*lbuf++ = *(volatile unsigned *)(data->chip.IO_ADDR_R);
++	#endif
++	ftnandc024_nand_wait(mtd, chip);
++	
++	memcpy(spare_buf, data->io_base + SPARE_SRAM + (data->cur_chan << 5), mtd->oobsize);
++	
++	return 0;
++}
++
++static int rd_oob(struct mtd_info *mtd, int real_pg, u_char *spare_buf) {
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++	int status;
++
++	cmd_f.row_cycle = data->sys_hdr->nandfixup.nand_row_cycle - 1;
++	cmd_f.col_cycle = data->sys_hdr->nandfixup.nand_col_cycle - 1;
++	cmd_f.cq1 = real_pg;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(1);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) |\
++			CMD_INDEX(LARGE_FIXFLOW_READOOB);
++
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if (status < 0)
++		return 1;
++
++	ftnandc024_nand_wait(mtd, chip);
++	memcpy(spare_buf, data->io_base + SPARE_SRAM + (data->cur_chan << 5), mtd->oobsize);
++	return 0;
++}
++
++static int rd_oob_sp(struct mtd_info *mtd, int real_pg, u_char *spare_buf) {
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++	int status;
++	
++	cmd_f.row_cycle = ROW_ADDR_2CYCLE;
++	cmd_f.col_cycle = COL_ADDR_1CYCLE;
++	cmd_f.cq1 = real_pg;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(1);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) |\
++			CMD_INDEX(SMALL_FIXFLOW_READOOB);
++
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if (status < 0)
++		return 1;
++	
++	ftnandc024_nand_wait(mtd, chip);
++	
++	memcpy(spare_buf, data->io_base + SPARE_SRAM + (data->cur_chan << 5), mtd->oobsize);
++
++	return 0;
++}
++
++static int rd_pg(struct mtd_info *mtd, int real_pg, u_char *data_buf) {
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++	int status;	
++	#ifndef CONFIG_NAND_V2_USE_AHBDMA
++	u32 *lbuf;
++	int i;
++	#endif
++
++	cmd_f.row_cycle = data->sys_hdr->nandfixup.nand_row_cycle - 1;
++	cmd_f.col_cycle = data->sys_hdr->nandfixup.nand_col_cycle - 1;
++	cmd_f.cq1 = real_pg;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(mtd->writesize >> eccbasft) | (data->column & 0xFF);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) |\
++			CMD_INDEX(LARGE_FIXFLOW_PAGEREAD);
++	#ifdef CONFIG_NAND_V2_USE_AHBDMA
++	cmd_f.cq4 |= CMD_DMA_HANDSHAKE_EN;
++	#endif
++	
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if(status < 0)
++		return 1;
++	#ifdef CONFIG_NAND_V2_USE_AHBDMA
++	if(ftnandc024_nand_dma_rd(mtd, data_buf)) {
++		return 1;
++	}
++	#else
++	lbuf = (u32 *) data_buf;
++	for (i = 0; i < mtd->writesize; i += 4)
++		*lbuf++ = *(volatile unsigned *)(data->chip.IO_ADDR_R);
++	#endif
++	ftnandc024_nand_wait(mtd, chip);
++
++	return 0;
++}
++
++static int rd_pg_sp(struct mtd_info *mtd, int real_pg, u_char *data_buf) {
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++	int progflow_buf[3];
++	int status;
++	#ifndef CONFIG_NAND_V2_USE_AHBDMA
++	int i;
++	u32 *lbuf;
++	#endif
++
++	cmd_f.row_cycle = ROW_ADDR_2CYCLE;
++	cmd_f.col_cycle = COL_ADDR_1CYCLE;
++	cmd_f.cq1 = real_pg;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(1) | (data->column & 0xFF);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip);
++	#ifdef CONFIG_NAND_V2_USE_AHBDMA
++	cmd_f.cq4 |= CMD_DMA_HANDSHAKE_EN;
++	#endif
++
++	progflow_buf[0] = 0x66414200;
++	progflow_buf[1] = 0x66626561;
++	progflow_buf[2] = 0x000067C8;
++	ftnandc024_fill_prog_flow(mtd, progflow_buf, 10);
++	cmd_f.cq4 |= CMD_PROM_FLOW | CMD_INDEX(0x0);
++
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if (status < 0)
++		return 1;
++
++	#ifdef CONFIG_NAND_V2_USE_AHBDMA
++	if(ftnandc024_nand_dma_rd(mtd, data_buf)) 
++		return 1;
++	
++	#else
++	lbuf = (u32 *)data_buf;
++	for (i = 0; i < mtd->writesize; i += 4)
++		*lbuf++ = *(volatile unsigned *)(data->chip.IO_ADDR_R);
++	#endif
++	ftnandc024_nand_wait(mtd, chip);
++		
++	return 0;
++}
++
++static void ftnandc024_onfi_set_feature(struct mtd_info *mtd, int chn, int ce, int val)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++    
++	/* 0x11 means Timing mode 1 and Synchronous DDR */
++	writel(val, data->io_base + SPARE_SRAM + (chn << 5));
++
++	/* 0x1 is Timing mode feature address */
++	cmd_f.row_cycle = ROW_ADDR_2CYCLE;
++	cmd_f.col_cycle = COL_ADDR_1CYCLE;
++	cmd_f.cq1 = 0x1;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = 0;
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(LEGACY_FLASH) |\
++			CMD_START_CE(ce) | CMD_BYTE_MODE | CMD_SPARE_NUM(4) |\
++			CMD_INDEX(ONFI_FIXFLOW_SETFEATURE);
++
++	ftnandc024_issue_cmd(mtd, &cmd_f);
++
++	ftnandc024_nand_wait(mtd, chip);
++
++    platform_select_pinmux(nand_fd, -1);
++}
++
++static void ftnandc024_read_raw_id(struct mtd_info *mtd)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++	u8 id_size = 5;
++
++	data->cur_chan = 0;
++	data->sel_chip = 0;
++
++	// Set the flash to Legacy mode, in advance.
++	if(data->flash_type == ONFI2 || data->flash_type == ONFI3) {
++		ftnandc024_onfi_set_feature(mtd, data->cur_chan, data->sel_chip, 0x00);
++	}
++
++	// Issue the RESET cmd
++	cmd_f.cq1 = 0;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = 0;
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(LEGACY_FLASH) |\
++			CMD_START_CE(data->sel_chip) | CMD_INDEX(FIXFLOW_RESET);
++
++	ftnandc024_issue_cmd(mtd, &cmd_f);
++	
++	ftnandc024_nand_wait(mtd, chip);
++
++	// Issue the READID cmd
++	cmd_f.row_cycle = ROW_ADDR_1CYCLE;
++	cmd_f.col_cycle = COL_ADDR_1CYCLE;
++	cmd_f.cq1 = 0;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(1);
++	cmd_f.cq4 = CMD_FLASH_TYPE(LEGACY_FLASH) | CMD_COMPLETE_EN |\
++			CMD_INDEX(FIXFLOW_READID) | CMD_START_CE(data->sel_chip) |\
++			CMD_BYTE_MODE | CMD_SPARE_NUM(id_size);
++	
++	ftnandc024_issue_cmd(mtd, &cmd_f);	
++
++	ftnandc024_nand_wait(mtd, chip);
++	
++	memcpy(data->flash_raw_id, data->io_base + SPARE_SRAM + (data->cur_chan << 5) , id_size);
++
++	DBGLEVEL2(ftnandc024_dbg("ID@(ch:%d, ce:%d):0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", 
++					data->cur_chan, data->sel_chip, data->flash_raw_id[0], 
++					data->flash_raw_id[1], data->flash_raw_id[2], 
++					data->flash_raw_id[3], data->flash_raw_id[4]));
++}
++
++static int ftnandc024_check_bad_spare(struct mtd_info *mtd, int pg){
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	int spare_phy_start, spare_phy_len, eccbyte;
++	int errbit_num, i, j, ret;
++	int sec_num = (mtd->writesize >> eccbasft);
++	u_char *spare_buf;
++	
++	eccbyte = (useecc * 14) / 8;
++	if (((useecc * 14) % 8) != 0)
++		eccbyte++;
++
++	spare_phy_start = mtd->writesize + (eccbyte * sec_num);
++
++	eccbyte = (useecc_spare * 14) / 8;
++	if (((useecc_spare * 14) % 8) != 0)
++		eccbyte++;
++
++	spare_phy_len = spare + eccbyte;
++	spare_buf = vmalloc(spare_phy_len);
++	
++	ret = 0;
++	errbit_num = 0;
++
++	if(!byte_rd(mtd, pg, spare_phy_start, spare_phy_len, spare_buf)) {
++		
++		for(i = 0; i < spare_phy_len; i++) {
++			if(*(spare_buf + i) != 0xFF) {
++				for(j = 0; j < 8; j ++) {
++					if((*(spare_buf + i) & (0x1 << j)) == 0)
++						errbit_num ++;
++				}
++			}
++		}
++		
++		if(errbit_num > readl(data->io_base + ECC_CORRECT_BIT_FOR_SPARE_REG1) + 1)
++			ret = 1;
++		else
++			ret = 0;
++	}
++	else
++		ret = 1;
++
++	vfree(spare_buf);
++	return ret;
++
++}
++
++static void ftnandc024_calibrate_dqs_delay(struct mtd_info *mtd, int type)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++	int i, max_dqs_delay = 0;
++	int id_size = 5;
++	int id_size_ddr = (id_size << 1);
++	u8 *p, *golden_p;
++	u8 dqs_lower_bound, dqs_upper_bound, state;
++	u32 val;
++
++	dqs_lower_bound = dqs_upper_bound = 0;
++	p = kmalloc(id_size, GFP_KERNEL);
++	golden_p = kmalloc(id_size, GFP_KERNEL);
++	 	
++	if(type == ONFI2) {
++		/* Extent the data from SDR to DDR. 
++		   Ex. If "0xaa, 0xbb, 0xcc, 0xdd, 0xee" is in SDR, 
++		          "0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee" is in DDR(ONFI).
++		*/
++		for(i = 0; i< id_size; i++) {
++			*(golden_p + (i << 1) + 0) = *(data->flash_raw_id + i);
++			*(golden_p + (i << 1) + 1) = *(data->flash_raw_id + i);
++		}
++		DBGLEVEL2(ftnandc024_dbg("Golden ID:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 
++					*golden_p, *(golden_p+1), *(golden_p+2), 
++					*(golden_p+3), *(golden_p+4), *(golden_p+5)));
++		max_dqs_delay = 20;
++	}
++	else if(type == TOGGLE1 || TOGGLE2) {
++		/* Extent the data from SDR to DDR. 
++		   Ex. If "0xaa, 0xbb, 0xcc, 0xdd, 0xee" is in SDR, 
++		          "0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee" is in DDR(TOGGLE).
++		*/
++		for(i = 0; i< id_size; i++) {
++			*(golden_p + (i << 1) + 0) = *(data->flash_raw_id + i);
++			*(golden_p + (i << 1) + 1) = *(data->flash_raw_id + i);
++		}
++		golden_p ++;
++		
++		DBGLEVEL2(ftnandc024_dbg("Golden ID:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 
++					*golden_p, *(golden_p+1), *(golden_p+2), 
++					*(golden_p+3), *(golden_p+4), *(golden_p+5)));
++		max_dqs_delay = 18;
++	}
++	else {
++		printk("%s:Type:%d isn't allowed\n", __func__, type);
++		goto out;
++	}	
++		
++
++	state = 0;
++	for(i = 0; i <= max_dqs_delay; i++) {
++		// setting the dqs delay before READID.
++		writel(i, data->io_base + DQS_DELAY);
++		memset(p, 0, id_size_ddr);
++		
++		// Issuing the READID
++		cmd_f.row_cycle = ROW_ADDR_1CYCLE;
++		cmd_f.col_cycle = COL_ADDR_1CYCLE;
++		cmd_f.cq1 = 0;
++		cmd_f.cq2 = 0;
++		cmd_f.cq3 = CMD_COUNT(1);
++		cmd_f.cq4 = CMD_FLASH_TYPE(type) | CMD_COMPLETE_EN |\
++				CMD_INDEX(FIXFLOW_READID) | CMD_BYTE_MODE |\
++				CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(id_size_ddr);
++		
++		ftnandc024_issue_cmd(mtd, &cmd_f);
++		
++		ftnandc024_nand_wait(mtd, chip);
++		
++			
++		if(type == ONFI2) {
++			memcpy(p, data->io_base + SPARE_SRAM + (data->cur_chan<< 5), id_size_ddr);
++			if(state == 0 && memcmp(golden_p, p, id_size_ddr) == 0) {
++				dqs_lower_bound = i;
++				state = 1;
++			}
++			else if(state == 1 && memcmp(golden_p, p, id_size_ddr) != 0){
++				dqs_upper_bound = i - 1;
++				break;
++			}
++		}
++		else if(type == TOGGLE1 || type == TOGGLE2) {
++			memcpy(p, data->io_base + SPARE_SRAM + (data->cur_chan<< 5), id_size_ddr-1);
++			
++			if(state == 0 && memcmp(golden_p, p, (id_size_ddr - 1)) == 0) {
++				dqs_lower_bound = i;
++				state = 1;
++			}
++			else if(state == 1 && memcmp(golden_p, p, (id_size_ddr - 1)) != 0){
++				dqs_upper_bound = (i - 1);
++				break;
++			}
++
++		}
++		DBGLEVEL2(ftnandc024_dbg("===============================================\n"));
++		DBGLEVEL2(ftnandc024_dbg("ID       :0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 
++							*p, *(p+1), *(p+2), *(p+3), 
++							*(p+4), *(p+5), *(p+6), *(p+7),
++							*(p+8) ));
++		DBGLEVEL2(ftnandc024_dbg("Golden ID:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 
++							*golden_p, *(golden_p+1), *(golden_p+2), *(golden_p+3), 
++							*(golden_p+4), *(golden_p+5),*(golden_p+6), *(golden_p+7), 
++							*(golden_p+8) ));
++		DBGLEVEL2(ftnandc024_dbg("===============================================\n"));	
++	}
++	// Prevent the dqs_upper_bound is zero when ID still accuracy on the max dqs delay
++	if(i == max_dqs_delay + 1)
++		dqs_upper_bound = max_dqs_delay;
++		
++	printk("Upper:%d & Lower:%d for DQS, then Middle:%d\n", 
++		dqs_upper_bound, dqs_lower_bound, ((dqs_upper_bound + dqs_lower_bound) >> 1));
++	// Setting the middle dqs delay
++	val = readl(data->io_base + DQS_DELAY);
++	val &= ~0x1F;
++	val |= (((dqs_lower_bound + dqs_upper_bound) >> 1) & 0x1F);
++	writel(val, data->io_base + DQS_DELAY);
++out:
++	kfree(p);
++	kfree(golden_p);
++
++}
++
++static uint32_t ftnandc024_onfi_get_feature(struct mtd_info *mtd, int chn, int ce, int type)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++	struct cmd_feature cmd_f;
++    u32 val;
++
++    platform_select_pinmux(nand_fd, 0);
++
++	/* 0x1 is Timing mode feature address */
++	cmd_f.row_cycle = ROW_ADDR_2CYCLE;
++	cmd_f.col_cycle = COL_ADDR_1CYCLE;
++	cmd_f.cq1 = 0x1;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = 0;
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(type) |\
++			CMD_START_CE(ce) | CMD_BYTE_MODE | CMD_SPARE_NUM(4) |\
++			CMD_INDEX(ONFI_FIXFLOW_GETFEATURE);
++
++	ftnandc024_issue_cmd(mtd, &cmd_f);
++
++	ftnandc024_nand_wait(mtd, chip);
++
++	val = readl(data->io_base + SPARE_SRAM + (chn << 5));
++
++	platform_select_pinmux(nand_fd, -1);
++
++    return val;
++}
++
++static int ftnandc024_onfi_sync(struct mtd_info *mtd)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc024_nand_data *data = p->priv;
++    u32 val;
++    int ret = -1;
++
++    platform_select_pinmux(nand_fd, 0);
++    
++	ftnandc024_nand_select_chip(mtd, 0);
++	val = ftnandc024_onfi_get_feature(mtd, data->cur_chan, data->sel_chip, 0);
++	printk("onfi feature for Ch %d, CE %d: 0x%x\n", data->cur_chan, data->sel_chip, val);
++
++	ftnandc024_onfi_set_feature(mtd, data->cur_chan, data->sel_chip, 0x11);
++	
++	val = ftnandc024_onfi_get_feature(mtd, data->cur_chan, data->sel_chip, ONFI2);
++	printk("onfi feature for Ch %d, CE %d: 0x%x\n", data->cur_chan, data->sel_chip, val);
++	if (val != 0x1111) {
++		goto out_onfi_sync;
++	}
++	ret = 0;
++
++  out_onfi_sync:
++  	platform_select_pinmux(nand_fd, -1);
++    return ret;
++}
++
++static int ftnandc024_available_oob(struct mtd_info *mtd)
++{
++	int ret = 0;
++	int consume_byte, eccbyte, eccbyte_spare;
++	int available_spare;
++	int sector_num = (mtd->writesize >> eccbasft);
++	
++	if (useecc < 0)
++		goto out;
++	if (protect_spare != 0)
++		protect_spare = 1;
++	else
++		protect_spare = 0;
++
++	eccbyte = (useecc * 14) / 8;
++	if (((useecc * 14) % 8) != 0)
++		eccbyte++;
++
++	consume_byte = (eccbyte * sector_num);
++	if (protect_spare == 1) { 
++		
++		eccbyte_spare = (useecc_spare * 14) / 8;
++		if (((useecc_spare * 14) % 8) != 0)
++			eccbyte_spare++;
++		consume_byte += eccbyte_spare;
++	}
++	available_spare = spare - consume_byte;	
++
++	DBGLEVEL2(ftnandc024_dbg(
++		"mtd->erasesize:%d, mtd->writesize:%d, block_boundary:%d", 
++		mtd->erasesize, mtd->writesize, block_boundary));
++	DBGLEVEL2(ftnandc024_dbg(
++		"page num:%d, eccbasft:%d, protect_spare:%d, spare:%d", 
++		 mtd->erasesize/mtd->writesize,eccbasft, protect_spare, spare));
++	DBGLEVEL2(ftnandc024_dbg(
++		"consume_byte:%d, eccbyte:%d, eccbytes(spare):%d, useecc:%d",
++		consume_byte, eccbyte, eccbyte_spare, useecc));
++	
++	/*----------------------------------------------------------
++	 * YAFFS require 16 bytes OOB without ECC, 28 bytes with
++	 * ECC enable.
++	 * BBT require 5 bytes for Bad Block Table marker.
++	 */
++	if (available_spare >= 4) {
++		if(available_spare >= 32) {
++			ret = 32;
++		}
++		else if(available_spare >= 16) {
++			ret = 16;
++		}
++		else if(available_spare >= 8) {
++			ret = 8;
++		}
++		else if(available_spare >= 4) {
++			ret = 4;
++		}
++		printk(KERN_INFO "Available OOB is %d byte, but we use %d bytes in page mode.\n", available_spare, ret);
++	} else {
++		printk(KERN_INFO "Not enough OOB, try to reduce ECC correction bits.\n");
++		printk(KERN_INFO "(Currently ECC setting for Data:%d)\n", useecc);
++		printk(KERN_INFO "(Currently ECC setting for Spare:%d)\n", useecc_spare);
++	}
++  out:
++    return ret;
++}
++
++static uint8_t ftnandc024_read_byte(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    uint32_t lv;
++    uint8_t b = 0;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    switch (data->cur_cmd) {
++    case NAND_CMD_READID:
++		lv = readl(data->io_base + SPARE_SRAM + (data->cur_chan << 5));
++		b = (lv >> data->byte_ofs) & 0xFF;
++		data->byte_ofs += 8;
++		if (data->byte_ofs == 32)
++			data->byte_ofs = 0;
++        break;
++    case NAND_CMD_STATUS:
++        lv = readl(data->io_base + READ_STATUS0);
++        lv = lv >> (data->cur_chan * 8);
++        b = (lv & 0xFF);
++        /* FIXME: status seems has problem, workaround here */
++        b |= NAND_STATUS_WP;
++        break;
++    }
++		platform_select_pinmux(nand_fd, -1);
++    return b;
++}
++
++static int ftnandc024_nand_read_oob_lp(struct mtd_info *mtd, u_char * buf)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	int status = 0, i, ecc_original_setting, generic_original_setting, val;
++	int real_pg, empty;
++	
++	real_pg = data->page_addr;
++
++	DBGLEVEL2(ftnandc024_dbg(
++		"read_oob: ch = %d, ce = %d, page = 0x%x, real: 0x%x, spare = %d\n", 
++		data->cur_chan, data->sel_chip, data->page_addr, real_pg, spare));
++
++    platform_select_pinmux(nand_fd, 0);
++
++	if(!rd_oob(mtd, real_pg, chip->oob_poi)) {
++	    //check if this page is erased and first time to use it, let's ecc error
++		if(data->cmd_status & CMD_ECC_FAIL_ON_SPARE) {
++			// Store the original setting
++			ecc_original_setting = readl(data->io_base + ECC_CONTROL); 
++			generic_original_setting = readl(data->io_base + GENERAL_SETTING);
++			// Disable the ECC engine & HW-Scramble, temporarily.
++			val = readl(data->io_base + ECC_CONTROL);
++			val = val & ~(ECC_EN(0xFF));
++			writel(val, data->io_base + ECC_CONTROL);
++			val = readl(data->io_base + GENERAL_SETTING);
++			val &= ~DATA_SCRAMBLER;
++			writel(val, data->io_base + GENERAL_SETTING);
++			
++			if(!rd_oob(mtd, real_pg, chip->oob_poi)) {	
++				empty = 1;
++				for (i = 0; i < mtd->oobsize; i++) {
++					if (*(buf + i) != 0xFF) {
++						printk(KERN_ERR "ECC err for spare(Read oob) @");//???
++						printk(KERN_ERR	"ch:%d ce:%d page0x%x real:0x%x\n",
++							data->cur_chan, data->sel_chip, data->page_addr, real_pg);
++						mtd->ecc_stats.failed++;
++						status = -1;
++						empty = 0;
++						break;
++					}
++				}
++				if (empty == 1)
++					DBGLEVEL2(ftnandc024_dbg("Spare real 0xFF"));
++			}			
++			// Restore the ecc original setting & generic original setting.
++			writel(ecc_original_setting, data->io_base + ECC_CONTROL);
++			writel(generic_original_setting, data->io_base + GENERAL_SETTING);
++		}
++	}
++  	platform_select_pinmux(nand_fd, -1);
++	// Returning the any value isn't allowed, except 0, -EBADMSG, or -EUCLEAN
++	return 0;
++}
++
++static int ftnandc024_nand_read_oob_sp(struct mtd_info *mtd, u_char * buf)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	int i, status = 0;
++	int val, ecc_original_setting, empty;
++
++	DBGLEVEL2(ftnandc024_dbg("smallread_oob: ch = %d, ce = %d, page = 0x%x, size = %d\n", 
++				data->cur_chan, data->sel_chip, data->page_addr, mtd->writesize));
++
++    platform_select_pinmux(nand_fd, 0);
++
++	if(!rd_oob_sp(mtd, data->page_addr, buf)) {
++		if(data->cmd_status & CMD_ECC_FAIL_ON_SPARE) {
++			// Store the original setting
++			ecc_original_setting = readl(data->io_base + ECC_CONTROL); 
++			// Disable the ECC engine & HW-Scramble, temporarily.
++			val = readl(data->io_base + ECC_CONTROL);
++			val = val & ~(ECC_EN(0xFF));
++			writel(val, data->io_base + ECC_CONTROL);
++			
++			if(!rd_oob_sp(mtd, data->page_addr, buf)) {
++				empty = 1;
++				for (i = 0; i < mtd->oobsize; i++) {             
++					if (*(buf + i) != 0xFF) {                
++						printk(KERN_ERR "ECC err for spare(Read oob) @ page0x%x\n",
++								data->page_addr);
++						mtd->ecc_stats.failed++;
++						status = -1;
++						empty = 0;
++						break;           
++					}                      
++				}
++				if(empty == 1)	
++					DBGLEVEL2(ftnandc024_dbg("Spare real 0xFF"));
++			}
++			// Restore the ecc original setting & generic original setting.
++			writel(ecc_original_setting, data->io_base + ECC_CONTROL);
++		}
++	}
++	
++  	platform_select_pinmux(nand_fd, -1);
++	// Returning the any value isn't allowed, except 0, -EBADMSG, or -EUCLEAN
++	return 0;
++}
++
++static int ftnandc024_nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page,
++                                        int sndcmd)
++{
++    struct ftnandc024_nand_data *data = chip->priv;
++
++    data->page_addr = page;
++
++    return data->read_oob(mtd, chip->oob_poi);
++}
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++
++static int setup_dma(struct ftnandc024_nand_data *data, int direct)
++{
++    struct dma_slave_config *common;
++    
++    data->dma_slave_config.id = -1;
++    data->dma_slave_config.handshake = DMA_NANDC_REQ;//enable
++
++    common = &data->dma_slave_config.common;
++    
++#ifdef CONFIG_NAND_V2_USE_AHBDMA    
++    if (eccbasft > 9)
++    	data->dma_slave_config.src_size = FTDMAC020_BURST_SZ_256;//256x4=1024
++    else
++    	data->dma_slave_config.src_size = FTDMAC020_BURST_SZ_128;//128x4=512
++    
++    if(direct == DMA_DEV_TO_MEM){
++        data->dma_slave_config.src_sel = AHBMASTER_R_SRC;
++        data->dma_slave_config.dst_sel = AHBMASTER_R_DST;
++    }else{
++        data->dma_slave_config.src_sel = AHBMASTER_W_SRC;
++        data->dma_slave_config.dst_sel = AHBMASTER_W_DST;
++    }
++#else
++    common->src_maxburst = 128;
++    common->dst_maxburst = 128;
++#endif
++     
++    if(direct == DMA_MEM_TO_DEV){
++     	common->src_addr = data->mem_dmaaddr;    
++    	common->dst_addr = data->nand_dmaaddr;   
++    }else{
++     	common->src_addr = data->nand_dmaaddr;    
++    	common->dst_addr = data->mem_dmaaddr;     
++    }
++
++    common->dst_addr_width = 4;
++    common->src_addr_width = 4;
++    common->direction = direct;
++
++    return dmaengine_slave_config(data->dma_chan, common);//step 2
++}
++
++static int nand_dma_start(struct ftnandc024_nand_data *data, size_t len, int direct)
++{
++	int ret;
++	enum dma_ctrl_flags flags;
++	struct dma_async_tx_descriptor *desc;
++
++	ret = setup_dma(data, direct);
++	if (ret){
++	    printk("Nand setup dma fail\n");
++	    return ret;
++	}
++
++	flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++
++	desc = dmaengine_prep_slave_single(data->dma_chan, (void *)data->sg_dmabuf, len, direct, flags);//step 3
++			    
++	if (!desc){
++	    printk("Error dma parameter\n");
++	    return ret;
++	}	
++
++	desc->callback = ftnandc024_dma_callback;
++        desc->callback_param = &data;
++        data->cookie = dmaengine_submit(desc);	//step 4
++	dma_async_issue_pending(data->dma_chan);//step 5
++	
++	return 0;
++}
++#endif
++
++static int calc_new_page(struct mtd_info *mtd, int page_addr)
++{
++    unsigned int start_addr, end_addr, check_addr, tmp_addr, bad_num = 0;
++    unsigned int block_page_num = mtd->erasesize / mtd->writesize;
++    struct nand_chip *chip = mtd->priv;
++    
++    if (root_mtd_num != 0xFFFF) {// is squashfs
++        start_addr = ftnandc024_partition_info[root_mtd_num].offset;
++        end_addr = ftnandc024_partition_info[root_mtd_num].size + start_addr;
++        //printk("squash start addr = 0x%x, end addr = 0x%x\n", start_addr, end_addr); 
++
++        check_addr = page_addr * mtd->writesize;
++        
++        if((check_addr >= start_addr) && (check_addr < end_addr)) {
++            tmp_addr = start_addr;
++            
++            /* have bad block between start to here? */
++            while (check_addr >= tmp_addr) {
++                if(ftnandc_read_bbt(mtd, (loff_t) tmp_addr) != 0) {
++                    bad_num++;
++                    //printk("<ba=0x%x>", tmp_addr);
++                }
++
++                tmp_addr += (0x1 << chip->bbt_erase_shift);
++            }
++            
++            /* move n good block */
++            if(bad_num) {
++                //printk("<br0x%x,bad=%d>",page_addr,bad_num);
++                while(bad_num) {
++                    //printk("<tmp_page = 0x%x>", tmp_addr / mtd->writesize);
++                    if(ftnandc_read_bbt(mtd, (loff_t) tmp_addr) == 0)
++                        bad_num--;
++    
++                    tmp_addr += (0x1 << chip->bbt_erase_shift);
++                    page_addr += block_page_num;                    
++                }
++                //printk("<ar0x%x>\n",page_addr);
++            }                        
++        }
++    }
++
++    return page_addr;
++}
++
++static int ftnandc024_nand_read_page_lp(struct mtd_info *mtd, u_char * buf)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	int status = 0, chk_data_0xFF, chk_spare_0xFF;
++	int i, ecc_original_setting, generic_original_setting, val;
++	int real_pg;
++	u8  empty;
++	u32 *lbuf;
++	
++	real_pg = data->page_addr;
++
++	DBGLEVEL2(ftnandc024_dbg
++		("r: ch = %d, ce = %d, page = 0x%x, real = 0x%x, size = %d, spare = %d\n", 
++		data->cur_chan, data->sel_chip, data->page_addr, real_pg, mtd->writesize, spare));
++    platform_select_pinmux(nand_fd, 0);
++
++    real_pg = data->page_addr = calc_new_page(mtd, data->page_addr);
++
++	chk_data_0xFF = chk_spare_0xFF = 0;
++
++	if(!rd_pg_w_oob(mtd, real_pg, buf, chip->oob_poi)) {
++	    //check if this page is erased and first time to use it, let's ecc error
++		if (data->cmd_status & 
++			(CMD_ECC_FAIL_ON_DATA | CMD_ECC_FAIL_ON_SPARE)) {
++			// Store the original setting
++			ecc_original_setting = readl(data->io_base + ECC_CONTROL); 
++			generic_original_setting = readl(data->io_base + GENERAL_SETTING);
++			// Disable the ECC engine & HW-Scramble, temporarily.
++			val = readl(data->io_base + ECC_CONTROL);
++			val = val & ~(ECC_EN(0xFF));
++			writel(val, data->io_base + ECC_CONTROL);
++			val = readl(data->io_base + GENERAL_SETTING);
++			val &= ~DATA_SCRAMBLER;
++			writel(val, data->io_base + GENERAL_SETTING);
++
++			if( data->cmd_status == (CMD_ECC_FAIL_ON_DATA | CMD_ECC_FAIL_ON_SPARE) ) {
++				if(!rd_pg_w_oob(mtd, real_pg, buf, chip->oob_poi)) {
++					chk_data_0xFF = chk_spare_0xFF = 1;
++				}	
++			}
++			else if(data->cmd_status == CMD_ECC_FAIL_ON_DATA) {
++				if(!rd_pg(mtd, real_pg, buf)) {
++					chk_data_0xFF = 1;
++				}	
++			}
++			else if(data->cmd_status == CMD_ECC_FAIL_ON_SPARE) {
++				if(!rd_oob(mtd, real_pg, chip->oob_poi)) {
++					chk_spare_0xFF = 1;
++				}	
++			}
++		
++			// Restore the ecc original setting & generic original setting.
++			writel(ecc_original_setting, data->io_base + ECC_CONTROL);
++			writel(generic_original_setting, data->io_base + GENERAL_SETTING);
++
++			if(chk_data_0xFF == 1) {
++			    data->cmd_status &= ~CMD_ECC_FAIL_ON_DATA;
++				empty = 1;
++				lbuf = (int *)buf;
++				for (i = 0; i < (mtd->writesize >> 2); i++) {
++					if (*(lbuf + i) != 0xFFFFFFFF) {
++						printk(KERN_ERR "ECC err @ page0x%x real:0x%x\n", 
++							data->page_addr, real_pg);
++						mtd->ecc_stats.failed++;						
++						status = -1;
++						empty = 0;
++						break;	
++					}
++				}
++				if(empty == 1)
++					DBGLEVEL2(ftnandc024_dbg("Data Real 0xFF\n"));
++			}
++			if(chk_spare_0xFF == 1) {
++			    data->cmd_status &= ~CMD_ECC_FAIL_ON_SPARE;
++				if(!ftnandc024_check_bad_spare(mtd, data->page_addr))
++					empty = 1;
++				else {				    
++					printk(KERN_ERR "ECC err for spare(Read page) @");
++					printk(KERN_ERR	"ch:%d ce:%d page0x%x real:0x%x\n",
++						data->cur_chan, data->sel_chip, data->page_addr, real_pg);
++					mtd->ecc_stats.failed++;					
++					status = -1;
++					empty = 0;
++				}
++				if(empty == 1)
++					DBGLEVEL2(ftnandc024_dbg("Spare Real 0xFF\n"));
++			}	
++		}
++	}
++
++  	platform_select_pinmux(nand_fd, -1);		
++	// Returning the any value isn't allowed, except 0, -EBADMSG, or -EUCLEAN
++	return 0;	
++}
++
++static int ftnandc024_nand_read_page_sp(struct mtd_info *mtd, u_char * buf)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	int status = 0;
++	int i, ecc_original_setting, val;
++	int chk_data_0xFF, chk_spare_0xFF, empty;
++	u8 *p;
++	u32 *lbuf;
++
++	DBGLEVEL2(ftnandc024_dbg("smallr: ch = %d, ce = %d, page = 0x%x, size = %d, data->column = %d\n", 
++			data->cur_chan, data->sel_chip, data->page_addr, mtd->writesize, data->column));
++
++    platform_select_pinmux(nand_fd, 0);
++    
++	chk_data_0xFF = chk_spare_0xFF = 0;
++	if(!rd_pg_w_oob_sp(mtd, data->page_addr, buf, chip->oob_poi)) {
++		if(data->cmd_status & (CMD_ECC_FAIL_ON_DATA | CMD_ECC_FAIL_ON_SPARE)) {
++			// Store the original setting
++			ecc_original_setting = readl(data->io_base + ECC_CONTROL); 
++			// Disable the ECC engine & HW-Scramble, temporarily.
++			val = readl(data->io_base + ECC_CONTROL);
++			val = val & ~(ECC_EN(0xFF));
++			writel(val, data->io_base + ECC_CONTROL);
++			
++			if(data->cmd_status == (CMD_ECC_FAIL_ON_DATA | CMD_ECC_FAIL_ON_SPARE)) {
++				if(!rd_pg_w_oob_sp(mtd, data->page_addr, buf, chip->oob_poi)) {
++					chk_data_0xFF = chk_spare_0xFF = 1;
++				}	
++			}
++			else if(data->cmd_status == CMD_ECC_FAIL_ON_DATA) {
++				if(!rd_pg_sp(mtd, data->page_addr, buf)) {
++					chk_data_0xFF = 1;
++				}
++			}
++			else if(data->cmd_status == CMD_ECC_FAIL_ON_SPARE) {
++				if(!rd_oob_sp(mtd, data->page_addr, chip->oob_poi)) {
++					chk_spare_0xFF = 1;		
++				}
++			}
++			// Restore the ecc original setting & generic original setting.
++			writel(ecc_original_setting, data->io_base + ECC_CONTROL);
++			
++			if(chk_data_0xFF == 1) {
++				lbuf = (u32 *)buf;
++				empty = 1;
++				for (i = 0; i < (mtd->writesize >> 2); i++) {
++					if (*(lbuf + i) != 0xFFFFFFFF) {
++						printk(KERN_ERR "ECC err @ page0x%x\n", data->page_addr); 
++						ftnandc024_regdump(mtd);
++						mtd->ecc_stats.failed++;
++						status = -1;
++						empty = 0;
++						break;
++					}
++				}
++				if (empty == 1)
++					DBGLEVEL2(ftnandc024_dbg("Data Real 0xFF\n"));
++			}
++			if(chk_spare_0xFF == 1) {
++				p = chip->oob_poi;
++				empty = 1;
++				for (i = 0; i < mtd->oobsize; i++) {
++					if (*(p + i) != 0xFF) {
++						printk(KERN_ERR"ECC err for spare(Read page) @ page0x%x\n", data->page_addr);
++						mtd->ecc_stats.failed++;
++						status = -1;
++						empty = 0;
++						break;
++					}
++				}
++				if (empty == 1)
++					DBGLEVEL2(ftnandc024_dbg("Spare Real 0xFF\n"));
++			}
++		}
++	}
++    platform_select_pinmux(nand_fd, -1);
++	// Returning the any value isn't allowed, except 0, -EBADMSG, or -EUCLEAN
++	return 0;
++}
++
++static int ftnandc024_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, int page)
++{
++    struct ftnandc024_nand_data *data = chip->priv;
++
++    data->buf = (u32 *) buf;
++
++    return data->read_page(mtd, buf);
++}
++
++static int ftnandc024_nand_write_oob_lp(struct mtd_info *mtd, const u_char * buf, int len)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    struct cmd_feature cmd_f;
++    int status = 0, real_pg;
++
++    real_pg = data->page_addr;
++
++	DBGLEVEL2(ftnandc024_dbg(
++		"write_oob: ch = %d, ce = %d, page = 0x%x, real page:0x%x, sz = %d, oobsz = %d\n", 
++		data->cur_chan, data->sel_chip, data->page_addr, real_pg, mtd->writesize, mtd->oobsize));
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++
++	memcpy(data->io_base + SPARE_SRAM + (data->cur_chan << 5), buf, mtd->oobsize);
++
++	cmd_f.row_cycle = data->sys_hdr->nandfixup.nand_row_cycle - 1;
++	cmd_f.col_cycle = data->sys_hdr->nandfixup.nand_col_cycle - 1;
++	cmd_f.cq1 = real_pg;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(1);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) |\
++			CMD_INDEX(LARGE_FIXFLOW_WRITEOOB);
++		
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++    if (status < 0) {
++        printk("status error\n");
++        goto out_write_oob_lp;
++    }
++
++    if (ftnandc024_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        printk("wait error\n");
++        goto out_write_oob_lp;
++    }
++  out_write_oob_lp:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc024_nand_write_oob_sp(struct mtd_info *mtd, const u_char * buf, int len)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    struct cmd_feature cmd_f;
++    int status = 0;
++
++    platform_select_pinmux(nand_fd, 0);
++    
++	DBGLEVEL2(ftnandc024_dbg("smallwrite_oob: ch = %d, ce = %d, page = 0x%x, size = %d\n", 
++				data->cur_chan, data->sel_chip, data->page_addr, mtd->writesize));
++	
++	memcpy(data->io_base + SPARE_SRAM + (data->cur_chan << 5), buf, len);
++
++	cmd_f.row_cycle = ROW_ADDR_2CYCLE;
++	cmd_f.col_cycle = COL_ADDR_1CYCLE;
++	cmd_f.cq1 = data->page_addr;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(1);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare) |\
++			CMD_INDEX(SMALL_FIXFLOW_WRITEOOB);
++
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if (status < 0)
++		goto out_write_oob_sp;
++
++    if (ftnandc024_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out_write_oob_sp;
++    }
++  out_write_oob_sp:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc024_nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++    struct ftnandc024_nand_data *data = chip->priv;
++
++    DBGLEVEL2(ftnandc024_dbg("write oob only to page = 0x%x\n", page));
++    data->page_addr = page;
++
++    return data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++}
++
++static int ftnandc024_nand_write_page_lp(struct mtd_info *mtd, const uint8_t * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    struct cmd_feature cmd_f;
++#ifndef CONFIG_NAND_V2_USE_AHBDMA
++    int i;
++    u32 *lbuf;
++#endif
++    int status = 0;
++    int real_pg;
++    u8 *p, w_wo_spare = 1;
++
++    DBGLEVEL2(ftnandc024_dbg (
++              "w:page = 0x%x, size = %d, data->column = %d, spare = %d\n", data->page_addr, mtd->writesize,
++               data->column, spare));
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++    
++    real_pg = data->page_addr;
++    p = chip->oob_poi;
++#if 1//always set LARGE_PAGEWRITE_W_SPARE command, need assign data into SRAM ???
++    w_wo_spare = 0;
++#else
++    if (p != NULL) {
++    	for(i = 0; i < mtd->oobsize; i++) {
++    		if( *( p + i) != 0xFF) {
++    			//w_wo_spare = 0;
++    			printk("w spare %x\n",*( p + i));
++    			break;
++    		}
++    	}
++    }
++#endif
++
++	cmd_f.row_cycle = data->sys_hdr->nandfixup.nand_row_cycle - 1;
++	cmd_f.col_cycle = data->sys_hdr->nandfixup.nand_col_cycle - 1;
++	cmd_f.cq1 = real_pg;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(mtd->writesize >> eccbasft) | (data->column & 0xFF);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) | \
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare);
++
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    cmd_f.cq4 |= CMD_DMA_HANDSHAKE_EN;
++#endif
++	if(w_wo_spare == 0) {
++		memcpy((data->io_base + SPARE_SRAM + (data->cur_chan << 5)), p, mtd->oobsize);
++		cmd_f.cq4 |= CMD_INDEX(LARGE_PAGEWRITE_W_SPARE);
++	}
++	else {
++		cmd_f.cq4 |= CMD_INDEX(LARGE_PAGEWRITE);
++	}
++
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if (status < 0)
++		goto out_write_page_lp;
++	
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    if(ftnandc024_nand_dma_wr(mtd, buf)) {
++        printk("nand dma write page lp fail\n");
++        goto out_write_page_lp;
++    }
++#else
++	lbuf = (u32 *) buf;
++	for (i = 0; i < mtd->writesize; i += 4)
++		*(volatile unsigned *)(data->chip.IO_ADDR_R) = *lbuf++;
++#endif
++
++    if (ftnandc024_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out_write_page_lp;
++    }
++  out_write_page_lp:
++    platform_select_pinmux(nand_fd, -1);
++
++    return status;
++}
++
++static int ftnandc024_nand_write_page_sp(struct mtd_info *mtd, const uint8_t * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    struct cmd_feature cmd_f;
++    int progflow_buf[3];
++    int i;
++    int status = 0;
++    u8 *p, w_wo_spare = 1;    
++#ifndef CONFIG_NAND_V2_USE_AHBDMA
++    u32 *lbuf;
++#endif
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++
++	p = chip->oob_poi;
++	for(i = 0; i < mtd->oobsize; i++) {
++		if( *( p + i) != 0xFF) {
++			w_wo_spare = 0;
++			break;
++		}
++	}
++	
++	cmd_f.row_cycle = data->sys_hdr->nandfixup.nand_row_cycle - 1;
++	cmd_f.col_cycle = data->sys_hdr->nandfixup.nand_col_cycle - 1;
++	cmd_f.cq1 = data->page_addr;
++	cmd_f.cq2 = 0;
++	cmd_f.cq3 = CMD_COUNT(1) | (data->column / mtd->writesize);
++	cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type) |\
++			CMD_START_CE(data->sel_chip) | CMD_SPARE_NUM(spare);
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    cmd_f.cq4 |= CMD_DMA_HANDSHAKE_EN;
++#endif
++ 	if(w_wo_spare == 0) {
++		memcpy((data->io_base + SPARE_SRAM + (data->cur_chan << 5)), chip->oob_poi, mtd->oobsize);
++		cmd_f.cq4 |= CMD_INDEX(SMALL_FIXFLOW_PAGEWRITE);
++	}
++	else {
++		progflow_buf[0] = 0x41421D00;
++		progflow_buf[1] = 0x66086460;
++		progflow_buf[2] = 0x000067C7;
++		ftnandc024_fill_prog_flow(mtd, progflow_buf, 10);
++		cmd_f.cq4 |= CMD_PROM_FLOW | CMD_INDEX(0x0);
++	}
++
++	status = ftnandc024_issue_cmd(mtd, &cmd_f);
++	if (status < 0)
++		goto out_write_page_sp;
++		
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    if(ftnandc024_nand_dma_wr(mtd, buf)) {
++        printk("nand dma write page sp fail\n");
++        goto out_write_page_sp;
++    }
++#else
++    lbuf = (u32 *) buf;
++    for (i = 0; i < mtd->writesize; i += 4)
++        *(volatile unsigned *)(data->chip.IO_ADDR_R) = *lbuf++;
++#endif
++    if (ftnandc024_nand_wait(mtd, chip) == NAND_STATUS_FAIL) {
++        status = -1;
++        goto out_write_page_sp;
++    }
++  out_write_page_sp:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static int ftnandc024_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++                                      const uint8_t * buf, int page, int cached, int raw)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc024_nand_data *data = p->priv;
++    int status = 0;
++#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
++    u8 *vbuf;
++    int i;
++#endif
++    data->page_addr = page;
++
++    platform_select_pinmux(nand_fd, 0);
++    write_protect(0);
++
++    status = data->write_page(mtd, buf);
++    if (status < 0)
++        goto out;
++
++#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
++    vbuf = vmalloc(mtd->writesize + mtd->oobsize);
++    memcpy(vbuf + mtd->writesize, chip->oob_poi, mtd->oobsize);
++
++    status = data->read_page(mtd, vbuf);
++    if (status < 0)
++        goto out;
++    for (i = 0; i < mtd->writesize; i++) {
++        if (*(buf + i) != *(vbuf + i)) {
++            printk(KERN_ERR "write verify failed at normal region..");
++            goto out_free;
++        }
++    }
++    for (i = 0; i < mtd->oobsize; i++) {
++        if (*(chip->oob_poi + i) != *(vbuf + mtd->writesize + i)) {
++            printk(KERN_ERR "write verify failed at oob region..\n");
++            goto out_free;
++        }
++    }
++
++  out_free:
++    vfree(vbuf);
++#endif
++  out:
++    platform_select_pinmux(nand_fd, -1);
++    return status;
++}
++
++static void ftnandc024_nand_write_page_lowlevel(struct mtd_info *mtd,
++                                                struct nand_chip *chip, const uint8_t * buf)
++{
++}
++
++static void ftnandc024_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
++                                    int column, int page_addr)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    struct cmd_feature cmd_f;
++    int real_pg;
++    u8 id_size = 6;
++
++    platform_select_pinmux(nand_fd, 0);
++
++    cmd_f.cq4 = CMD_COMPLETE_EN | CMD_FLASH_TYPE(data->flash_type);
++    data->cur_cmd = command;
++    if (page_addr != -1)
++        data->page_addr = page_addr;
++    if (column != -1)
++        data->column = column;
++        
++    real_pg = data->page_addr;
++    
++    switch (command) {
++    case NAND_CMD_READID:
++        /* read ID use sector mode, can't use page mode */
++        DBGLEVEL2(ftnandc024_dbg( "Read ID@(CH:%d, CE:%d)\n", data->cur_chan, data->sel_chip));	
++		
++        data->byte_ofs = 0;
++		cmd_f.row_cycle = ROW_ADDR_1CYCLE;
++		cmd_f.col_cycle = COL_ADDR_1CYCLE;
++		cmd_f.cq1 = 0;
++		cmd_f.cq2 = 0;
++		cmd_f.cq3 = CMD_COUNT(1);
++		cmd_f.cq4 |= CMD_START_CE(data->sel_chip) | CMD_BYTE_MODE |\
++				CMD_SPARE_NUM(id_size) | CMD_INDEX(FIXFLOW_READID);
++		
++		ftnandc024_issue_cmd(mtd, &cmd_f);
++		
++		ftnandc024_nand_wait(mtd, chip);
++        break;
++    case NAND_CMD_RESET:
++		DBGLEVEL2(ftnandc024_dbg("Cmd Reset@(CH:%d, CE:%d)\n", data->cur_chan, data->sel_chip));
++		
++		cmd_f.cq1 = 0;
++		cmd_f.cq2 = 0;
++		cmd_f.cq3 = 0;
++		cmd_f.cq4 |= CMD_START_CE(data->sel_chip);
++		if (data->flash_type == ONFI2 || data->flash_type == ONFI3)
++			cmd_f.cq4 |= CMD_INDEX(ONFI_FIXFLOW_SYNCRESET);
++		else
++			cmd_f.cq4 |= CMD_INDEX(FIXFLOW_RESET);
++
++		ftnandc024_issue_cmd(mtd, &cmd_f);
++
++		ftnandc024_nand_wait(mtd, chip);
++
++        break;
++    case NAND_CMD_STATUS:
++		DBGLEVEL2(ftnandc024_dbg( "Read Status\n"));
++		
++		cmd_f.cq1 = 0;
++		cmd_f.cq2 = 0;
++		cmd_f.cq3 = CMD_COUNT(1);
++		cmd_f.cq4 |= CMD_START_CE(data->sel_chip) | CMD_INDEX(FIXFLOW_READSTATUS);
++
++		ftnandc024_issue_cmd(mtd, &cmd_f);
++		
++		ftnandc024_nand_wait(mtd, chip);
++        break;
++    case NAND_CMD_ERASE1:
++    		write_protect(0);
++		DBGLEVEL2(ftnandc024_dbg(
++			"Erase Page: 0x%x, Real:0x%x\n", data->page_addr, real_pg));
++		
++		cmd_f.cq1 = real_pg;
++		cmd_f.cq2 = 0;
++		cmd_f.cq3 = CMD_COUNT(1);
++		cmd_f.cq4 |= CMD_START_CE(data->sel_chip) | CMD_SCALE(1);
++		
++		cmd_f.row_cycle = data->sys_hdr->nandfixup.nand_row_cycle - 1;
++		cmd_f.col_cycle = data->sys_hdr->nandfixup.nand_col_cycle - 1;
++		if (data->large_page)
++			cmd_f.cq4 |= CMD_INDEX(LARGE_FIXFLOW_ERASE);
++		else
++			cmd_f.cq4 |= CMD_INDEX(SMALL_FIXFLOW_ERASE);
++		
++		ftnandc024_issue_cmd(mtd, &cmd_f);
++        break;
++    case NAND_CMD_ERASE2:
++    case NAND_CMD_PAGEPROG:
++    case NAND_CMD_SEQIN:
++        break;
++    }
++		
++		platform_select_pinmux(nand_fd, -1);
++}
++
++/*
++ * Currently, we have pin mux with SD card
++ */
++void ftnandc024_nand_select_chip(struct mtd_info *mtd, int chip)//???
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc024_nand_data *data = p->priv;
++    int chn = 0;
++
++    //DBGLEVEL2(ftnandc024_dbg("chip = %d, ", chip));
++    if (data->scan_state != 1) {
++        while (chip != -1) {
++            if (chip < data->valid_chip[chn]) {
++                break;
++            } else {
++                chip = chip - data->valid_chip[chn];
++                chn++;
++            }
++        }
++        data->cur_chan = chn;
++    }
++#ifdef CONFIG_FTnandc024_HYNIX_HY27US08561A
++    if (chip == 1)
++        data->sel_chip = 2;
++    else if (chip == 2)
++        data->sel_chip = 1;
++    else
++        data->sel_chip = chip;
++#else
++    data->sel_chip = chip;
++#endif
++
++    //DBGLEVEL2(ftnandc024_dbg("==>chan = %d, ce = %d\n", data->cur_chan, data->sel_chip));
++}
++
++/*
++ * Probe for the NAND device.
++ */
++static int __devinit ftnandc024_nand_probe(struct platform_device *pdev)
++{
++    struct ftnandc024_nand_data *data;
++    struct mtd_partition *partitions;
++    int res, chipnum, size;
++    int i, sel, type;
++    int partitions_num;
++    u32 val;
++    unsigned char spare_buf[64];
++
++    res = chipnum = size = type = 0;
++    /* Allocate memory for the device structure (and zero it) */
++    data = kzalloc(sizeof(struct ftnandc024_nand_data), GFP_KERNEL);
++    if (!data) {
++        dev_err(&pdev->dev, "failed to allocate device structure.\n");
++        res = -ENOMEM;
++        goto out;
++    }
++
++    data->io_base = ioremap_nocache(pdev->resource[0].start,
++                            pdev->resource[0].end - pdev->resource[0].start + 1);
++    printk("NAND reg mapping to addr = 0x%x, phy = 0x%x\n", (u32)data->io_base, (u32)pdev->resource[0].start);
++    if (data->io_base == NULL) {
++        dev_err(&pdev->dev, "ioremap failed for register.\n");
++        res = -EIO;
++        goto out_free_data;
++    }
++    
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    data->nand_dmaaddr = pdev->resource[1].start;
++#else
++    data->chip.IO_ADDR_R = ioremap_nocache(pdev->resource[1].start,
++                                   pdev->resource[1].end - pdev->resource[1].start + 1);
++    //printk("NAND data port mapping to addr = 0x%x, phy = 0x%x\n", (u32)data->chip.IO_ADDR_R, (u32)pdev->resource[1].start);                                   
++    if (data->chip.IO_ADDR_R == NULL) {
++        dev_err(&pdev->dev, "ioremap failed for data port.\n");
++        res = -EIO;
++        goto out_no_ior;
++    }
++  
++#endif
++
++    /* The following setting was done in nsboot already. Actually it don't need to be 
++     * configured again. 
++     */
++    writel(BUSY_RDY_LOC(6) | CMD_STS_LOC(0) | CE_NUM(0) | DATA_INVERSE,
++           data->io_base + GENERAL_SETTING);
++
++	val = readl(data->io_base + AHB_SLAVEPORT_SIZE);
++	val &= ~0xFFF0FF;
++	val |= AHB_SLAVE_SPACE_32KB;
++	for(i = 0; i < MAX_CHANNEL; i++)
++		val |= AHB_PREFETCH(i);
++	val |= AHB_PRERETCH_LEN(128);	
++	writel(val, data->io_base + AHB_SLAVEPORT_SIZE);
++
++    /* Currently, it is fixed in LEGACY_FLASH//???
++     */
++    sel = 2;
++	//printk(KERN_INFO "Use %s NAND chip...\n", nand_attr[sel].name);
++	spare = nand_attr[sel].sparesize;
++	useecc = nand_attr[sel].ecc;
++	useecc_spare = nand_attr[sel].ecc_spare;
++	eccbasft = nand_attr[sel].eccbaseshift;
++	protect_spare = nand_attr[sel].crc;
++	
++	data->flash_type = nand_attr[sel].flash_type;
++
++    data->chip.priv = data;
++    data->mtd.priv = &data->chip;
++    data->mtd.owner = THIS_MODULE;
++    data->mtd.name = "nand-flash";//u-boot commandline
++    data->dev = &pdev->dev;
++    data->chip.IO_ADDR_W = data->chip.IO_ADDR_R;
++    data->chip.select_chip = ftnandc024_nand_select_chip;
++    data->chip.cmdfunc = ftnandc024_nand_cmdfunc;
++    data->chip.read_byte = ftnandc024_read_byte;
++    data->chip.write_page = ftnandc024_nand_write_page;
++    data->chip.waitfunc = ftnandc024_nand_wait;
++    data->chip.block_markbad = ftnandc024v2_block_markbad;
++    data->chip.chip_delay = 0;
++
++    //data->chip.options = NAND_BBT_USE_FLASH | NAND_NO_SUBPAGE_WRITE | NAND_OWN_BUFFERS;
++    data->chip.options = NAND_NO_SUBPAGE_WRITE | NAND_OWN_BUFFERS;      /* remove NAND_BBT_USE_FLASH */
++    block_boundary = nand_attr[sel].block_boundary;
++    platform_set_drvdata(pdev, data);
++
++	// Set the default AC timing/Warmup cyc for ftnandc024. 
++	// The register of AC timing/Warmup  keeps the value 
++	// set before although the Global Reset is set. 
++	ftnandc024_set_default_timing(&data->mtd);
++	ftnandc024_set_default_warmup_cyc(&data->mtd);
++	
++	// Disable the scan state for ftnandc024_nand_select_chip
++	data->scan_state = 0;
++
++	// Read the raw id to calibrate the DQS delay for Sync. latching(DDR)
++	ftnandc024_read_raw_id(&data->mtd);
++	if(data->flash_type == TOGGLE1 || data->flash_type == TOGGLE2) {	
++		ftnandc024_calc_timing(&data->mtd);	
++		ftnandc024_calibrate_dqs_delay(&data->mtd, data->flash_type);	
++	}
++
++        /*--------------------------------------------------------
++	 * ONFI flash must work in Asynch mode for READ ID command.
++	 * Switch it back to Legacy.
++	 */
++	if (data->flash_type == ONFI2) {
++		type = data->flash_type;
++		data->flash_type = LEGACY_FLASH;
++	}
++	
++	// Enable the scan state for ftnandc024_nand_select_chip
++	data->scan_state = 1;
++    /* Scan to find existance of the device */
++    for (i = startchn; i < MAX_CHANNEL; i++) {
++        //printk(KERN_INFO "NAND: Scan Channel %d...\n", i);
++
++        data->cur_chan = i;
++        if (!nand_scan_ident(&data->mtd, MAX_CE, NULL)) {
++            if ((0xFFFFFFFF - size) > (data->mtd.size)
++                && ((chipnum + data->chip.numchips) <= NAND_MAX_CHIPS)) {
++                data->valid_chip[i] = data->chip.numchips;
++                chipnum += data->chip.numchips;
++                size += (chipnum * data->chip.chipsize);
++            } else {
++                printk(KERN_INFO "Can not accept more flash chips.\n");
++                break;
++            }
++        }
++    }
++
++    if (chipnum == 0) {
++        res = -ENXIO;
++        goto out_unset_drv;
++    }
++
++    data->chip.numchips = chipnum;
++    data->mtd.size = size;
++    data->scan_state = 0;
++
++    data->chip.ecc.layout = &nand_hw_eccoob;
++    data->chip.bbt_td = &ftnandc024_bbt_main_descr;
++    data->chip.bbt_md = &ftnandc024_bbt_mirror_descr;
++    data->chip.badblock_pattern = &ftnandc024_largepage_flashbased;
++
++	if (spare < (data->mtd.writesize >> 5))
++		spare = (data->mtd.writesize >> 5);
++
++	val = readl(data->io_base + MEM_ATTR_SET);
++	val &= ~(0x7 << 16);
++	switch (data->mtd.writesize) {
++	case 512:
++		val |= PG_SZ_512;
++		data->large_page = 0;
++		break;
++	case 2048:
++		val |= PG_SZ_2K;
++		data->large_page = 1;
++		break;
++	case 4096:
++		val |= PG_SZ_4K;
++		data->large_page = 1;
++		break;
++	case 8192:
++		val |= PG_SZ_8K;
++		data->large_page = 1;
++		break;
++	case 16384:
++		val |= PG_SZ_16K;
++		data->large_page = 1;
++		break;
++	}
++	val &= ~(0x3FF << 2);
++	val |= ((block_boundary - 1) << 2);
++	writel(val, data->io_base + MEM_ATTR_SET);
++	
++	val = readl(data->io_base + MEM_ATTR_SET2); 
++	val &= ~(0x3FF << 16);
++	val |=  VALID_PAGE((data->mtd.erasesize / data->mtd.writesize - 1));
++	writel(val, data->io_base + MEM_ATTR_SET2);
++
++	i = ftnandc024_available_oob(&data->mtd);
++	if (likely(i >= 4)) {
++		if (i > 32)
++			data->mtd.oobsize = 32;
++		else
++			data->mtd.oobsize = i;
++		data->chip.ecc.layout->oobfree[0].length = data->mtd.oobsize;
++	} else {
++		res = -ENXIO;
++		goto out_unset_drv;
++	}	
++	DBGLEVEL1(ftnandc024_dbg("total oobsize: %d\n", data->mtd.oobsize));
++	
++	switch(data->mtd.oobsize){
++	case 4:
++	case 8:
++	case 16:
++	case 32:
++		spare = data->mtd.oobsize;
++		/* In MTD utility, the oobsize should be multiple of 64. We should be on the way. */
++		data->mtd.oobsize = nand_attr[sel].sparesize;
++		DBGLEVEL1(ftnandc024_dbg("oobsize(page mode): %02d\n", data->mtd.oobsize));
++		break;
++	default:
++		data->mtd.oobsize = 4;
++		spare = data->mtd.oobsize;
++		DBGLEVEL1(
++			ftnandc024_dbg("Warning: Unknown spare setting %d, use default oobsize(page mode): 4\n"
++			, data->mtd.oobsize));
++		break;
++	}
++	
++	if (useecc > 0) {
++		DBGLEVEL1(ftnandc024_dbg("ECC correction bits: %d\n", useecc));
++		writel(0x01010101, data->io_base + ECC_THRES_BITREG1);
++		writel(0x01010101, data->io_base + ECC_THRES_BITREG2);
++		val = (useecc - 1) | ((useecc - 1) << 8) | ((useecc - 1) << 16) | ((useecc - 1) << 24);
++		writel(val, data->io_base + ECC_CORRECT_BITREG1);
++		writel(val, data->io_base + ECC_CORRECT_BITREG2);
++
++		val = readl(data->io_base + ECC_CONTROL);
++		val &= ~ECC_BASE;
++		if (eccbasft > 9)
++			val |= ECC_BASE;
++		val |= (ECC_EN(0xFF) | ECC_ERR_MASK(0xFF));
++		writel(val, data->io_base + ECC_CONTROL);
++		writel(ECC_INTR_THRES_HIT | ECC_INTR_CORRECT_FAIL, data->io_base + ECC_INTR_EN);
++	} else {
++		DBGLEVEL1(ftnandc024_dbg("ECC disabled\n"));
++		writel(0, data->io_base + ECC_THRES_BITREG1);
++		writel(0, data->io_base + ECC_THRES_BITREG2);
++		writel(0, data->io_base + ECC_CORRECT_BITREG1);
++		writel(0, data->io_base + ECC_CORRECT_BITREG2);
++
++		val = readl(data->io_base + ECC_CONTROL);
++		val &= ~ECC_BASE;
++		val &= ~(ECC_EN(0xFF) | ECC_ERR_MASK(0xFF));
++		val |= ECC_NO_PARITY;
++		writel(val, data->io_base + ECC_CONTROL);
++	}
++
++	// Enable the Status Check Intr
++	val = readl(data->io_base + INTR_ENABLE);
++	val &= ~INTR_ENABLE_STS_CHECK_EN(0xff);
++	val |= INTR_ENABLE_STS_CHECK_EN(0xff);
++	writel(val, data->io_base + INTR_ENABLE);
++
++	// Setting the ecc capability & threshold for spare
++	writel(0x01010101, data->io_base + ECC_THRES_BITREG1);
++	writel(0x01010101, data->io_base + ECC_THRES_BITREG2);
++	val = (useecc_spare-1) | ((useecc_spare-1) << 8) | ((useecc_spare-1) << 16) | ((useecc_spare-1) << 24);
++	writel(val, data->io_base + ECC_CORRECT_BIT_FOR_SPARE_REG1);  
++	writel(val, data->io_base + ECC_CORRECT_BIT_FOR_SPARE_REG2);  
++
++	DBGLEVEL2(ftnandc024_dbg("struct nand_buffers size:%d\n", sizeof(struct nand_buffers)));
++	data->chip.buffers = kmalloc(sizeof(struct nand_buffers), GFP_KERNEL);
++	if (!data->chip.buffers) {
++		dev_err(&pdev->dev, "failed to allocate chip buffers.\n");
++		res = -ENOMEM;
++		goto out_unset_drv;
++	}
++	else if((sizeof(struct nand_buffers) <  data->mtd.writesize)) {
++		dev_err(&pdev->dev, "Please adjust the NAND_MAX_OOBSIZE & NAND_MAX_PAGESIZE\n");
++		dev_err(&pdev->dev, "Flash Page size:%d, but NAND_MAX_PAGESIZE is %d\n", data->mtd.writesize, NAND_MAX_PAGESIZE);
++		res = -ENOMEM;
++		goto out_unset_drv;
++	}
++
++    data->chip.ecc.mode = NAND_ECC_HW;
++    data->chip.ecc.size = data->mtd.writesize;
++    data->chip.ecc.bytes = 0;
++    data->chip.ecc.read_page = ftnandc024_nand_read_page;
++    data->chip.ecc.write_page = ftnandc024_nand_write_page_lowlevel;
++    data->chip.ecc.read_oob = ftnandc024_nand_read_oob_std;
++    data->chip.ecc.write_oob = ftnandc024_nand_write_oob_std;
++    data->chip.ecc.read_page_raw = ftnandc024_nand_read_page;
++
++    if (data->large_page) {
++        data->read_page = ftnandc024_nand_read_page_lp;
++        data->write_page = ftnandc024_nand_write_page_lp;
++        data->read_oob = ftnandc024_nand_read_oob_lp;
++        data->write_oob = ftnandc024_nand_write_oob_lp;
++    } else {
++        data->read_page = ftnandc024_nand_read_page_sp;
++        data->write_page = ftnandc024_nand_write_page_sp;
++        data->read_oob = ftnandc024_nand_read_oob_sp;
++        data->write_oob = ftnandc024_nand_write_oob_sp;
++    }
++
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++#ifdef CONFIG_NAND_V2_USE_AHBDMA
++    printk("use AHB DMA mode\n");
++#else
++    printk("use AXI DMA mode\n");
++#endif    
++    dma_cap_set(DMA_SLAVE, data->cap_mask);
++    data->dma_chan = dma_request_channel(data->cap_mask, NULL, NULL);//step 1
++
++    if (!data->dma_chan){
++        dev_err(&pdev->dev, "DMA channel allocation failed\n");
++        res = -ENODEV;
++        goto out_free_buf;
++    }
++    printk("Nand get DMA channel %d\n", data->dma_chan->chan_id);
++
++    data->mem_dmabuf = dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->mem_dmaaddr, GFP_KERNEL);
++//printk("vir=%x, phy=%x\n",data->mem_dmabuf,data->mem_dmaaddr);
++    if (!data->mem_dmabuf) {
++        res = -ENOMEM;
++        goto out_free_dma;
++    }
++    data->sg_dmabuf = dma_to_virt(&pdev->dev, data->mem_dmaaddr);
++      
++    //printk("sg mem pa = 0x%x, va = 0x%x\n", (u32)data->mem_dmaaddr, (u32)data->sg_dmabuf);
++
++#else
++    printk("use PIO mode\n");    
++#endif
++
++    /* read the system header first 
++     */
++    if (1) {
++        /* first disble ecc due to potential different ecc capability 
++         */
++        unsigned int usr_base;
++        
++        /* read system header 
++         */
++        //data->sys_hdr = kzalloc(data->mtd.writesize, GFP_KERNEL);
++        data->sys_hdr = dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->syshd_dmaaddr, GFP_KERNEL);
++        if (data->sys_hdr == NULL) {
++            printk("Warning............NAND: can't alloc memory");
++            return -ENOMEM; 
++        }
++        data->page_addr = 0;
++
++        //data->chip.oob_poi = data->chip.buffers->databuf + data->mtd.writesize;
++        data->chip.oob_poi = spare_buf;
++
++        if (data->read_page(&data->mtd, (u_char *) data->sys_hdr) < 0) {
++            printk("Warning............NAND: read system header fail!");
++            return -ENODEV;
++        }
++
++        printk("row_cycle = %d, nand_col_cycle = %d\n", data->sys_hdr->nandfixup.nand_row_cycle, data->sys_hdr->nandfixup.nand_col_cycle);
++        /* read bad block table 
++         */  
++        //data->bi_table = kzalloc(data->mtd.writesize, GFP_KERNEL);
++        data->bi_table = dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->bitab_dmaaddr, GFP_KERNEL);
++        if (data->bi_table == NULL) {
++            printk("Warning............NAND: can't alloc table memory");
++            return -ENOMEM;            
++        }
++        /* the bi table is next to system header */
++        data->page_addr += 1;
++        if (data->read_page(&data->mtd, (u_char *) data->bi_table) < 0) {
++            printk("Warning............NAND: read bad block table fail!");
++            return -ENODEV;
++        }
++            
++        partitions = ftnandc024_partition_info;
++        partitions_num = partition_check(partitions, data, data->mtd.erasesize); 
++
++        /* 
++         * calculate the mtd of user configuration base
++         */
++        /* user partition */       
++        usr_base = data->sys_hdr->image[partitions_num].addr + data->sys_hdr->image[partitions_num].size + (2 * data->mtd.writesize);
++        partitions[partitions_num].offset = ftnandc024v2_get_blockbase(&data->mtd, usr_base);
++
++        /* restore the orginal setting */
++        data->page_addr = 0;
++    }
++
++    /* Scan bad block and create bbt table
++     */    
++    nand_scan_tail(&data->mtd);
++
++        /*----------------------------------------------------------
++	 * ONFI synch mode means High Speed. If fails to change to
++	 * Synch mode, then use flash as Async mode(Normal speed) and
++	 * use LEGACY_LARGE fix flow.
++	 */
++	if (type == ONFI2) {
++		if (ftnandc024_onfi_sync(&data->mtd) == 0) {
++			data->flash_type = ONFI2;
++			ftnandc024_calc_timing(&data->mtd);
++			ftnandc024_calibrate_dqs_delay(&data->mtd, ONFI2);
++		}
++		else{
++			data->flash_type = LEGACY_FLASH;
++		}
++	}
++	
++	// Toggle & ONFI flash has set the proper timing before READ ID.
++	// We don't do that twice.	
++	//if (data->flash_type == LEGACY_FLASH) {
++		ftnandc024_calc_timing(&data->mtd);
++	//}
++
++    res = mtd_device_parse_register(&data->mtd, NULL, 0, partitions, partitions_num);
++    if (!res)
++        return res;
++
++    nand_release(&data->mtd);
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++  out_free_dma:
++    if(data->dma_chan)
++    	dma_release_channel(data->dma_chan);
++  out_free_buf:
++#endif
++    kfree(data->chip.buffers);
++
++  out_unset_drv:
++    platform_set_drvdata(pdev, NULL);
++
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    if(data->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->mem_dmabuf, data->mem_dmaaddr);
++#else
++  out_no_ior:
++    iounmap(data->chip.IO_ADDR_R);
++#endif
++    iounmap(data->io_base);
++  out_free_data:
++    if (data->sys_hdr)
++        kfree(data->sys_hdr);
++    if (data->bi_table)
++        kfree(data->bi_table);
++    kfree(data);
++  out:
++    return res;
++}
++
++/*
++ * @consult with bad block table about this block is good or bad.
++ *
++ * @ftnandc_read_bbt(struct mtd_info *mtd, loff_t offs)
++ * @param mtd: MTD device structure
++ * @param offs: block base address
++ * @return: 1 for bad block, 0 for good block
++*/
++int ftnandc_read_bbt(struct mtd_info *mtd, loff_t offs)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc024_nand_data *data = chip->priv;
++    unsigned int *bi_table = (unsigned int *)data->bi_table;
++    int quotient, remainder, blk_id, result;
++
++    blk_id = offs >> chip->bbt_erase_shift;
++    quotient = blk_id >> 5;
++    remainder = blk_id & 0x1F;
++    result = (bi_table[quotient] >> remainder) & 0x1;
++
++    if (result == 1)
++        return 0;               /* good */
++
++    return 1;                   /* bad */
++}
++
++extern int erase_write_block0 (struct mtd_info *mtd, unsigned long pos, int len, const char *buf);
++/**
++ * ftnandc024v2_default_block_markbad - mark a block bad
++ * @mtd:	MTD device structure
++ * @ofs:	offset from device start
++ *
++ * This is the default implementation, which can be overridden by
++ * a hardware specific driver.
++*/
++static int ftnandc024v2_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nand_chip *chip = mtd->priv;
++	struct ftnandc024_nand_data *data = chip->priv;
++	unsigned int *bi_table = (unsigned int *)data->bi_table;
++	int ret = 0;
++	int quotient, remainder, blk_id, result;
++	size_t retlen;
++
++    printk("markbad, addr = 0x%x\n", (int)ofs);
++    
++    platform_select_pinmux(nand_fd, 0);
++    
++	/* Get block number */
++	blk_id = (int)(ofs >> chip->bbt_erase_shift);
++	if (data->bi_table){
++	    blk_id = ofs >> chip->bbt_erase_shift;
++	    quotient = blk_id >> 5;
++	    remainder = blk_id & 0x1F;
++    	result = (bi_table[quotient] >> remainder) & 0x1;
++    	//printk("BI table %dth, bit %d, data = 0x%x, result = %d\n", quotient, remainder, bi_table[quotient], result);
++    	if (result == 0) {/* bad block, not need to do it */
++      	    ret = 0;
++      	    goto exit_block_markbad;
++        }      
++	    
++	    bi_table[quotient] &= ~(1 << remainder);/* Write the block mark. */
++	    blk_id <<= 1;
++	    //printk("blk_id %dth, data = 0x%x, result = %x\n", blk_id, chip->bbt[blk_id >> 3], (0x3 << (blk_id & 0x06)));
++	    chip->bbt[blk_id >> 3] |= (0x3 << (blk_id & 0x06));	 	    
++	}
++
++	ret = erase_write_block0(mtd, 0, mtd->writesize, (const uint8_t *)data->sys_hdr);
++	if (ret < 0)
++		printk("Markbad Step 1 Error\n");
++
++	//data->page_addr = 1;
++	ret = mtd_write(mtd, mtd->writesize, mtd->writesize, &retlen, (const uint8_t *)bi_table);
++	if (ret < 0)
++		printk("Markbad Step 2 Error\n");
++		
++exit_block_markbad:	
++	platform_select_pinmux(nand_fd, -1);
++		
++	return ret;
++}
++
++/*
++ * @get block baseaddr. It skips the bad block as well.
++ *
++ * @ftnandc024v2_get_blockbase(struct mtd_info *mtd, unsigned int base_addr)
++ * @param mtd: MTD device structure
++ * @param base_addr: liner base address
++ * @return: good block address
++*/
++unsigned int ftnandc024v2_get_blockbase(struct mtd_info *mtd, unsigned int base_addr)
++{
++    struct nand_chip *chip = mtd->priv;
++    unsigned int block_base;
++
++    block_base = BLOCK_ALIGN(base_addr, chip->bbt_erase_shift);
++
++    while (ftnandc_read_bbt(mtd, (loff_t) block_base) != 0)        /* find good block */
++        block_base += (0x1 << chip->bbt_erase_shift);   //move to next block
++
++    return block_base;
++}
++
++/*
++ * Remove a NAND device.
++ */
++static int __devexit ftnandc024_nand_remove(struct platform_device *pdev)
++{
++    struct ftnandc024_nand_data *data = platform_get_drvdata(pdev);
++
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    if(data->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->mem_dmabuf, data->mem_dmaaddr);
++    if(data->dma_chan)
++    	dma_release_channel(data->dma_chan);
++#endif
++    if(data->sys_hdr)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->sys_hdr, data->syshd_dmaaddr);
++    if(data->bi_table)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->bi_table, data->bitab_dmaaddr);
++
++    nand_release(&data->mtd);
++    iounmap(data->io_base);
++    kfree(data->chip.buffers);
++    kfree(data);
++
++    return 0;
++}
++
++static void ftnandc024_release(struct device *dev)
++{
++}
++
++static u64 ftnandc024_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftnandc024_device = {
++    .name = "ftnandc024_nand",
++    .id = -1,
++    .num_resources = ARRAY_SIZE(ftnandc024_resource),
++    .resource = ftnandc024_resource,
++    .dev = {
++            .dma_mask = &ftnandc024_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            .release = ftnandc024_release,
++            },
++};
++
++static struct platform_driver ftnandc024_nand_driver = {
++    .probe = ftnandc024_nand_probe,
++    .remove = __devexit_p(ftnandc024_nand_remove),
++    .driver = {
++               .name = "ftnandc024_nand",
++               .owner = THIS_MODULE,
++               },
++};
++
++static int __init ftnandc024_nand_init(void)
++{
++    int ret = 0;
++
++    /* check if the system is running NAND system 
++     */   
++#ifndef CONFIG_FPGA
++    if (platform_check_flash_type() != 0){
++        printk("Not for NAND pin mux\n");
++        return 0;
++    }
++#endif        
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++    init_waitqueue_head(&nand024_queue);
++#endif    
++    /* Register PMU and turn on gate clock
++     */
++    nand_fd = ftpmu010_register_reg(&pmu_reg_info);
++    if (nand_fd < 0)
++        printk("NANDC: register PMU fail");
++
++#ifdef CONFIG_GPIO_WP
++    if ((ret = gpio_request(GPIO_PIN, PIN_NAME)) != 0) {
++        printk("gpio request fail\n");
++        return ret;
++    }
++    printk("register GPIO for NAND write protect\n");
++#endif
++
++    if (platform_device_register(&ftnandc024_device)) {
++        printk(KERN_ERR "device register failed\n");
++        ret = -ENODEV;
++    }
++    if (platform_driver_register(&ftnandc024_nand_driver)) {
++        printk(KERN_ERR "driver register failed\n");
++        ret = -ENODEV;
++    }
++    return ret;
++}
++
++static void __exit ftnandc024_nand_exit(void)
++{
++    /* check if the system is running NAND system 
++     */
++#ifndef CONFIG_FPGA
++    if (platform_check_flash_type() != 0)
++        return;
++#endif
++    /* Deregister PMU
++     */
++    ftpmu010_deregister_reg(nand_fd);
++
++    platform_driver_unregister(&ftnandc024_nand_driver);
++    platform_device_unregister(&ftnandc024_device);
++}
++
++#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA)
++/*
++ * @callback function from DMAC module
++ *
++ * @ftnandc024_dma_callback int func(int ch, u16 int_status, void *data)
++ * @param ch is used to indicate DMA channel
++ * @param int_status indicates the interrupt status of DMA controller
++ * @param data indicates the private data
++ * @return: none
++*/
++void ftnandc024_dma_callback(void *param)
++{
++    //printk("%s\n", __func__);
++
++    trigger_flag = 1;
++    wake_up(&nand024_queue);
++
++    return;
++}
++#endif
++
++module_init(ftnandc024_nand_init);
++module_exit(ftnandc024_nand_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Te-Chen Ying");
++MODULE_DESCRIPTION("FTnandc024 V2.0 NAND driver");
++MODULE_ALIAS("platform:ftnandc024_nand");
+diff --git a/drivers/mtd/nand/ftnandc024v2_nand.h b/drivers/mtd/nand/ftnandc024v2_nand.h
+new file mode 100644
+index 00000000..aee3aa47
+--- /dev/null
++++ b/drivers/mtd/nand/ftnandc024v2_nand.h
+@@ -0,0 +1,278 @@
++/* general register difinition */
++#define ECC_CONTROL			0x8
++#define	  ECC_ERR_MASK(x)		(x << 0)
++#define	  ECC_EN(x)			(x << 8)
++#define	  ECC_BASE			(1 << 16)
++#define	  ECC_NO_PARITY			(1 << 17)
++#define ECC_THRES_BITREG1		0x10
++#define	ECC_THRES_BITREG2		0x14
++#define ECC_CORRECT_BITREG1		0x18
++#define	ECC_CORRECT_BITREG2		0x1C
++#define	ECC_INTR_EN			0x20
++#define	  ECC_INTR_THRES_HIT		(1 << 1)
++#define	  ECC_INTR_CORRECT_FAIL		(1 << 0)
++#define	ECC_INTR_STATUS			0x24
++#define	  ECC_ERR_THRES_HIT(x)		(1 << (8 + x))
++#define	  ECC_ERR_FAIL(x)		(1 << x)
++#define ECC_THRES_BIT_FOR_SPARE_REG1    0x34
++#define ECC_THRES_BIT_FOR_SPARE_REG2    0x38
++#define ECC_CORRECT_BIT_FOR_SPARE_REG1  0x3C
++#define ECC_CORRECT_BIT_FOR_SPARE_REG2  0x40
++#define	DEV_BUSY			0x100
++#define GENERAL_SETTING			0x104
++#define	  CE_NUM(x)			(x << 24)
++#define	  BUSY_RDY_LOC(x)		(x << 12)
++#define	  CMD_STS_LOC(x)		(x << 8)
++//#define	  REPORT_ADDR_EN		(1 << 4)
++#define	  WRITE_PROTECT			(1 << 2)
++#define	  DATA_INVERSE			(1 << 1)
++#define	  DATA_SCRAMBLER		(1 << 0)
++#define MEM_ATTR_SET			0x108
++#define   PG_SZ_512				(0 << 16)
++#define   PG_SZ_2K				(1 << 16)
++#define   PG_SZ_4K				(2 << 16)
++#define   PG_SZ_8K				(3 << 16)
++#define   PG_SZ_16K				(4 << 16)
++#define	  ATTR_COL_CYCLE(x)		((x & 0x1) << 12)
++#define	  ATTR_ROW_CYCLE(x)		((x & 0x3) << 13)
++	#define ROW_ADDR_1CYCLE		0
++	#define ROW_ADDR_2CYCLE		1
++	#define ROW_ADDR_3CYCLE		2
++	#define ROW_ADDR_4CYCLE		3
++	#define COL_ADDR_1CYCLE		0
++	#define COL_ADDR_2CYCLE		1
++#define	MEM_ATTR_SET2			0x10C
++//#define	  SPARE_PAGE_MODE(x)		(x << 0)
++//#define	  SPARE_PROT_EN(x)		(x << 8)
++#define	  VALID_PAGE(x)			((x & 0x3FF) << 16)
++
++#define	FL_AC_TIMING0(x)		(0x110 + (x << 3))
++#define	FL_AC_TIMING1(x)		(0x114 + (x << 3))
++#define FL_AC_TIMING2(x)		(0x190 + (x << 3))
++#define FL_AC_TIMING3(x)		(0x194 + (x << 3))
++#define INTR_ENABLE             0x150
++//#define STS_FAIL_INT_EN(x)      (0x1 << x)
++//#define CRC_FAIL_INT_EN(x)      (0x1 << (x + 8))
++//#define   INTR_ENABLE_CRC_CHECK_EN(x)	(x << 8)
++#define	  INTR_ENABLE_STS_CHECK_EN(x)	(x << 0)
++#define INTR_STATUS			0x154
++#define	  STATUS_CMD_COMPLETE(x)	(1 << (16 + x))
++//#define	  STATUS_CRC_FAIL(x)		(1 << (8 + x))
++#define	  STATUS_FAIL(x)		(1 << x)
++#define READ_STATUS0			0x178
++#define CMDQUEUE_STATUS			0x200
++#define	  CMDQUEUE_STATUS_FULL(x)	(1 << (8 + x))
++
++#define	CMDQUEUE1(x)			(0x300 + (x << 5))
++#define	CMDQUEUE2(x)			(0x304 + (x << 5))
++#define	CMDQUEUE3(x)			(0x308 + (x << 5))
++#define	  CMD_COUNT(x)			(x << 16)
++#define	CMDQUEUE4(x)			(0x30C + (x << 5))
++//#define	CMDQUEUE5(x)			(0x310 + (x << 5))
++//#define	  CMD_COUNT(x)			(x << 16)
++//#define	CMDQUEUE6(x)			(0x314 + (x << 5))
++#define	  CMD_COMPLETE_EN		(1 << 0)
++#define	  CMD_SCALE(x)			((x & 0x3) << 2)
++#define   CMD_DMA_HANDSHAKE_EN	(1 << 4)
++#define	  CMD_FLASH_TYPE(x)		((x & 0x7) << 5)
++#define	  CMD_INDEX(x)			((x & 0x3FF) << 8)
++#define   CMD_PROM_FLOW			(1 << 18)
++#define	  CMD_SPARE_NUM(x)		(((x - 1) &0x1F) << 19)
++#define	  CMD_BYTE_MODE			(1 << 28)
++#define	  CMD_START_CE(x)		((x & 0x7) << 29)
++
++#define	BMC_REGION_STATUS		0x400
++#define AHB_SLAVEPORT_SIZE		0x508
++#define   AHB_SLAVE_SPACE_512B          (1 << 0)
++#define   AHB_SLAVE_SPACE_1KB           (1 << 1)
++#define   AHB_SLAVE_SPACE_2KB           (1 << 2)
++#define   AHB_SLAVE_SPACE_4KB           (1 << 3)
++#define   AHB_SLAVE_SPACE_8KB           (1 << 4)
++#define   AHB_SLAVE_SPACE_16KB          (1 << 5)
++#define   AHB_SLAVE_SPACE_32KB          (1 << 6)
++#define   AHB_SLAVE_SPACE_64KB          (1 << 7)
++#define   AHB_RETRY_EN(ch_index)        (1 << (ch_index + 8))
++#define   AHB_PREFETCH(ch_index)        (1 << (ch_index + 12))
++#define   AHB_PRERETCH_LEN(x_words)     (x_words << 16)
++#define   AHB_SPLIT_EN                  (1 << 25)
++#define	GLOBAL_RESET			0x50C
++#define DQS_DELAY			0x520
++#define PROGRAMMABLE_OPCODE		0x700
++#define PROGRAMMABLE_FLOW_CONTROL	0x2000
++#define	SPARE_SRAM			0x1000
++
++#define		FIXFLOW_READID				0x5F
++#define		FIXFLOW_RESET				0x65
++#define		FIXFLOW_READSTATUS			0x96
++/* FIX_FLOW_INDEX for small page */
++#define		SMALL_FIXFLOW_READOOB		0x249
++#define		SMALL_FIXFLOW_PAGEREAD		0x23E
++#define		SMALL_FIXFLOW_PAGEWRITE		0x26C
++#define		SMALL_FIXFLOW_WRITEOOB		0x278
++#define		SMALL_FIXFLOW_ERASE			0x2C1
++
++/* FIX_FLOW_INDEX for large page */
++#define		LARGE_FIXFLOW_BYTEREAD			0x8A
++#define		LARGE_FIXFLOW_READOOB			0x3E
++#define		LARGE_FIXFLOW_PAGEREAD			0x1C
++#define		LARGE_FIXFLOW_PAGEREAD_W_SPARE	0x48
++#define		LARGE_PAGEWRITE_W_SPARE			0x26
++#define		LARGE_PAGEWRITE					0x54
++#define		LARGE_FIXFLOW_WRITEOOB			0x33
++#define		LARGE_FIXFLOW_ERASE				0x68
++
++/* FIX_FLOW_INDEX for ONFI change mode */
++#define		ONFI_FIXFLOW_GETFEATURE		0x22B
++#define		ONFI_FIXFLOW_SETFEATURE		0x232
++#define		ONFI_FIXFLOW_SYNCRESET		0x21A
++
++#define		max_2(a,b)		max(a,b)
++#define		min_2(a,b)		min(a,b)
++#define 	max_3(a,b,c)	(max_2(a,b) > c ? max_2(a,b): c)
++#define		min_3(a,b,c)	(min_2(a,b) < c ? min_2(a,b): c)
++#define		max_4(a,b,c,d)	(max_3(a,b,c) > d ? max_3(a,b,c): d)
++#define		min_4(a,b,c,d)	(min_3(a,b,c) < d ? min_3(a,b,c): d)
++
++#define		MAX_CE				1   //4
++#define		MAX_CHANNEL			1   //2
++//#define		NAND_USE_AHBDMA_CHANNEL		0
++
++/* For recording the command execution status*/
++#define CMD_SUCCESS				0					
++#define CMD_CRC_FAIL				(1 << 1)
++#define CMD_STATUS_FAIL				(1 << 2)
++#define CMD_ECC_FAIL_ON_DATA			(1 << 3)
++#define CMD_ECC_FAIL_ON_SPARE			(1 << 4)
++
++#ifdef MODULE
++#undef CONFIG_MTD_NAND_FTNANDC024
++#define CONFIG_FTNANDC024_USE_DMA
++
++/* ONFI 2.0 4K MLC */
++#undef CONFIG_FTNANDC024_MICRON_29F32G08CBABB
++/* Toggle 8K MLC*/
++#undef CONFIG_FTNANDC024_SAMSUNG_K9HDGD8X5M
++/* 2K SLC */
++#undef CONFIG_FTNANDC024_SAMSUNG_K9F4G08U0A
++/* 8K MLC */
++#undef CONFIG_FTNANDC024_TOSHIBA_TH58NVG5D2ETA20
++/* 4K MLC */
++#undef CONFIG_FTNANDC024_MICRON_29F16G08MAA
++/* 512B SLC */
++#undef CONFIG_FTNANDC024_HYNIX_HY27US08561A
++/* 4K MLC */
++#undef CONFIG_FTNANDC024_SAMSUNG_K9LBG08U0M
++#endif
++
++//#define CONFIG_FTNANDC024_DEBUG			2
++
++#ifndef CONFIG_FTNANDC024_DEBUG
++#define CONFIG_FTNANDC024_DEBUG			0
++#endif
++#if CONFIG_FTNANDC024_DEBUG > 0
++#define ftnandc024_dbg(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__);
++#else
++#define ftnandc024_dbg(fmt, ...) do {} while (0);
++#endif
++
++#if CONFIG_FTNANDC024_DEBUG > 0
++#define DBGLEVEL1(x)	x
++#else
++#define DBGLEVEL1(x)
++#endif
++
++#if CONFIG_FTNANDC024_DEBUG > 1
++#define DBGLEVEL2(x)	x
++#else
++#define DBGLEVEL2(x)
++#endif
++
++typedef enum {
++	/*LEGACY_SMALL = 0,
++	LEGACY_LARGE,*/
++	LEGACY_FLASH = 0,
++	ONFI2,
++	ONFI3,
++	TOGGLE1,
++	TOGGLE2,
++} flashtype;
++
++struct ftnandc024_nandchip_attr {
++	char *name;
++	int sparesize;
++	int ecc;
++	int eccbaseshift;
++	int ecc_spare;
++	int block_boundary;
++	int crc;
++	flashtype flash_type;
++};
++
++struct ftnandc024_chip_timing {
++	uint8_t		tWH;
++	uint8_t		tCH;
++	uint8_t		tCLH;
++	uint8_t		tALH;
++	uint8_t		tCALH;
++	uint8_t		tWP;
++	uint8_t		tREH;
++	uint8_t		tCR;
++	uint8_t		tRSTO;
++	uint8_t		tREAID;
++	uint8_t		tREA;
++	uint8_t		tRP;
++	uint8_t		tWB;
++	uint8_t		tRB;
++	uint8_t		tWHR;
++	int			tWHR2;
++	uint8_t		tRHW;
++	uint8_t		tRR;
++	uint8_t		tAR;
++	uint8_t		tRC;
++	int			tADL;
++	uint8_t		tRHZ;
++	uint8_t		tCCS;
++	uint8_t		tCS;
++	uint8_t		tCS2;
++	uint8_t		tCLS;
++	uint8_t		tCLR;
++	uint8_t		tALS;
++	uint8_t		tCALS;
++	uint8_t		tCAL2;
++	uint8_t		tCRES;
++	uint8_t		tCDQSS;
++	uint8_t		tDBS;
++	int			tCWAW;
++	uint8_t		tWPRE;
++	uint8_t		tRPRE;
++	uint8_t		tWPST;
++	uint8_t		tRPST;
++	uint8_t		tWPSTH;
++	uint8_t		tRPSTH;
++	uint8_t		tDQSHZ;
++	uint8_t		tDQSCK;
++	uint8_t		tCAD;
++	uint8_t		tDSL;
++	uint8_t		tDSH;
++	uint8_t		tDQSL;
++	uint8_t		tDQSH;
++	uint8_t		tDQSD;
++	uint8_t		tCKWR;
++	uint8_t		tWRCK;
++	uint8_t		tCK;
++	uint8_t		tCALS2;
++	uint8_t		tDQSRE;
++	uint8_t		tWPRE2;
++	uint8_t		tRPRE2;
++	uint8_t		tCEH;
++};
++
++struct cmd_feature {
++	u32 cq1;
++	u32 cq2;
++	u32 cq3;
++	u32 cq4;
++	u8 row_cycle;
++	u8 col_cycle;
++};
++void ftnandc024_nand_select_chip(struct mtd_info *mtd, int chip);
+\ No newline at end of file
+diff --git a/drivers/mtd/nand/ftspi020_nand.c b/drivers/mtd/nand/ftspi020_nand.c
+new file mode 100644
+index 00000000..c06c721e
+--- /dev/null
++++ b/drivers/mtd/nand/ftspi020_nand.c
+@@ -0,0 +1,2697 @@
++/*
++ * FTNANDC023 NAND driver
++ *
++ * 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 <linux/version.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/vmalloc.h>
++#include <linux/dma-mapping.h>
++#include <linux/jiffies.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/board.h>
++#include <mach/ftpmu010.h>
++//#include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/spi/spi.h>
++#include "ftspi020_nand.h"
++#include <linux/delay.h>
++
++//#define MTD_backup  1
++
++#define CONFIG_FTSPI_NAND_DEBUG			0
++#if CONFIG_FTSPI_NAND_DEBUG > 0
++#define ftspi_nand_dbg(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__);
++#else
++#define ftspi_nand_dbg(fmt, ...) do {} while (0);
++#endif
++/*
++ * Local function or variables declaration
++ */
++//#define CONFIG_SPI_NAND_USE_AHBDMA//???
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++#include <linux/dmaengine.h>
++
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++#include <mach/ftdmac020.h>
++#else
++#include <mach/ftdmac030.h>
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++#define AHBMASTER_R_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_R_DST   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_SRC   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_DST   FTDMA020_AHBMASTER_0
++#define SPI020_REQ    8
++#endif
++
++#endif
++
++#define PORTING
++static int ftnandc023v2_block_markbad(struct mtd_info *mtd, loff_t ofs);
++static int calc_new_page(struct mtd_info *mtd, int page_addr);
++int ftnandc_spi_read_bbt(struct mtd_info *mtd, loff_t offs);
++static int nand_fd, cmdfunc_status = NAND_STATUS_READY;
++
++#define FLASH_PAGESIZE  256
++#define IDCODE_LEN		4
++
++/* Flash opcodes. */
++#define	OPCODE_WREN		0x06    /* Write enable */
++#define	OPCODE_RDSR		0x05    /* Read status register */
++#define	OPCODE_RDSR2	0x35
++#define	OPCODE_WRSR		0x01    /* Write status register 1 byte */
++#define	OPCODE_EN4B		0xB7
++#define	OPCODE_EX4B		0xE9
++
++#define	OPCODE_BE_32K		0x52    /* Erase 32KiB block */
++#define	OPCODE_BE_64K		0xd8    /* Erase 64KiB block */
++
++/* 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	30000
++#define	CMD_SIZE		    4
++
++#define SPI_NAME	"SPI_NAND_FLASH"
++#define BLOCK_ALIGN(base, blk_shift) ((((base) + (0x1 << (blk_shift)) - 1) >> (blk_shift)) << (blk_shift))
++
++/*
++ * Macro definitions
++ */
++#define DEFAULT_BLOCK_SIZE  0x20000
++#define MTD_CFG_SZ          (6 * DEFAULT_BLOCK_SIZE)    //2 block + reserved
++
++#define CONFIG_FTNANDC023_START_CHANNEL     0
++#define BLOCK_ALIGN(base, blk_shift) ((((base) + (0x1 << (blk_shift)) - 1) >> (blk_shift)) << (blk_shift))
++
++#define FTSPI020_FEATURE_RXFIFO_DEPTH(reg)	(((reg) >>  8) & 0xff)
++#define FTSPI020_FEATURE_TXFIFO_DEPTH(reg)	(((reg) >>  0) & 0xff)
++
++static uint8_t ftnandc023_bbt_pattern[] = { 'B', 'b', 't', '0' };
++static uint8_t ftnandc023_mirror_pattern[] = { '1', 't', 'b', 'B' };
++
++#ifdef CONFIG_GPIO_WP
++#define GPIO_PIN      28
++#define PIN_NAME      "gpio28"
++#endif
++
++//=============================================================================
++// System Header, size = 512 bytes
++//=============================================================================
++
++static int read_id_time = 0, ID_point = 0;
++static int startchn = CONFIG_FTNANDC023_START_CHANNEL;
++static int legacy;
++
++static u8 idcode[IDCODE_LEN];
++static struct mtd_partition PORTING ftnandc023_partition_info[20];
++
++int show_one_time = 1;int read_ecc_limit = 0;
++extern int root_mtd_num;
++
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++static void ftspi020_dma_callback(void *param);
++static unsigned int dma_trigger_flag = 0;
++static wait_queue_head_t dma_queue;
++#endif
++
++/******************************************************************************
++ * spi private data
++ *****************************************************************************/
++typedef struct spi_nand_sys_header {
++    char signature[8];          /* Signature is "GM8xxx" */
++    unsigned int bootm_addr;    /* Image offset to load by spiboot */
++    unsigned int bootm_size;
++    unsigned int bootm_reserved;
++
++    struct {
++        unsigned int addr;      /* image address */
++        unsigned int size;      /* image size */
++        unsigned char name[8];  /* image name */
++        unsigned int reserved[1];
++    } image[10];
++
++    struct {
++        unsigned int nand_numblks;      //number of blocks in chip
++        unsigned int nand_numpgs_blk;   //how many pages in a block
++        unsigned int nand_pagesz;       //real size in bytes                        
++        unsigned int nand_sparesz_inpage;       //64bytes for 2k, ...... needed for NANDC023
++        unsigned int nand_numce;        //how many CE in chip
++        unsigned int nand_status_bit;
++        unsigned int nand_cmmand_bit;
++        unsigned int nand_ecc_capability;
++        unsigned int nand_ecc_base;     //0/1 indicates 512/1024 bytes      
++        unsigned int nand_sparesz_insect;
++        unsigned int reserved_1;
++        unsigned int nand_row_cycle;    //1 for 1 cycle ...
++        unsigned int nand_col_cycle;    //1 for 1 cycle ...
++        unsigned int reserved[1];
++    } nandfixup;
++    
++    unsigned int reserved2[57]; // unused
++    unsigned char function[4];
++    unsigned char last_511[4];  // byte510:0x55, byte511:0xAA
++} spi_nand_sys_header_t;
++
++struct common_spi_flash {
++    struct spi_device *spi;
++    struct mutex lock;
++    struct mtd_info mtd;
++    spi_nand_sys_header_t *sys_hdr;      /* system header */
++
++    u8 erase_opcode;
++    u8 mode_3_4;
++    u8 flash_type;              //1:winbond, status register is different
++};
++
++static struct resource ftnandc023_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static struct nand_ecclayout nand_0_hw_eccoob = {
++    .eccbytes = 16,    
++    .eccpos = {
++               },        
++    .oobfree = {
++                {.offset = 4,.length = 12,},
++                {.offset = 20,.length = 12,},
++                {.offset = 36,.length = 12,},
++                {.offset = 52,.length = 12,}
++                },
++};
++
++static struct nand_ecclayout nand_1_hw_eccoob = {
++    .eccbytes = 16,    
++    .eccpos = {
++               /* at the end of spare sector */
++               12, 13, 14, 15,
++               28, 29, 30, 31,
++               44, 45, 46, 47,
++               60, 61, 62, 63,
++               },        
++    .oobfree = {
++                {.offset = 4,.length = 8},
++                {.offset = 20,.length = 8},
++                {.offset = 36,.length = 8},
++                {.offset = 52,.length = 8}
++                },
++};
++
++static struct nand_ecclayout nand_2_hw_eccoob = {
++    .eccbytes = 12,    
++    .eccpos = {
++               /* at the end of spare sector */
++               1, 2, 3,
++               17, 18, 19,
++               33, 34, 35,
++               49, 50, 51,
++               },
++    .oobfree = {
++                {.offset = 8,.length = 8,},
++                {.offset = 24,.length = 8,},
++                {.offset = 40,.length = 8,},
++                {.offset = 56,.length = 8,}
++                },
++};
++
++static struct nand_ecclayout nand_3_hw_eccoob = {
++    .eccbytes = 24,    
++    .eccpos = {
++               /* at the end of spare sector */
++               8, 9, 10, 11, 12, 13,
++               24, 25, 26, 27, 28, 29,
++               40, 41, 42, 43, 44, 45,
++               56, 57, 58, 59, 60, 61,
++               },        
++    .oobfree = {
++                {.offset = 4,.length = 4,},
++                {.offset = 20,.length = 4,},
++                {.offset = 36,.length = 4,},
++                {.offset = 52,.length = 4,}
++                },
++};
++
++static struct nand_ecclayout nand_4_hw_eccoob = {
++    .eccbytes = 28,    
++    .eccpos = {
++               /* at the end of spare sector */
++               18, 19, 20, 21, 22, 23, 24,
++               25, 26, 27, 28, 29, 30, 31,
++               50, 51, 52, 53, 54, 55, 56,
++               57, 58, 59, 60, 61, 62, 63,
++               },        
++    .oobfree = {/* chip & datasheet not match */
++                {.offset = 2,.length = 8,},
++                {.offset = 10,.length = 8,},
++                {.offset = 34,.length = 8,},
++                {.offset = 42,.length = 8,}
++                },
++};
++
++static struct nand_bbt_descr ftnandc023_bbt_mirror_descr = {
++    .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++        | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++    .offs = 0,
++    .len = 4,
++    .veroffs = 4,
++    .maxblocks = 4,
++    .pattern = ftnandc023_mirror_pattern
++};
++
++static struct nand_bbt_descr ftnandc023_bbt_main_descr = {
++    .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++        | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++    .offs = 0,
++    .len = 4,
++    .veroffs = 4,
++    .maxblocks = 4,
++    .pattern = ftnandc023_bbt_pattern
++};
++
++static uint8_t ftnandc023_scan_ff_pattern[] = { 0xff };
++
++static struct nand_bbt_descr ftnandc023_largepage_flashbased = {
++    .options = NAND_BBT_SCAN2NDPAGE,
++    .offs = 0,
++    .len = 1,
++    .pattern = ftnandc023_scan_ff_pattern
++};
++
++//=============================================================================
++// BI table, size = 1024 bytes
++//=============================================================================
++typedef struct bi_table {
++    /* This array size is related to USB_BUFF_SZ defined in usb_scsi.h */
++    unsigned int bi_status[256];        //each bit indicates a block. 1 for good, 0 for bad
++} bi_table_t;
++
++typedef struct lookup_table
++{
++    unsigned short physical[8192];
++} lookup_table_t;
++
++struct ftnandc023_nand_data {
++    struct nand_chip chip;
++    struct mtd_info mtd;
++    void __iomem *io_base;
++    int sel_chip;
++    int cur_cmd;
++    int page_addr;
++    int column;
++    int byte_ofs;
++    u32 *buf;            
++    struct device *dev;
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    struct dma_chan *dma_chan;
++    dma_cap_mask_t cap_mask;
++#ifdef CONFIG_SPI_NAND_USE_AXIDMA
++    struct ftdmac030_dma_slave dma_slave_config;
++#else
++    struct ftdmac020_dma_slave dma_slave_config;
++#endif
++    dma_cookie_t cookie;
++    dma_addr_t mem_dmaaddr;
++    dma_addr_t nand_dmaaddr;
++    unsigned char *mem_dmabuf;
++    unsigned char *sg_dmabuf;
++#endif
++    dma_addr_t syshd_dmaaddr;
++    dma_addr_t bitab_dmaaddr;
++    dma_addr_t lookuptab_dmaaddr;
++       
++    unsigned int ce;
++    unsigned int erase_sector_size;
++    unsigned short page_size;
++    unsigned int nr_pages;
++    unsigned int size;          //chip size
++    unsigned int mode_3_4;      //addres length = 3 or 4 bytes
++    unsigned short chip_type;
++    
++    struct {
++        unsigned int block_pg;
++        unsigned int page_size;
++        unsigned int spare_size;
++        unsigned int block_size;
++    } nand_parm;
++
++    int rxfifo_depth;
++    int txfifo_depth;
++
++    int cur_chan;
++    int valid_chip[MAX_CHANNEL];
++    int scan_state;
++    int flash_type;
++    int large_page;
++    int lookup_flag;
++    //unsigned char ecc_type;
++    unsigned short block_limit;
++    spi_nand_sys_header_t *sys_hdr;      /* system header */
++    bi_table_t *bi_table;       /* bad block table next to sys_hdr */
++    lookup_table_t *lookup_table;
++    int (*write_oob) (struct mtd_info * mtd, const u_char * buf, int len);
++    int (*read_oob) (struct mtd_info * mtd, u_char * buf);
++    int (*write_page) (struct mtd_info * mtd, const uint8_t * buf);
++    int (*read_page) (struct mtd_info * mtd, u_char * buf);
++};
++
++static int ftspi020_data_access(struct ftnandc023_nand_data *data, u8 direction, u8 * addr, u32 len);
++static int spi_flash_cmd_read_fast(struct ftnandc023_nand_data *data, u32 offset, size_t len, u8 *buf);
++/******************************************************************************
++ * internal functions for FTSPI020
++ *****************************************************************************/
++#ifdef CONFIG_PLATFORM_GM8139
++static pmuReg_t pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x54, (0x3F << 26), 0, (0x15 << 26), (0x3F << 26)},        /* pinMux with NAND */
++    {0x58, (0x3 << 0), (0x3 << 0), (0x1 << 0), (0x3 << 0)},     /* DMA ack selection */
++    {0x6C, (0x7 << 0), (0x7 << 0), (0x7 << 0), (0x7 << 0)},
++    {0xB4, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, /* AHB clock gate */
++};
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8136
++static pmuReg_t pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x6C, (0x7 << 0), (0x7 << 0), (0x7 << 0), (0x7 << 0)},
++    {0xB4, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, /* AHB clock gate */
++};
++#endif
++
++static pmuRegInfo_t pmu_reg_info = {
++    "SPI020_NAND",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++static void ftspi020_dma_disable(void __iomem * base)
++{
++    unsigned int tmp = inl(base + FTSPI020_REG_ICR);
++
++    tmp &= ~FTSPI020_ICR_DMA;
++    outl(tmp, base + FTSPI020_REG_ICR);
++}
++
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++static void ftspi020_dma_enable(void __iomem * base)
++{
++    unsigned int tmp = inl(base + FTSPI020_REG_ICR);
++
++    tmp |= FTSPI020_ICR_DMA;
++    outl(tmp, base + FTSPI020_REG_ICR);
++}
++
++static int ftspi020_dma_wait(void)
++{
++    int rc = 0;
++
++    rc = wait_event_timeout(dma_queue, dma_trigger_flag == 1, 10 * HZ);
++    if (rc == 0) {
++        printk(KERN_ERR "SPI-NAND queue wake up timeout signal arrived\n");
++        return 1;
++    }
++
++    dma_trigger_flag = 0;
++    return 0;
++}
++
++#else
++
++static void ftspi020_wait_rxfifo_ready(void __iomem * base)
++{
++    volatile u32 value;
++    unsigned long timeo = jiffies;
++    int ret = 1;
++
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        //udelay (1);
++        value = inl(base + FTSPI020_REG_STS);
++        if (value & FTSPI020_STS_RFR)
++            break;
++    }
++    if (!(value & FTSPI020_STS_RFR))
++        printk(KERN_ERR "Wait RX FIFO timeout!\n");
++    else
++        ret = 0
++
++    return ret;        
++}
++
++static int ftspi020_wait_txfifo_ready(void __iomem * base)
++{
++    volatile u32 value;
++    int ret = 1;
++
++    unsigned long timeo = jiffies;
++
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        //udelay (1);
++        value = inl(base + FTSPI020_REG_STS);
++        if (value & FTSPI020_STS_TFR)
++            break;
++    }
++    if (!(value & FTSPI020_STS_TFR))
++        printk(KERN_ERR "Wait TX FIFO timeout!\n");
++    else
++        ret = 0
++
++    return ret;
++}
++#endif
++
++static unsigned int ftspi020_read_feature(void __iomem * base)
++{
++    return inl(base + FTSPI020_REG_FEATURE);
++}
++
++static int ftspi020_txfifo_depth(void __iomem * base)
++{
++    return FTSPI020_FEATURE_TXFIFO_DEPTH(ftspi020_read_feature(base));
++}
++
++static int ftspi020_rxfifo_depth(void __iomem * base)
++{
++    return FTSPI020_FEATURE_RXFIFO_DEPTH(ftspi020_read_feature(base));
++}
++
++static unsigned char ftspi020_read_status(void __iomem * base)
++{
++    return inb(base + FTSPI020_REG_READ_STS);
++}
++
++static void ftspi020_clk_divider(void __iomem * base, char div)
++{
++	unsigned int tmp = inl(base + FTSPI020_REG_CTRL);
++
++	tmp &= FTSPI020_CTRL_CLK_DIVIDER_MASK;
++	tmp |= div;
++	outl(tmp, base + FTSPI020_REG_CTRL);
++}
++
++static void setup_clk(void __iomem * base)
++{
++    int CLK, SCU_DIV, SPI_DIV, mod, max_speed_hz;
++
++#ifdef CONFIG_PLATFORM_GM8139
++    max_speed_hz = 45 * 1000 * 1000; //45MHz
++
++    if(ftpmu010_read_reg(0x28) & (1 << 13))
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL2) / 4;
++    else
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL1) / 2;
++#endif
++#ifdef CONFIG_PLATFORM_GM8136
++    max_speed_hz = 45 * 1000 * 1000; //45MHz
++
++    if(ftpmu010_read_reg(0x28) & (1 << 10))
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL1);
++    else
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL2);
++#endif
++
++	//printk("CLK = %d\n", CLK);
++    SCU_DIV = CLK / 2;
++    mod = do_div(SCU_DIV, max_speed_hz);
++    
++    if(mod == 0)
++        SCU_DIV -= 1;
++
++    if(SCU_DIV > 7){
++        printk(KERN_ERR "SPI clock too quick\n");
++        SPI_DIV = FTSPI020_CTRL_CLK_DIVIDER_4;
++        SCU_DIV = 3;
++    }
++    else {
++        SPI_DIV = FTSPI020_CTRL_CLK_DIVIDER_2;
++    }
++    
++    CLK = CLK / ((1 << (SPI_DIV + 1)) * (SCU_DIV + 1));
++    ftpmu010_write_reg(nand_fd, 0x6C, SCU_DIV, 0x7);
++
++    printk(KERN_INFO "CLK scu div %d, spi div %d, clock = %dHz\n", SCU_DIV, SPI_DIV, CLK);
++	ftspi020_clk_divider(base, SPI_DIV);
++}
++
++/* polling command complete interrupt until the interrupt comes.
++ */
++static int ftspi020_wait_cmd_complete(struct ftnandc023_nand_data *data)
++{
++    u32 value = 0;
++    int ret = 1;
++    unsigned long timeo = jiffies;
++
++    ftspi_nand_dbg("wait_cmd_complete\n");
++
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        //udelay (1);
++        value = inl(data->io_base + FTSPI020_REG_ISR);
++        if (value & FTSPI020_ISR_CMD_CMPL) {
++            outl(value, data->io_base + FTSPI020_REG_ISR);
++            break;
++        }
++    }
++    if (!(value & FTSPI020_ISR_CMD_CMPL))
++        printk(KERN_ERR "Wait command complete timeout!\n");
++    else
++        ret = 0;
++        
++    return ret;
++}
++
++void ftspi020_issue_cmd(struct ftnandc023_nand_data *data, struct ftspi020_cmd *command)
++{
++    u32 cmd_feature1, cmd_feature2;
++
++    outl(command->spi_addr, data->io_base + FTSPI020_REG_CMD0);
++
++    cmd_feature1 = ((command->conti_read_mode_en & 0x1) << 28) |
++        ((command->ins_len & 0x3) << 24) | ((command->dum_2nd_cyc & 0xFF) << 16) | 
++        ((command->addr_len & 0x7) << 0);
++    outl(cmd_feature1, data->io_base + FTSPI020_REG_CMD1);
++
++    outl(command->data_cnt, data->io_base + FTSPI020_REG_CMD2);
++
++    cmd_feature2 = ((command->ins_code & 0xFF) << 24) |
++        ((command->conti_read_mode_code & 0xFF) << 16) |
++        ((command->start_ce & 0x3) << 8) |
++        ((command->spi_mode & 0x7) << 5) |
++        ((command->dtr_mode & 0x1) << 4) |
++        ((command->read_status & 0x1) << 3) |
++        ((command->read_status_en & 0x1) << 2) | ((command->write_en & 0x1) << 1) | 
++        ((command->intr_en & 0x1) << 0);
++    ftspi_nand_dbg("spi reg 0x%x = 0x%x, reg 0x%x = 0x%x\n", FTSPI020_REG_ICR,
++                   inl(data->io_base + FTSPI020_REG_ICR), FTSPI020_REG_ISR,
++                   inl(data->io_base + FTSPI020_REG_ISR));
++    ftspi_nand_dbg("spi cmd queue = 0x%x, 0x%x, 0x%x, 0x%x\n", command->spi_addr, cmd_feature1,
++                   command->data_cnt, cmd_feature2);
++    outl(cmd_feature2, data->io_base + FTSPI020_REG_CMD3);
++}
++
++void ftspi020_setup_cmdq(struct ftnandc023_nand_data *data, ftspi020_cmd_t * spi_cmd, int ins_code,
++                         int ins_len, int write_en, int spi_mode, int data_cnt)
++{
++    memset(spi_cmd, 0x0, sizeof(ftspi020_cmd_t));
++//SPI_DEBUG("<ftspi020_setup_cmdq=0x%x>",ins_code);      
++    spi_cmd->start_ce = 0;      //only one CE???
++    spi_cmd->ins_code = ins_code;
++    spi_cmd->intr_en = FTSPI020_CMD3_CMD_COMPL_INTR;
++    spi_cmd->ins_len = ins_len;
++    spi_cmd->write_en = write_en;       //0 for the read ata or read status, others are 1.
++    spi_cmd->dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++    spi_cmd->spi_mode = spi_mode;
++    spi_cmd->data_cnt = data_cnt;
++
++    switch (ins_code) {
++    case COMMAND_READ_ID:
++        spi_cmd->spi_addr = 0x00;
++        spi_cmd->addr_len = FTSPI020_CMD1_ADDR_1BYTE;
++        break;
++    case COMMAND_SET_FEATURES:
++        spi_cmd->spi_addr = 0xA0;       // to disble write protect
++        spi_cmd->addr_len = FTSPI020_CMD1_ADDR_1BYTE;
++        break;
++    default:
++        break;
++    }
++
++    /* update to the controller */
++    ftspi020_issue_cmd(data, spi_cmd);
++}
++
++static int spi_xfer(struct ftnandc023_nand_data *data, unsigned int len, const void *dout, void *din,
++             unsigned long flags)
++{
++    struct ftspi020_cmd spi_cmd;
++    u8 *u8_data_out = (u8 *) dout;
++    int ret = 0;
++
++    memset(&spi_cmd, 0, sizeof(struct ftspi020_cmd));
++
++    /* send the instruction */
++    if (flags & SPI_XFER_CMD_STATE) {
++
++        spi_cmd.ins_code = *u8_data_out;
++        //printk("dout=0x%x,din=0x%x,%d,%d\n",*(UINT8 *)dout,*(UINT8 *)din, len, spi->cs);
++        spi_cmd.intr_en = FTSPI020_ISR_CMD_CMPL;
++#ifdef CONFIG_CMD_FPGA
++        spi_cmd.start_ce = 0;
++#endif
++        ftspi_nand_dbg("spi cmd = 0x%x\n", spi_cmd.ins_code);
++        switch (spi_cmd.ins_code) {
++        case COMMAND_READ_ID:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            spi_cmd.data_cnt = IDCODE_LEN;
++            spi_cmd.spi_addr = (u32) * (u8_data_out + 1);
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_1BYTE;
++            break;
++        case COMMAND_RESET:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_WRITE_ENABLE:
++        case COMMAND_WRITE_DISABLE:
++            //if (write_enable == spi_cmd.ins_code){
++            //          printk("exit\n");
++            //    goto exit;
++            //  }
++            //write_enable = spi_cmd.ins_code;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_ERASE_128K_BLOCK:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_ERASE_CHIP:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_WRITE_STATUS:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            spi_cmd.data_cnt = len;
++            break;
++        case COMMAND_READ_STATUS1:
++        case COMMAND_READ_STATUS2:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_EN;
++            spi_cmd.read_status = FTSPI020_CMD3_STS_SW_READ;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_WRITE_PAGE:       //cmd as the same with COMMAND_PROGRAM_EXECUTE
++            spi_cmd.spi_addr = (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_2BYTE;
++
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_WINBOND_QUAD_WRITE_PAGE:
++        case COMMAND_QUAD_WRITE_PAGE:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_QUAD_MODE;
++            break;
++        case COMMAND_FAST_READ_QUAD_IO:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++
++            spi_cmd.dum_2nd_cyc = 4;
++            spi_cmd.conti_read_mode_en = 1;
++            spi_cmd.conti_read_mode_code = 0;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_QUAD_MODE;
++            break;
++        case COMMAND_READ_DATA:
++        case COMMAND_FAST_READ:
++            spi_cmd.spi_addr = (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_2BYTE;
++
++            spi_cmd.dum_2nd_cyc = 8;
++            spi_cmd.conti_read_mode_en = 0;
++            spi_cmd.conti_read_mode_code = 0;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_FAST_READ_DUAL:
++            spi_cmd.spi_addr = (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_2BYTE;
++
++            spi_cmd.dum_2nd_cyc = 8;
++            spi_cmd.conti_read_mode_en = 0;
++            spi_cmd.conti_read_mode_code = 0;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_DUAL_MODE;
++            break;
++        case COMMAND_GET_FEATURES:
++            spi_cmd.spi_addr = (u32) * (u8_data_out + 1);
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_1BYTE;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_EN;
++            spi_cmd.read_status = FTSPI020_CMD3_STS_SW_READ;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_PAGE_READ:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = 0;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_PROGRAM_EXECUTE:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        default:
++            printk(KERN_ERR "Not define this command 0x%x!!!!!!!\n", spi_cmd.ins_code);
++            goto xfer_exit;
++            break;
++        }
++        /* sent the command out */
++        ftspi020_issue_cmd(data, &spi_cmd);
++
++    }
++    else if (flags & SPI_XFER_DATA_IN_STATE) {
++        /* read the data */
++        //printk("read len = %d, buf = 0x%x\n", len, din);
++        ret = ftspi020_data_access(data, 1, (u8 *) din, len);
++        if(ret)
++            return ret;
++        ftspi_nand_dbg("read data finish\n");
++    }
++    else if (flags & SPI_XFER_DATA_OUT_STATE) {
++        /* send the data */
++        ftspi_nand_dbg("write len = %d, buf = 0x%x\n", len, dout);
++        ret = ftspi020_data_access(data, 0, (u8 *) dout, len);
++        if(ret)
++            return ret;        
++        ftspi_nand_dbg("write data finish\n");
++    }
++
++    /* check command complete */
++    if (flags & SPI_XFER_CHECK_CMD_COMPLETE)
++        ret = ftspi020_wait_cmd_complete(data);
++
++xfer_exit:
++    return ret;
++}
++
++/******************************************************************************
++ * workqueue
++ *****************************************************************************/
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++
++static int setup_dma(struct ftnandc023_nand_data *ctrl, int direct)
++{
++    struct dma_slave_config *common;
++
++    ctrl->dma_slave_config.id = -1;
++    ctrl->dma_slave_config.handshake = SPI020_REQ;      //enable
++
++    common = &ctrl->dma_slave_config.common;
++
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++    ctrl->dma_slave_config.src_size = FTDMAC020_BURST_SZ_4;     //64x4=256
++
++    if (direct == DMA_DEV_TO_MEM) {
++        ctrl->dma_slave_config.src_sel = AHBMASTER_R_SRC;
++        ctrl->dma_slave_config.dst_sel = AHBMASTER_R_DST;
++    } else {
++        ctrl->dma_slave_config.src_sel = AHBMASTER_W_SRC;
++        ctrl->dma_slave_config.dst_sel = AHBMASTER_W_DST;
++    }
++#else
++    common->dst_maxburst = 4;
++    common->src_maxburst = 4;
++#endif
++
++    if (direct == DMA_MEM_TO_DEV) {
++        common->src_addr = ctrl->mem_dmaaddr;
++        common->dst_addr = ctrl->nand_dmaaddr;
++    } else {
++        common->src_addr = ctrl->nand_dmaaddr;
++        common->dst_addr = ctrl->mem_dmaaddr;
++    }
++
++    /* SPI kernel maybe send len = 2011, so can't div 4 */
++    common->dst_addr_width = 1;
++    common->src_addr_width = 1;
++
++    common->direction = direct;
++
++    return dmaengine_slave_config(ctrl->dma_chan, common);      //step 2
++}
++
++static int spi020_dma_start(struct ftnandc023_nand_data *ctrl, size_t len, int direct)
++{
++    int ret;
++    enum dma_ctrl_flags flags;
++    struct dma_async_tx_descriptor *desc;
++
++    ret = setup_dma(ctrl, direct);
++    if (ret)
++        return ret;
++
++    flags =
++        DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++
++    desc = dmaengine_prep_slave_single(ctrl->dma_chan, (void *)ctrl->sg_dmabuf, len, direct, flags);    //step 3
++
++    if (!desc)
++        return -1;
++
++    desc->callback = ftspi020_dma_callback;
++    desc->callback_param = &ctrl;
++    ctrl->cookie = dmaengine_submit(desc);      //step 4
++    dma_async_issue_pending(ctrl->dma_chan);    //step 5
++
++    return 0;
++}
++
++static void ftspi020_dma_callback(void *param)
++{
++    //printk("<D>\n");
++
++    dma_trigger_flag = 1;
++    wake_up(&dma_queue);
++
++    return;
++}
++#endif
++
++/* direction: 1 is read, 0 is write */
++static int ftspi020_data_access(struct ftnandc023_nand_data *data, u8 direction, u8 * addr, u32 len)
++{
++    u32 *tmp;
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++    int ret = -1;
++#endif
++
++    tmp = (u32 *) addr;
++
++    if (direction) {
++        /* read direction */
++        if (len == IDCODE_LEN) {        // read ID
++            *tmp++ = *(volatile unsigned *)(data->chip.IO_ADDR_R);
++            return 0;
++        }
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++
++//printk("len=%d\n",len); 
++        ret = spi020_dma_start(data, len, DMA_DEV_TO_MEM);
++        if (ret < 0) {
++            printk(KERN_ERR "spi020 dma read fail\n");
++            return ret;
++        }
++
++        if(ftspi020_dma_wait())
++            return ret;
++
++        memcpy(addr, data->mem_dmabuf, len);
++#else
++        {
++            int i, j, tmp_size;
++            //printk("len = %d, one time %d, tmp = 0x%x\n",len,data->rxfifo_depth * 4, tmp);
++
++            tmp_size = len % (data->rxfifo_depth * 4);
++            //read 2048 bytes       
++            for (i = 0; i < (len / (data->rxfifo_depth * 4)); i++) {
++                ret = ftspi020_wait_rxfifo_ready(data->io_base);
++                if(ret)
++                    return ret;                
++                for (j = 0; j < data->rxfifo_depth; j++, tmp++) {
++                    *tmp = inl(data->io_base + 0x100);
++                    //printk("<%x>", *tmp);
++                }
++                //printk("\n");
++            }
++            //read 64 bytes
++            if (tmp_size) {
++                ret = ftspi020_wait_rxfifo_ready(data->io_base);
++                if(ret)
++                    return ret;                  
++                for (i = 0; i < (tmp_size / 4); i++, tmp++) {
++                    *tmp = inl(data->io_base + 0x100);
++                    //printk("<%x>", *tmp);
++                }
++            }
++            //printk("\n");
++        }
++#endif
++    } else {
++        /* write direction */
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++
++        memcpy(data->mem_dmabuf, addr, len);
++        ret = spi020_dma_start(data, len, DMA_MEM_TO_DEV);
++        if (ret < 0) {
++            printk(KERN_ERR "spi020 dma write fail\n");
++            return ret;
++        }
++        if(ftspi020_dma_wait())
++            return ret;
++#else
++        int i, j, tmp_size;
++
++        tmp_size = len % (data->txfifo_depth * 4);
++        //write 2048 bytes      
++        for (i = 0; i < (len / (data->txfifo_depth * 4)); i++) {
++            ret = ftspi020_wait_txfifo_ready(data->io_base);
++            if(ret)
++                return ret;
++            for (j = 0; j < data->txfifo_depth; j++, tmp++)
++                //*(volatile u32 *)(data->chip.IO_ADDR_R) = *tmp++;
++                outl(*tmp, data->io_base + 0x100);
++        }
++        //write 64 bytes
++        //*tmp = 0xFF;//good block//??? set bad block?
++        if (tmp_size) {
++            ret = ftspi020_wait_txfifo_ready(data->io_base);
++            if(ret)
++                return ret;
++            for (i = 0; i < (tmp_size / 4); i++, tmp++) {
++                outl(*tmp, data->io_base + 0x100);
++                //printk("<%x>", *tmp);
++            }
++        }
++#endif
++    }
++    return 0;
++}
++
++static inline struct common_spi_flash *mtd_to_common_spi_flash(struct mtd_info *mtd)
++{
++    return container_of(mtd, struct common_spi_flash, 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 common_spi_flash *flash, u8 ins_cmd)
++{
++    u8 val;
++    struct ftspi020_cmd cmd[2];
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    memset(&cmd[0], 0, sizeof(struct ftspi020_cmd));
++    cmd[0].ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd[0].write_en = FTSPI020_CMD3_READ;
++    cmd[0].read_status_en = FTSPI020_CMD3_RD_STS_EN;
++    cmd[0].read_status = FTSPI020_CMD3_STS_SW_READ;
++    cmd[0].ins_code = FTSPI020_CMD3_INSTR_CODE(ins_cmd);
++    cmd[0].flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    memset(&cmd[1], 0, sizeof(struct ftspi020_cmd));
++    cmd[1].rx_buf = &val;
++    cmd[1].data_cnt = 1;
++    cmd[1].read_status_en = FTSPI020_CMD3_RD_STS_EN;
++    cmd[1].read_status = FTSPI020_CMD3_STS_SW_READ;;
++    cmd[1].flags = FTSPI020_XFER_DATA_STATE;
++
++    return val;
++}
++
++/*
++ * Write status register 1 byte
++ * Returns negative if error occurred.
++ */
++static int write_sr(struct common_spi_flash *flash, u8 * val, u8 len)
++{
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WRSR);
++    cmd.tx_buf = val;
++    cmd.data_cnt = len;
++    cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    return 0;
++}
++
++static inline int change_4b(struct common_spi_flash *flash, u8 val)
++{
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    if (val)
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_EN4B);
++    else
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_EX4B);
++        
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    return 0;
++}
++
++/*
++ * Set write enable latch with Write Enable command.
++ * Returns negative if error occurred.
++ */
++static inline int write_enable(struct common_spi_flash *flash)
++{
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WREN);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    return 0;
++}
++
++/*
++ * Service routine to read status register until ready, or timeout occurs.
++ * Returns non-zero if error.
++ */
++static int wait_till_ready(struct common_spi_flash *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++) {
++        if ((sr = read_sr(flash, OPCODE_RDSR)) < 0)
++            break;
++        else if (!(sr & SR_WIP))
++            return 0;
++
++        /* REVISIT sometimes sleeping would be best */
++        ndelay(10);
++    }
++
++    return 1;
++}
++
++static inline int flash_set_quad_enable(struct common_spi_flash *flash)
++{
++    u8 sr[2];
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    /* Wait until finished previous write command. */
++    if (wait_till_ready(flash))
++        return 1;
++
++    if ((sr[0] = read_sr(flash, OPCODE_RDSR)) < 0)
++        return 1;
++
++    if (flash->flash_type == 1) {       //winbond
++        if ((sr[1] = read_sr(flash, OPCODE_RDSR2)) < 0)
++            return 1;
++        if (sr[1] & (1 << 1))   //has enable
++            return 0;
++    } else {
++        if (sr[0] & (1 << 6))   //has enable
++            return 0;
++    }
++    /* Send write enable, then erase commands. */
++    write_enable(flash);
++    
++    if (flash->flash_type == 1) //winbond
++        write_sr(flash, &sr[0], 2);
++    else
++        write_sr(flash, &sr[0], 1);
++
++    return 0;
++}
++
++static int partition_check(struct mtd_partition *partitions, struct ftnandc023_nand_data *data,
++                           int block_size)
++{
++    int i, num = 0, k, backup_partition_start = 0;
++    int j, A_begin, A_end, B_begin, B_end;
++    unsigned int backup_offset = 0, addr;
++
++    spi_nand_sys_header_t *sys_hdr;
++
++    sys_hdr = data->sys_hdr;
++
++    if (sys_hdr->image[0].size == 0) {
++        printk(KERN_WARNING "Warning...Not find partition message, use default setting\n");
++        partitions[0].name = "a";
++        partitions[0].offset = 0x140000;
++        partitions[0].size = 0x200000;
++
++        partitions[1].name = "b";
++        partitions[1].offset = 0x500000;
++        partitions[1].size = 0x200000;
++
++        num = 2;
++    } else {
++        for (k = 0; k < 2; k++) {
++            for (i = backup_partition_start; i < 10; i++) { // image array 10
++                if (sys_hdr->image[i].size == 0)
++                    continue;
++
++                partitions[num].offset = sys_hdr->image[i].addr + backup_offset;
++
++                partitions[num].size = sys_hdr->image[i].size;
++                partitions[num].name = sys_hdr->image[i].name;
++ 
++                //printk("MTD%d addr = 0x%x, size = 0x%x\n", num, (unsigned int)partitions[num].offset, (unsigned int)sys_hdr->image[i].size);     
++                if (sys_hdr->image[i].addr % block_size) {
++                    printk(KERN_WARNING "Warning... partition %d addr 0x%x not block alignment, one block = 0x%x\n",
++                           i, sys_hdr->image[i].addr, block_size);
++                    partitions[i].offset = BLOCK_ALIGN(sys_hdr->image[i].addr, block_size);
++                }
++                if (sys_hdr->image[i].size % block_size) {
++                    printk(KERN_WARNING "Warning... partition %d size 0x%x not block alignment, one block = 0x%x\n",
++                           i, sys_hdr->image[i].size, block_size);
++                    partitions[i].size = BLOCK_ALIGN(sys_hdr->image[i].size, block_size);
++                }
++                if(data->lookup_flag) {
++                	addr = sys_hdr->image[i].addr + partitions[i].size;
++                	if(addr > data->nand_parm.page_size * data->nand_parm.block_pg * data->block_limit)
++                		printk(KERN_WARNING "Warning... partition %d addr 0x%x overlap with reserve addr 0x%x to end\n", i, addr, data->nand_parm.page_size * data->nand_parm.block_pg * data->block_limit);
++            	}
++                num++;
++            }
++#ifdef MTD_backup
++            backup_offset = 0x3d80000;
++            backup_partition_start = 1;
++#else
++            break;
++#endif
++        }
++        
++        /* system header image */
++        partitions[num].offset = 0;
++        partitions[num].size = block_size;
++        partitions[num].name = "SYSHDR";        
++        num++;
++
++        /* nsboot image */
++        partitions[num].offset = sys_hdr->bootm_addr;
++        partitions[num].size = block_size;
++        partitions[num].name = "NSBOOT";        
++        num++;
++
++        for (i = 0; i < ARRAY_SIZE(ftnandc023_partition_info); i++)
++            ftspi_nand_dbg("partation %d addr = 0x%x, size = 0x%x, name = %s\n", i,
++                           sys_hdr->image[i].addr, sys_hdr->image[i].size, sys_hdr->image[i].name);
++
++        for (i = 0; i < (num - 2); i++) {
++            if (partitions[i + 1].offset >= partitions[i].offset)
++                if (partitions[i + 1].offset - partitions[i].offset < (2 * block_size)) {
++                    printk
++                        (KERN_WARNING "Warning... Block reserve for bad issue between partition %d with %d is not enough\n",
++                         i, i + 1);
++                    printk(KERN_INFO "partition %d addr = 0x%x, %d addr = 0x%x\n", i,
++                           (u32) partitions[i].offset, i + 1, (u32) partitions[i + 1].offset);
++                }
++        }
++    }
++
++    //overlap check
++    for (i = 0; i < (num - 3); i++) {
++        A_begin = partitions[i].offset;
++        A_end = A_begin + partitions[i].size;
++        //printk("A %x,%x\n",A_begin,A_end);
++
++        for (j = (i + 1); j < num; j++) {
++            B_begin = partitions[j].offset;
++            B_end = B_begin + partitions[j].size;
++            //printk("B %x,%x\n",B_begin,B_end);
++
++            /* A_end between B_end and B_begin */
++            if ((B_end >= A_end) && (A_end > B_begin))
++                goto check_fail;
++            /* A_begin between B_end and B_begin */
++            if ((B_end > A_begin) && (A_begin >= B_begin))
++                goto check_fail;
++            /* B between A */
++            if ((A_end >= B_end) && (B_begin >= A_begin))
++                goto check_fail;
++        }
++    }
++
++    return num;
++check_fail:
++    printk(KERN_WARNING "Warning ============> partition %d overlap with %d\n", i, j);
++    return num;
++}
++
++/* low enable write protect, high disable write protect */
++static void write_protect(int mode)
++{
++#ifdef CONFIG_GPIO_WP
++    if (mode)
++        gpio_direction_output(GPIO_PIN, 0);
++    else
++        gpio_direction_output(GPIO_PIN, 1);
++#endif
++}
++
++int spi020_flash_cmd(struct ftnandc023_nand_data *data, uint8_t * u8_cmd, void *response,
++                     size_t len)
++{
++    int ret;
++
++    ret = spi_xfer(data, len, u8_cmd, NULL, SPI_XFER_CMD_STATE | SPI_XFER_CHECK_CMD_COMPLETE);
++    if (ret) {
++        printk(KERN_ERR "SF: Failed to send command %02x: %d\n", u8_cmd[0], ret);
++        return ret;
++    }
++
++    if (len && response != NULL) {
++        ret = spi_xfer(data, len, NULL, response, SPI_XFER_DATA_IN_STATE);
++        if (ret) {
++            printk(KERN_ERR "SF: Failed to read response (%zu bytes): %d\n", len, ret);
++        }
++    } else if ((len && response == NULL) || (!len && response != NULL)) {
++        printk
++            (KERN_ERR "SF: Failed to read response due to the mismatch of len and response (%zu bytes): %d\n",
++             len, ret);
++    }
++
++    return ret;
++}
++
++/* Wait until BUSY bit clear
++ */
++static int flash_wait_busy_ready(struct ftnandc023_nand_data *data)
++{
++    unsigned long timeo = jiffies;
++    u8 rd_sts_cmd[1];
++    u8 status = 0xFF;
++
++    rd_sts_cmd[0] = COMMAND_GET_FEATURES;
++    rd_sts_cmd[1] = 0xC0;
++
++    timeo += (10 * HZ);
++    while (time_before(jiffies, timeo)) {
++        if (spi020_flash_cmd(data, rd_sts_cmd, NULL, 0)) {
++            printk(KERN_ERR "Failed to check status!\n");
++            break;
++        }
++
++        status = ftspi020_read_status(data->io_base);
++        if (!(status & FLASH_STS_BUSY))
++            break;
++    };
++    if (status & FLASH_STS_BUSY) {
++        printk(KERN_ERR "Wait bus busy timeout!\n");
++        return 0xFF;
++    } else {
++        ftspi_nand_dbg("get feature = 0x%x\n", status);
++        //printk("<get feature = 0x%x>", status);
++    }
++
++    return status;
++}
++
++static int ftnandc023_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++    ftspi_nand_dbg("%s\n", __FUNCTION__);
++    return cmdfunc_status;
++}
++
++static int ftnandc023_available_oob(struct ftnandc023_nand_data *data)
++{
++    int ret = 0;
++
++    ret = data->chip.ecc.layout->oobfree[0].length * 4;
++
++        /*----------------------------------------------------------
++	 * YAFFS require 16 bytes OOB without ECC, 28 bytes with
++	 * ECC enable.
++	 * BBT require 5 bytes for Bad Block Table marker.
++	 */
++#ifdef CONFIG_YAFFS_FS
++    if (ret >= 16) {
++        printk(KERN_INFO "NAND(YAFFS): avaliable OOB is %d byte.\n", ret);
++    } else {
++        printk(KERN_INFO
++               "NAND: Not enough OOB:%d bytes(YAFFS requires 16 bytes without software ECC, "
++               "28 bytes with ECC enable), try to reduce ECC correction bits.\n", ret);
++    }
++#else
++    printk(KERN_INFO "Avaliable OOB is %d byte.\n", ret);
++#endif
++    return ret;
++}
++
++static void nand_read_buffer(struct ftnandc023_nand_data *data, int cmd, u_char * buf, int len)
++{
++    if (cmd == NAND_CMD_READID) {
++        ftspi_nand_dbg("read_buffer ID\n");
++        ftspi020_data_access(data, 1, buf, IDCODE_LEN);
++        //*(u32 *)buf=0xF1C8F1C8;
++    }
++}
++
++static uint8_t ftnandc023_read_byte(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    uint8_t b = 0xFF;
++
++    ftspi_nand_dbg("%s, cmd = 0x%x\n", __FUNCTION__, data->cur_cmd);
++
++    switch (data->cur_cmd) {
++    case NAND_CMD_READID:
++        if (read_id_time == 0) {
++            //buf = *(u32 *)(data->chip.IO_ADDR_R)
++
++            nand_read_buffer(data, NAND_CMD_READID, idcode, IDCODE_LEN);
++            ftspi_nand_dbg("ID = 0x%x,0x%x,0x%x,0x%x\n", idcode[0], idcode[1], idcode[2],
++                           idcode[3]);
++
++            read_id_time = 1;
++        }
++        b = idcode[ID_point++];
++        break;
++    case NAND_CMD_STATUS:
++        /* fail to return 0 */
++        ftspi_nand_dbg("NAND_CMD_STATUS\n");    //not need to implement, r/w/e already do it.
++        break;
++    }
++    
++    return b;
++}
++
++int log_to_phy(struct ftnandc023_nand_data *data, int page_addr)
++{
++    int log_block_num, phy_block_num, ren, new_page_addr;
++    
++    log_block_num = page_addr / data->nand_parm.block_pg;
++    ren = page_addr % data->nand_parm.block_pg;
++
++    /* read system header and lookup tab */
++    if(log_block_num == 0)
++        return page_addr;
++
++    phy_block_num = data->lookup_table->physical[log_block_num];
++
++    if(phy_block_num > 0x8000) {
++        printk(KERN_WARNING "Block %d not be mapping\n", log_block_num);
++        return 0x0FFFFFFF;
++    } else if(phy_block_num == 0xFFFF) {
++        printk(KERN_WARNING "Block %d is bad\n", log_block_num);
++        return 0x0FFFFFFF;
++    }
++
++    new_page_addr = phy_block_num * data->nand_parm.block_pg + ren;
++    
++    ftspi_nand_dbg("page in = %d, log_b = %d, phy_b = %d, page out = %d\n", page_addr, log_block_num, phy_block_num, new_page_addr);
++    return new_page_addr;
++}
++
++static int ftnandc023_nand_read_oob_lp(struct mtd_info *mtd, u_char * buf)
++{
++    int ret, new_page;    
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("%s\n", __FUNCTION__);
++
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, data->page_addr);
++        ftspi_nand_dbg("read_oob page num logical = %d, physical = %d\n", data->page_addr, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to write bad block\n");
++            return -1;
++        }
++        data->page_addr = new_page;
++    }
++    else
++        data->page_addr = calc_new_page(mtd, data->page_addr);
++
++	ret = spi_flash_cmd_read_fast(data, data->page_addr, mtd->oobsize, buf);
++
++    if(ret) {
++        cmdfunc_status = NAND_STATUS_FAIL;
++        return -EIO;
++    } else {
++        cmdfunc_status = NAND_STATUS_READY;
++        return 0;
++    }
++}
++
++static int ftnandc023_nand_read_oob_sp(struct mtd_info *mtd, u_char * buf)
++{
++    printk("%s: not implement.\n", __FUNCTION__);
++    return 0;
++}
++
++static int ftnandc023_nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("read oob page = 0x%x\n", page);
++    data->page_addr = page;
++
++    return data->read_oob(mtd, chip->oob_poi);
++}
++
++static int spi020_flash_cmd_write(struct ftnandc023_nand_data *spi, u8 * u8_cmd, const void *data, int data_len)
++{
++    int ret;
++
++    ret = spi_xfer(spi, data_len, u8_cmd, NULL, SPI_XFER_CMD_STATE);
++    if (ret) {
++        printk(KERN_ERR "SF: Failed to send command %02x: %d\n", u8_cmd[0], ret);
++        return ret;
++    } else if (data_len != 0) {
++        ret = spi_xfer(spi, data_len, data, NULL, SPI_XFER_DATA_OUT_STATE | SPI_XFER_CHECK_CMD_COMPLETE);       //SPI_XFER_CHECK_CMD_COMPLETE);
++        if (ret) {
++            printk(KERN_ERR "SF: Failed to write data (%zu bytes): %d\n", data_len, ret);
++        }
++    }
++
++    return ret;
++}
++
++static int spi020_flash_cmd_read(struct ftnandc023_nand_data *spi, uint8_t * u8_cmd, void *data, int data_len)
++{
++    int ret;
++
++    ret = spi_xfer(spi, data_len, u8_cmd, NULL, SPI_XFER_CMD_STATE);
++//printk("spi020_flash_cmd_read cmd=0x%x,len=0x%x\n",*u8_cmd,data_len);    
++    if (ret) {
++        printk(KERN_ERR "SF: Failed to send command %02x: %d\n", u8_cmd[0], ret);
++    } else if (data_len != 0) {
++        //printk("A0\n");
++        ret =
++            spi_xfer(spi, data_len, NULL, data,
++                     SPI_XFER_DATA_IN_STATE | SPI_XFER_CHECK_CMD_COMPLETE);
++        if (ret) {
++            printk(KERN_ERR "SF: Failed to read data (%zu bytes): %d\n", data_len, ret);
++        }
++    }
++
++    return ret;
++}
++
++static int spi_flash_read_write(struct ftnandc023_nand_data *spi,
++                                const u8 * cmd, size_t cmd_len,
++                                const u8 * data_out, u8 * data_in, size_t data_len)
++{
++    unsigned long flags;
++    int ret;
++
++    if (data_len == 0)
++        flags = (SPI_XFER_CMD_STATE | SPI_XFER_CHECK_CMD_COMPLETE);     //(SPI_XFER_END | SPI_XFER_CHECK_CMD_COMPLETE);
++
++    ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
++    
++    if (ret) {
++        printk(KERN_ERR "SF: Failed to send command (%zu bytes): %d\n", cmd_len, ret);
++    } else if (data_len != 0) {
++        if (data_in == NULL) {  // write
++            if (data_len % 4) {
++                if (*cmd != COMMAND_WRITE_STATUS)
++                    printk(KERN_WARNING "data len %x not 4 times\n", data_len);
++                return ret;
++            }
++        }
++        ret = spi_xfer(spi, data_len * 8, data_out, data_in, SPI_XFER_CHECK_CMD_COMPLETE);      //SPI_XFER_END, 0);
++        if (ret)
++            printk(KERN_ERR "SF: Failed to transfer %zu bytes of data: %d\n", data_len, ret);
++    }
++
++    return ret;
++}
++
++static int spi_flash_cmd(struct ftnandc023_nand_data *spi, u8 * cmd, void *response, size_t len)
++{
++    return spi_flash_read_write(spi, cmd, 1, NULL, response, len);
++}
++
++static int spi_flash_cmd_read_fast(struct ftnandc023_nand_data *data, u32 offset, size_t len, u8 *buf)
++{
++    int ret;
++    u8 u8_rd_cmd[5];
++
++    /* send PAGE READ command first for SPI NAND */
++    //flash_wait_busy_ready(flash);
++
++    memset(u8_rd_cmd, 0, 5);
++    u8_rd_cmd[0] = COMMAND_PAGE_READ;
++    /* assign row address */
++    u8_rd_cmd[1] = offset & 0xFF;
++    u8_rd_cmd[2] = ((offset & 0xFF00) >> 8);
++    u8_rd_cmd[3] = ((offset & 0xFF0000) >> 16);
++
++    ret = spi_flash_cmd(data, u8_rd_cmd, NULL, 0);
++    if (ret) {
++        printk(KERN_ERR "Read fast fail\n");
++        return ret;
++    }
++    
++    /* check if the flash is busy */
++    if ((flash_wait_busy_ready(data) & FLASH_NAND_R_FIELD ) == FLASH_NAND_R_FAIL) {
++        printk(KERN_ERR "read offset = 0x%x ECC fail\n", offset * data->nand_parm.page_size);
++#if 0//debug
++        if(data->nand_parm.spare_size == len)
++            *buf = 0xFF;
++        return 0;
++#else         
++        return 1;
++#endif        
++    }
++
++    memset(u8_rd_cmd, 0, 5);
++
++#ifdef CONFIG_SPI_QUAD
++    flash_set_quad_enable(data, 1);
++    u8_rd_cmd[0] = COMMAND_FAST_READ_QUAD_IO;
++#else
++	if(idcode[0] == 0x9B)        //ATO not have COMMAND_FAST_READ_DUAL mode
++		u8_rd_cmd[0] = COMMAND_FAST_READ;
++   	else
++		u8_rd_cmd[0] = COMMAND_FAST_READ_DUAL;
++#endif
++
++    /* assign column address */
++    if (len == data->nand_parm.spare_size) {
++        u8_rd_cmd[1] = data->nand_parm.page_size & 0xFF;
++        u8_rd_cmd[2] = ((data->nand_parm.page_size & 0xFF00) >> 8);
++    } else {
++        u8_rd_cmd[1] = 0x00;
++        u8_rd_cmd[2] = 0x00;
++    }    
++
++    ret = spi020_flash_cmd_read(data, u8_rd_cmd, buf, len);
++
++    return ret;
++}
++
++/* 0 is good, 1 is bad */
++static int check_bbt(struct mtd_info *mtd, loff_t offs)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    unsigned int *bi_table = (unsigned int *)data->bi_table;
++    int quotient, remainder, blk_id, result, ret = 0;
++
++    if(!data->lookup_flag) {
++        blk_id = offs >> chip->bbt_erase_shift;
++        quotient = blk_id >> 5;
++        remainder = blk_id & 0x1F;
++        result = (bi_table[quotient] >> remainder) & 0x1;
++        
++        if (result != 1)
++            ret = 1;
++    }
++    return ret;
++}
++
++static int calc_new_page(struct mtd_info *mtd, int page_addr)
++{
++    unsigned int start_addr, end_addr, check_addr, tmp_addr, bad_num = 0;
++    unsigned int block_page_num = mtd->erasesize / mtd->writesize;
++    struct nand_chip *chip = mtd->priv;
++
++    if (root_mtd_num != 0xFFFF) {// is squashfs
++        start_addr = ftnandc023_partition_info[root_mtd_num].offset;
++        end_addr = ftnandc023_partition_info[root_mtd_num].size + start_addr;
++        //printk("squash start addr = 0x%x, end addr = 0x%x\n", start_addr, end_addr); 
++
++        check_addr = page_addr * mtd->writesize;
++        
++        if((check_addr >= start_addr) && (check_addr < end_addr)) {
++            tmp_addr = start_addr;
++            
++            /* have bad block between start to here? */
++            while (check_addr >= tmp_addr) {
++                if(check_bbt(mtd, (loff_t) tmp_addr) != 0) {
++                    bad_num++;
++                    //printk("<ba=0x%x>", tmp_addr);
++                }
++
++                tmp_addr += (0x1 << chip->bbt_erase_shift);
++            }
++            
++            /* move n good block */
++            if(bad_num) {
++                //printk("<br0x%x,bad=%d>",page_addr,bad_num);
++                while(bad_num) {
++                    //printk("<tmp_page = 0x%x>", tmp_addr / mtd->writesize);
++                    if(check_bbt(mtd, (loff_t) tmp_addr) == 0)
++                        bad_num--;
++    
++                    tmp_addr += (0x1 << chip->bbt_erase_shift);
++                    page_addr += block_page_num;                    
++                }
++                //printk("<a=0x%x>\n",page_addr);
++            }                        
++        } else {
++                while(check_bbt(mtd, (loff_t) (page_addr * mtd->writesize)))
++                    page_addr += block_page_num;
++        }
++    }
++
++    return page_addr;
++}
++
++static int ftnandc023_nand_read_page_lp(struct mtd_info *mtd, u_char * buf)
++{
++    int ret, new_page;
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("r:page = 0x%x, size = %d\n", data->page_addr, mtd->writesize);
++
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, data->page_addr);
++        ftspi_nand_dbg("read_page page num logical = %d, physical = %d\n", data->page_addr, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to write bad block\n");
++            return -1;
++        }
++        data->page_addr = new_page;
++    }
++    else
++        data->page_addr = calc_new_page(mtd, data->page_addr);
++    
++    //spi_flash_cmd_read_fast(data, data->page_addr, data_len, data->chip.buffers->databuf);
++    //memcpy(buf, data->chip.buffers->databuf, mtd->writesize);
++    
++    /* nand_do_read_ops will reserve data->chip.buffers->databuf data last time, can't be overlap */
++    ret = spi_flash_cmd_read_fast(data, data->page_addr, mtd->writesize, buf);
++    if(ret) {
++        cmdfunc_status = NAND_STATUS_FAIL;
++        return -EIO;
++    } else {
++        cmdfunc_status = NAND_STATUS_READY;
++        return 0;
++    }
++}
++
++static int ftnandc023_nand_read_page_sp(struct mtd_info *mtd, u_char * buf)
++{
++    printk("%s: not implement.\n", __FUNCTION__);
++    return 0;
++}
++
++static int ftnandc023_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf,
++                                     int page)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("%s, page = 0x%x\n", __FUNCTION__, page);
++    data->buf = (u32 *) buf;
++    data->page_addr = page;
++
++    return data->read_page(mtd, buf);
++}
++
++static int spi_flash_cmd_write(struct ftnandc023_nand_data *data, u32 offset, size_t len,
++                        const uint8_t * buf)
++{
++    int ret = 1;
++    u8 u8_wr_en_cmd[1], u8_wr_cmd[5];
++    u8 *u8_buf = (u8 *) buf;
++
++    /* check if the flash is busy */
++    //flash_wait_busy_ready(flash);
++
++#ifdef CONFIG_SPI_QUAD
++    ret = flash_set_quad_enable(data, 1);
++    if (ret)
++        goto prog0_exit;
++#endif
++
++    u8_wr_en_cmd[0] = COMMAND_WRITE_ENABLE;
++    if (spi020_flash_cmd(data, u8_wr_en_cmd, NULL, 0)) {
++        printk(KERN_ERR "COMMAND_WRITE_ENABLE fail\n");
++        goto prog_exit;
++    }
++
++    /* send PROGRAM LOAD command for SPI NAND */
++    u8_wr_cmd[0] = COMMAND_PROGRAM_LOAD;
++    /* assign column address */
++    if (len == data->nand_parm.spare_size) {
++        u8_wr_cmd[1] = data->nand_parm.page_size & 0xFF;
++        u8_wr_cmd[2] = ((data->nand_parm.page_size & 0xFF00) >> 8);
++    } else {
++        u8_wr_cmd[1] = 0x00;
++        u8_wr_cmd[2] = 0x00;
++    }
++
++    ret = spi020_flash_cmd_write(data, u8_wr_cmd, u8_buf, len);
++    if (ret) {
++        printk(KERN_ERR "COMMAND_WRITE_ENABLE fail\n");
++        goto prog_exit;
++    }
++    //ftspi020_wait_cmd_complete(data);
++
++#ifdef CONFIG_SPI_QUAD
++    //only for QUAD_PROGRAM
++    if (data->chip_type)
++        u8_wr_cmd[0] = COMMAND_WINBOND_QUAD_WRITE_PAGE;
++    else
++        u8_wr_cmd[0] = COMMAND_QUAD_WRITE_PAGE;
++#else
++    u8_wr_cmd[0] = COMMAND_PROGRAM_EXECUTE;
++#endif
++
++    /* assign row address */
++    u8_wr_cmd[1] = offset & 0xFF;
++    u8_wr_cmd[2] = ((offset & 0xFF00) >> 8);
++    u8_wr_cmd[3] = ((offset & 0xFF0000) >> 16);
++
++    if (spi020_flash_cmd(data, u8_wr_cmd, NULL, 0)) {
++        printk(KERN_ERR "COMMAND_PROGRAM_EXECUTE fail\n");
++        goto prog_exit;
++    }
++
++    if (flash_wait_busy_ready(data) & FLASH_NAND_P_FAIL) {
++        printk(KERN_ERR "program result fail\n");
++        ret = 1;
++    } else
++        ret = 0;       
++        
++prog_exit:
++    return ret;
++}
++
++static int ftnandc023_nand_write_oob_lp(struct mtd_info *mtd, const uint8_t * buf, int len)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    int ret, new_page;
++
++    ftspi_nand_dbg("oob w:page = 0x%x, size = %d, data = 0x%x\n", data->page_addr, len, *buf);
++
++    //memcpy(data->chip.buffers->databuf + FLASH_NAND_PAGE_SZ, buf, mtd->oobsize);
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, data->page_addr);
++        ftspi_nand_dbg("write_oob page num logical = %d, physical = %d\n", data->page_addr, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to write bad block\n");
++            return -1;
++        }
++        data->page_addr = new_page;
++    }
++
++	ret = spi_flash_cmd_write(data, data->page_addr, mtd->oobsize, buf);	
++    if(ret) {
++        cmdfunc_status = NAND_STATUS_FAIL;
++        return -EIO;
++    } else {
++        cmdfunc_status = NAND_STATUS_READY;
++        return 0;
++    }
++}
++
++static int ftnandc023_nand_write_oob_sp(struct mtd_info *mtd, const u_char * buf, int len)
++{
++    printk("%s: not implement.\n", __FUNCTION__);
++    return 0;
++}
++
++#if 0
++static int ftnandc023_nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    printk("write oob page = 0x%x\n", page);
++    data->page_addr = page;
++
++    memcpy(data->chip.buffers->databuf + FLASH_NAND_PAGE_SZ, chip->oob_poi, mtd->oobsize);
++    data->write_page(mtd, data->chip.buffers->databuf);
++
++    printk("ddw = 0x%x, 0x%x, 0x%x\n", *(u32 *) chip->oob_poi, *(u32 *) (chip->oob_poi + 1),
++           *(u32 *) (chip->oob_poi + 2));
++    return true;                //data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++}
++#else
++static int ftnandc023_nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++    //u32 *tmp = (u32 *)chip->oob_poi;
++
++    ftspi_nand_dbg("write oob page = 0x%x\n", page);
++    data->page_addr = page;
++
++    //printk("ddw = 0x%x, 0x%x, 0x%x\n", *tmp, *(tmp + 1), *(tmp + 2));
++    return data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++}
++#endif
++
++static int ftnandc023_nand_write_page_lp(struct mtd_info *mtd, const uint8_t * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    int ret, new_page;
++
++    ftspi_nand_dbg("lp w:page = 0x%x, size = %d, data->column = %d,0x%x\n", data->page_addr,
++                   mtd->writesize, data->column, *buf);
++
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, data->page_addr);
++        ftspi_nand_dbg("write_page page num logical = %d, physical = %d\n", data->page_addr, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to write bad block\n");
++            return -1;
++        }
++        data->page_addr = new_page;
++    }
++  
++    ret = spi_flash_cmd_write(data, data->page_addr, mtd->writesize, buf);    
++    if(ret) {
++        cmdfunc_status = NAND_STATUS_FAIL;
++        return -EIO;
++    } else {
++        cmdfunc_status = NAND_STATUS_READY;
++        return 0;
++    }
++}
++
++static int ftnandc023_nand_write_page_sp(struct mtd_info *mtd, const uint8_t * buf)
++{
++    printk("%s: not implement.\n", __FUNCTION__);
++    return 0;
++}
++
++static int ftnandc023_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++                                      const uint8_t * buf, int page, int cached, int raw)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc023_nand_data *data = p->priv;
++    int status = 0;
++
++    ftspi_nand_dbg("%s, page = 0x%x\n", __FUNCTION__, page);
++    data->page_addr = page;
++
++    status = data->write_page(mtd, buf);
++
++    return status;
++}
++
++static void ftnandc023_nand_write_page_lowlevel(struct mtd_info *mtd,
++                                                struct nand_chip *chip, const uint8_t * buf)
++{
++}
++
++/* offset: byte offset
++ * len: how many bytes.
++ */
++static int spi_flash_cmd_erase(struct ftnandc023_nand_data *data, u32 offset)
++{
++    int ret = 1, new_page;
++    u8 u8_er_cmd[5];
++
++    /* check if the flash is busy */
++    //flash_wait_busy_ready(data);
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, offset);
++        ftspi_nand_dbg("erase page num logical = %d, physical = %d\n", offset, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to erase bad block\n");
++            return 1;
++        }
++        offset = new_page;
++    }
++
++    u8_er_cmd[0] = COMMAND_WRITE_ENABLE;
++    ret = spi020_flash_cmd(data, u8_er_cmd, NULL, 0);
++    if (ret) {
++        printk(KERN_ERR "cmd_erase write enable fail\n");
++        return ret;
++    }
++
++    u8_er_cmd[0] = COMMAND_ERASE_128K_BLOCK;
++    u8_er_cmd[1] = offset & 0xFF;
++    u8_er_cmd[2] = ((offset & 0xFF00) >> 8);
++    u8_er_cmd[3] = ((offset & 0xFF0000) >> 16);
++
++    ret = spi020_flash_cmd(data, u8_er_cmd, NULL, 0);
++    if (ret) {
++        printk(KERN_ERR "cmd_erase erase fail\n");
++        return ret;
++    }
++
++    /* check if the flash is busy */
++    if (flash_wait_busy_ready(data) & FLASH_NAND_E_FAIL) {
++        printk(KERN_ERR "erase result fail\n");
++        ret = 1;
++    } else
++        ret = 0;        
++
++    return ret;
++}
++
++static void ftnandc023_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
++                                    int column, int page_addr)
++{
++    int ret;
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("%s, cmd = 0x%x\n", __func__, command);
++
++    data->cur_cmd = command;
++
++    switch (command) {
++    case NAND_CMD_READID:
++        {
++            ftspi020_cmd_t spi_cmd;
++
++            read_id_time = 0;
++            ID_point = 0;
++            ftspi020_setup_cmdq(data, &spi_cmd, COMMAND_READ_ID, FTSPI020_CMD1_OP_CODE_1_BYTE,
++                                FTSPI020_CMD3_READ, FTSPI020_CMD3_SERIAL_MODE, IDCODE_LEN);
++            ftspi020_wait_cmd_complete(data);
++        }
++        break;
++    case NAND_CMD_RESET:
++        break;
++    case NAND_CMD_STATUS:
++        break;
++    case NAND_CMD_ERASE1:
++        write_protect(0);
++        //DBGLEVEL2(ftnandc023_dbg("erase page: 0x%x\n", data->page_addr));
++        ftspi_nand_dbg("erase sector: 0x%x\n", page_addr);
++        ret = spi_flash_cmd_erase(data, page_addr);
++        if(ret)
++            cmdfunc_status = NAND_STATUS_FAIL;
++        else
++            cmdfunc_status = NAND_STATUS_READY;
++
++        break;
++    case NAND_CMD_ERASE2:
++    case NAND_CMD_PAGEPROG:
++    case NAND_CMD_SEQIN:
++        break;
++    }
++}
++
++/*
++ * Currently, we have pin mux with SD card
++ */
++static void ftnandc023_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc023_nand_data *data = p->priv;
++    int chn = 0;
++
++    //DBGLEVEL2(ftnandc023_dbg("chip = %d, ", chip));
++    if (data->scan_state != 1) {
++        while (chip != -1) {
++            if (chip < data->valid_chip[chn]) {
++                break;
++            } else {
++                chip = chip - data->valid_chip[chn];
++                chn++;
++            }
++        }
++        data->cur_chan = chn;
++    }
++#ifdef CONFIG_FTNANDC023_HYNIX_HY27US08561A
++    if (chip == 1)
++        data->sel_chip = 2;
++    else if (chip == 2)
++        data->sel_chip = 1;
++    else
++        data->sel_chip = chip;
++#else
++    data->sel_chip = chip;
++#endif
++
++    //DBGLEVEL2(ftnandc023_dbg("==>chan = %d, ce = %d\n", data->cur_chan, data->sel_chip));
++}
++
++/*
++ * Probe for the NAND device.
++ */
++static int __devinit ftspi020_nand_probe(struct platform_device *pdev)
++{
++    struct ftnandc023_nand_data *data;
++    struct mtd_partition *partitions;
++    int res, chipnum, size;
++    static struct resource *irq;
++    int i;
++    int partitions_num;
++
++    res = chipnum = size = 0;
++    /* Allocate memory for the device structure (and zero it) */
++    data = kzalloc(sizeof(struct ftnandc023_nand_data), GFP_KERNEL);
++    if (!data) {
++        dev_err(&pdev->dev, "failed to allocate device structure.\n");
++        res = -ENOMEM;
++        goto out;
++    }
++
++    data->io_base = ioremap_nocache(pdev->resource[0].start,
++                                    pdev->resource[0].end - pdev->resource[0].start + 1);
++    printk(KERN_INFO "SPI-NAND reg mapping to addr = 0x%x, phy = 0x%x\n", (u32) data->io_base,
++           (u32) pdev->resource[0].start);
++    if (data->io_base == NULL) {
++        dev_err(&pdev->dev, "ioremap failed for register.\n");
++        res = -EIO;
++        goto out_free_data;
++    }
++    
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    init_waitqueue_head(&dma_queue);
++    data->nand_dmaaddr = pdev->resource[0].start + 0x100;
++#endif
++
++    data->chip.IO_ADDR_R = data->io_base + 0x100;
++    printk(KERN_INFO "NAND data port mapping to addr = 0x%x\n", (u32) data->chip.IO_ADDR_R);
++
++    irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++    if (!irq) {
++        printk(KERN_ERR "no irq resource\n");
++        res = -ENODEV;
++        goto out_free_data;
++    }
++
++    setup_clk(data->io_base);
++
++    /* Currently, it is fixed in LEGACY_LARGE
++     */
++    legacy = LEGACY_LARGE;
++	data->flash_type = 0;
++    data->large_page = 1;
++    data->rxfifo_depth = ftspi020_rxfifo_depth(data->io_base);
++    data->txfifo_depth = ftspi020_txfifo_depth(data->io_base);
++    data->chip.priv = data;
++    data->mtd.priv = &data->chip;
++    data->mtd.owner = THIS_MODULE;
++    data->mtd.name = pdev->dev.init_name;
++    data->dev = &pdev->dev;
++    data->chip.IO_ADDR_W = data->chip.IO_ADDR_R;
++    data->chip.select_chip = ftnandc023_nand_select_chip;
++    data->chip.cmdfunc = ftnandc023_nand_cmdfunc;
++    data->chip.read_byte = ftnandc023_read_byte;
++    data->chip.write_page = ftnandc023_nand_write_page;
++    data->chip.waitfunc = ftnandc023_nand_wait;
++    data->chip.block_markbad = ftnandc023v2_block_markbad;
++    data->chip.chip_delay = 0;
++    //data->chip.options = NAND_BBT_USE_FLASH | NAND_NO_SUBPAGE_WRITE | NAND_OWN_BUFFERS;
++    data->chip.options = NAND_NO_SUBPAGE_WRITE | NAND_OWN_BUFFERS;      /* remove NAND_BBT_USE_FLASH */
++
++    platform_set_drvdata(pdev, data);
++
++    data->scan_state = 1;
++    
++    /* read ID disable DMA */
++    ftspi020_dma_disable(data->io_base);
++    
++    /* Scan to find existance of the device */
++    for (i = startchn; i < MAX_CHANNEL; i++) {
++        printk(KERN_INFO "NAND: Scan Channel %d...\n", i);
++        data->cur_chan = i;
++        if (!nand_scan_ident(&data->mtd, MAX_CE, NULL)) {
++            if ((0xFFFFFFFF - size) > (data->mtd.size)
++                && ((chipnum + data->chip.numchips) <= NAND_MAX_CHIPS)) {
++                data->valid_chip[i] = data->chip.numchips;
++                chipnum += data->chip.numchips;
++                size += (chipnum * data->chip.chipsize);
++            } else {
++                printk(KERN_INFO "Can not accept more flash chips.\n");
++                break;
++            }
++        }
++    }
++    printk(KERN_INFO "NAND: Scan Channel finish, chipnum = %d\n", chipnum);
++    if (chipnum == 0) {
++        res = -ENXIO;
++        goto out_unset_drv;
++    }
++    
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++    ftspi020_dma_enable(data->io_base);
++#endif
++
++    data->chip.numchips = chipnum;
++    data->mtd.size = size;
++    data->scan_state = 0;
++
++	//data->ecc_type = FLASH_NAND_R_ECC_LIMIT;
++    if(idcode[1] == 0xF1) {	//GD5F1GQ4UA
++        data->chip.ecc.layout = &nand_1_hw_eccoob;
++    } else if(((idcode[0] == 0xC8) && (idcode[1] == 0x20)) || ((idcode[0] == 0xC8) && (idcode[1] == 0x21))){
++        data->chip.ecc.layout = &nand_2_hw_eccoob;
++    } else if((idcode[0] == 0xEF) || (idcode[0] == 0xC2)) {	//MXIC & Winbond
++        data->chip.ecc.layout = &nand_3_hw_eccoob;
++    } else if(idcode[0] == 0x91) {	//HY
++        data->chip.ecc.layout = &nand_4_hw_eccoob;
++    } else {	//GD5FxGQ4UB
++        data->chip.ecc.layout = &nand_0_hw_eccoob;
++        //data->ecc_type = FLASH_NAND_GD_R_FAIL;
++    }
++    data->chip.bbt_td = &ftnandc023_bbt_main_descr;
++    data->chip.bbt_md = &ftnandc023_bbt_mirror_descr;
++    data->chip.badblock_pattern = &ftnandc023_largepage_flashbased;
++
++    data->ce = 0;               //???
++
++    data->chip.ecc.mode = NAND_ECC_HW;
++
++    data->chip.ecc.size = data->mtd.writesize;
++    data->chip.ecc.bytes = 0;
++    data->chip.ecc.read_page = ftnandc023_nand_read_page;
++    data->chip.ecc.write_page = ftnandc023_nand_write_page_lowlevel;
++    data->chip.ecc.read_oob = ftnandc023_nand_read_oob_std;
++    data->chip.ecc.write_oob = ftnandc023_nand_write_oob_std;
++    data->chip.ecc.read_page_raw = ftnandc023_nand_read_page;
++
++    if (data->large_page) {
++        data->read_page = ftnandc023_nand_read_page_lp;
++        data->write_page = ftnandc023_nand_write_page_lp;
++        data->read_oob = ftnandc023_nand_read_oob_lp;
++        data->write_oob = ftnandc023_nand_write_oob_lp;
++    } else {
++        data->read_page = ftnandc023_nand_read_page_sp;
++        data->write_page = ftnandc023_nand_write_page_sp;
++        data->read_oob = ftnandc023_nand_read_oob_sp;
++        data->write_oob = ftnandc023_nand_write_oob_sp;
++    }
++    
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    dma_cap_set(DMA_SLAVE, data->cap_mask);
++
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++    printk(KERN_INFO "use AHB DMA mode\n");
++    {
++        struct ftdmac020_dma_slave slave;
++        memset(&slave, 0, sizeof(slave));
++        data->dma_chan = dma_request_channel(data->cap_mask, ftdmac020_chan_filter, (void *)&slave);    //step 1
++    }
++#else
++    ftpmu010_write_reg(nand_fd, 0xA4, (0x0 << 27), (0x1 << 27));
++    printk(KERN_INFO "use AXI DMA mode\n");
++    {
++        struct ftdmac030_dma_slave slave;
++        memset(&slave, 0, sizeof(slave));
++        data->dma_chan = dma_request_channel(data->cap_mask, ftdmac030_chan_filter, (void *)&slave);    //step 1
++    }
++#endif
++
++    if (!data->dma_chan) {
++        dev_err(&pdev->dev, "DMA channel allocation failed\n");
++        res = -ENODEV;
++        goto out_free_buf;
++    }
++    printk(KERN_INFO "Nand get DMA channel %d\n", data->dma_chan->chan_id);
++
++    data->mem_dmabuf =
++        dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->mem_dmaaddr, GFP_KERNEL);
++    if (!data->mem_dmabuf) {
++        dev_err(&pdev->dev, "failed to allocate dma buffers.\n");
++        res = -ENOMEM;
++        goto out_free_dma;
++    }
++    data->sg_dmabuf = dma_to_virt(&pdev->dev, data->mem_dmaaddr);
++
++    //printk("sg mem pa = 0x%x, va = 0x%x\n", (u32)data->mem_dmaaddr, (u32)data->sg_dmabuf);
++#else
++    printk(KERN_INFO "use PIO mode\n");
++#endif
++
++    /* read the system header first 
++     */
++    if (1) {
++        /* read system header 
++         */
++        //data->sys_hdr = kzalloc(data->mtd.writesize, GFP_KERNEL);
++        data->sys_hdr =
++            dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->syshd_dmaaddr, GFP_KERNEL);
++        if (data->sys_hdr == NULL) {
++            printk(KERN_ERR "Warning............SPI-NAND: can't alloc memory");
++            return -ENOMEM;
++        }
++        
++        data->chip.buffers = kmalloc(sizeof(struct nand_buffers), GFP_KERNEL);//kmalloc(data->mtd.writesize + (spare << 2), GFP_KERNEL);
++        if (!data->chip.buffers) {
++            dev_err(&pdev->dev, "failed to allocate chip buffers.\n");
++            res = -ENOMEM;
++            goto out_unset_drv;
++        }
++        else if((sizeof(struct nand_buffers) <  data->mtd.writesize)) {
++    		dev_err(&pdev->dev, "Please adjust the NAND_MAX_OOBSIZE & NAND_MAX_PAGESIZE\n");
++    		dev_err(&pdev->dev, "Flash Page size:%d, but NAND_MAX_PAGESIZE is %d\n", data->mtd.writesize, NAND_MAX_PAGESIZE);
++    		res = -ENOMEM;
++    		goto out_unset_drv;
++	    }
++
++        data->page_addr = 0;
++        data->chip.oob_poi = data->chip.buffers->databuf + data->mtd.writesize;
++
++        printk(KERN_INFO "NAND: read system header\n");
++        if (data->read_page(&data->mtd, (u_char *) data->sys_hdr) < 0) {
++            printk(KERN_ERR "Warning............SPI-NAND: read system header fail!");
++            return -ENODEV;
++        }
++        data->nand_parm.page_size = data->sys_hdr->nandfixup.nand_pagesz;
++        data->nand_parm.spare_size = data->sys_hdr->nandfixup.nand_sparesz_inpage;
++        data->nand_parm.block_pg = data->sys_hdr->nandfixup.nand_numpgs_blk;
++
++        data->lookup_flag = data->sys_hdr->function[0];
++        /* empty flash */
++        if(data->lookup_flag == 0xFF)
++            data->lookup_flag = 0;
++
++        data->bi_table =
++            dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->bitab_dmaaddr, GFP_KERNEL);
++        if (data->bi_table == NULL) {
++            printk(KERN_ERR "Warning............SPI-NAND: can't alloc bi table memory");
++            return -ENOMEM;
++        }
++
++		memset(data->bi_table, 0, sizeof(bi_table_t));
++        if(data->lookup_flag) {
++            data->lookup_table = kzalloc(8192*2, GFP_KERNEL);
++        	if (!data->lookup_table) {
++        		printk(KERN_ERR "SF: Failed to allocate lookup table\n");
++        		return -ENOMEM;
++        	} else {
++        	    int i, num, loop;
++        	    u8 *buf;
++        	    
++        	    num = data->sys_hdr->nandfixup.nand_pagesz;
++        	    if(data->sys_hdr->nandfixup.nand_numblks == 512) {
++        	        loop = 1;
++        	        data->block_limit = 500;
++        	    } else {
++        	        loop = data->sys_hdr->nandfixup.nand_numblks / 1024;
++        	        data->block_limit = data->sys_hdr->nandfixup.nand_numblks - (data->sys_hdr->nandfixup.nand_numblks % 1000);
++        	    }
++
++                buf = (u8 *)data->lookup_table;
++        	    for(i = 0; i < loop; i++) {
++        	        //printk("lookup addr = 0x%x, spi_pgbuf addr = 0x%x\n", nand_lookup + (i * num / 4), spi_pgbuf);
++        	        data->page_addr = i + 1;
++                    if (data->read_page(&data->mtd, buf) < 0) {
++                        printk(KERN_ERR "Warning............SPI-NAND: read lookup table fail!");
++                        return -ENODEV;
++                    }
++        
++                    buf += num;
++                }
++
++                num *= data->sys_hdr->nandfixup.nand_numpgs_blk;
++                for(i = 0; i < data->sys_hdr->nandfixup.nand_numblks; i++)
++                    ftspi_nand_dbg("<B l:0x%4x, p:0x%4x>", i * num, data->lookup_table->physical[i] * num);
++            }            
++        }
++
++        partitions = ftnandc023_partition_info;
++        partitions_num = partition_check(partitions, data, data->mtd.erasesize);
++
++        /* restore the orginal setting */
++        data->page_addr = 0;
++    }
++    
++    i = ftnandc023_available_oob(data);
++	data->mtd.oobsize = data->nand_parm.spare_size;
++
++    printk(KERN_INFO "NAND Chip: oobsize:%#x, pagesize:%#x, blocksize:%#x, chipsize:%#x\n",
++           (int)data->mtd.oobsize, (int)data->mtd.writesize, (int)data->mtd.erasesize, (int)data->chip.chipsize);
++
++    /* Scan bad block and create bbt table
++     */
++    nand_scan_tail(&data->mtd);
++
++        /*----------------------------------------------------------
++	 * ONFI synch mode means High Speed. If fails to change to
++	 * Synch mode, then use flash as Async mode(Normal speed) and
++	 * use LEGACY_LARGE fix flow.
++	 */
++    //if (type == ONFI)
++    //    data->flash_type = ONFI;
++
++    res = mtd_device_parse_register(&data->mtd, NULL, 0, partitions, partitions_num);
++    if (!res)
++        return res;
++
++    nand_release(&data->mtd);
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++out_free_dma:
++    if (data->dma_chan)
++        dma_release_channel(data->dma_chan);
++out_free_buf:
++#endif
++    kfree(data->chip.buffers);
++
++out_unset_drv:
++    platform_set_drvdata(pdev, NULL);
++
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    if (data->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->mem_dmabuf, data->mem_dmaaddr);
++#endif
++    iounmap(data->io_base);
++out_free_data:
++    if (data->sys_hdr)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->sys_hdr, data->syshd_dmaaddr);
++    if (data->bi_table)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->bi_table, data->bitab_dmaaddr);
++    if (data->lookup_table)
++        kfree(data->lookup_table);
++    kfree(data);
++out:
++    return res;
++}
++
++/*
++ * @consult with bad block table about this block is good or bad.
++ *
++ * @ftnandc_spi_read_bbt(struct mtd_info *mtd, loff_t offs)
++ * @param mtd: MTD device structure
++ * @param offs: block base address
++ * @return: 1 for bad block, 0 for good block
++*/
++int ftnandc_spi_read_bbt(struct mtd_info *mtd, loff_t offs)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    struct bi_table *bi = (bi_table_t *) data->bi_table;
++    int ret = 0, blk_id, result;
++
++    if(!data->lookup_flag) {
++        blk_id = offs >> chip->bbt_erase_shift;
++        data->page_addr = blk_id << (chip->bbt_erase_shift - chip->page_shift);
++    
++        ftspi_nand_dbg("%s, offs = 0x%x, page = 0x%x\n", __FUNCTION__, (u32) offs, data->page_addr);
++    
++        if (data->read_oob(&data->mtd, data->chip.oob_poi) < 0) {
++            //printk("NAND: read system header fail!");
++            return 1;
++        }
++    
++        result = bi->bi_status[blk_id / 32];
++    
++        if (*data->chip.oob_poi == 0xFF) {
++            bi->bi_status[blk_id / 32] = result;
++            result |= (1 << (blk_id % 32));
++            ret = 0;                /* good */
++        } else {
++            result &= ~(1 << (blk_id % 32));
++            ret = 1;                /* bad */
++        }
++        bi->bi_status[blk_id / 32] = result;
++    }
++
++    return ret;
++}
++
++/**
++ * ftnandc023v2_default_block_markbad - mark a block bad
++ * @mtd:	MTD device structure
++ * @ofs:	offset from device start
++ *
++ * This is the default implementation, which can be overridden by
++ * a hardware specific driver.
++*/
++static int ftnandc023v2_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++    int ret = 0;
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    unsigned int *bi_table = (unsigned int *)data->bi_table;
++    int quotient, remainder, blk_id, result;
++    int i, num, loop, value;
++    u8 *buf;    
++
++    printk(KERN_INFO "%s, addr = 0x%x\n", __FUNCTION__, (int)ofs);
++
++    /* Get block number */
++    blk_id = (int)(ofs >> chip->bbt_erase_shift);
++
++    if(!data->lookup_flag) {
++        if (data->bi_table) {
++            blk_id = ofs >> chip->bbt_erase_shift;
++            quotient = blk_id >> 5;
++            remainder = blk_id & 0x1F;
++            result = (bi_table[quotient] >> remainder) & 0x1;
++            //printk("BI table %dth, bit %d, data = 0x%x, result = %d\n", quotient, remainder, bi_table[quotient], result);
++            if (result == 0)        /* bad block, not need to do it */
++                return 0;
++    
++            bi_table[quotient] &= ~(1 << remainder);        /* Write the block mark. */
++            blk_id <<= 1;
++            //printk("blk_id %dth, data = 0x%x, result = %x\n", blk_id, chip->bbt[blk_id >> 3], (0x3 << (blk_id & 0x06)));
++            chip->bbt[blk_id >> 3] |= (0x3 << (blk_id & 0x06));
++        }
++        /* write 1 to 0, not need to erase first */
++        data->page_addr = (int)ofs / mtd->writesize;
++        *chip->oob_poi = 0x0;
++        ret = data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++        if (!ret)
++            mtd->ecc_stats.badblocks++;
++
++    } else {
++        /* set BI field */
++        data->page_addr = (int)ofs / mtd->writesize;
++        *chip->oob_poi = 0x0;
++        ret = data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++        if (!ret)
++            mtd->ecc_stats.badblocks++;
++
++        /* use another block to replace it */
++        for(i = data->block_limit; i < data->sys_hdr->nandfixup.nand_numblks; i++) {
++            value = data->lookup_table->physical[i];
++            if((value != 0xFFFF) && (value & 0x8000)) {
++                value &= ~0x8000;
++                data->lookup_table->physical[blk_id] = value;
++                data->lookup_table->physical[i] = 0xFFFF;
++                printk(KERN_NOTICE "Use physical block %d replace logical block %d\n", value, blk_id);
++                break;
++            }
++        }
++        if(i == data->sys_hdr->nandfixup.nand_numblks){
++            printk(KERN_ERR "Can't find good block to replace it");
++            return -EIO;            
++        }
++
++        data->page_addr = 0;
++        data->page_addr = 0;
++        data->sel_chip = 0;
++        data->flash_type = 0;
++        
++        chip->cmdfunc(mtd, NAND_CMD_ERASE1, 0, 0);
++        if (data->write_page(mtd, (const uint8_t *)data->sys_hdr) < 0) {
++                printk(KERN_ERR "Warning............SPI-NAND: write system header fail!");
++                return -ENODEV;
++        }
++   
++        num = data->sys_hdr->nandfixup.nand_pagesz;
++        if(data->sys_hdr->nandfixup.nand_numblks <= 1024)
++            loop = 1;
++        else
++            loop = data->sys_hdr->nandfixup.nand_numblks / 1024;
++        
++        buf = (u8 *)data->lookup_table;
++        for(i = 0; i < loop; i++) {
++            data->page_addr = i + 1;
++            if (data->write_page(mtd, buf) < 0) {
++                printk(KERN_ERR "Warning............SPI-NAND: write lookup table fail!");
++                return -ENODEV;
++            }
++        
++            buf += num;
++        }
++    }
++    return ret;
++}
++
++/*
++ * Remove a NAND device.
++ */
++int __devexit ftnandc023_nand_remove(struct platform_device *pdev)
++{
++    struct ftnandc023_nand_data *data = platform_get_drvdata(pdev);
++
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    if (data->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->mem_dmabuf, data->mem_dmaaddr);
++    if (data->dma_chan)
++        dma_release_channel(data->dma_chan);
++#endif
++    if (data->sys_hdr)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->sys_hdr, data->syshd_dmaaddr);
++    if (data->bi_table)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->bi_table, data->bitab_dmaaddr);
++    if (data->lookup_table)
++        kfree(data->lookup_table);
++
++    nand_release(&data->mtd);
++    iounmap(data->io_base);
++    kfree(data->chip.buffers);
++    kfree(data);
++
++    return 0;
++}
++
++static void ftnandc023_release(struct device *dev)
++{
++}
++
++static u64 ftnandc023_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftnandc023_device = {
++    .name = "ftnandc023_nand",
++    .id = -1,
++    .num_resources = ARRAY_SIZE(ftnandc023_resource),
++    .resource = ftnandc023_resource,
++    .dev = {
++            .dma_mask = &ftnandc023_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            .release = ftnandc023_release,
++            },
++};
++
++static struct platform_driver ftnandc023_nand_driver = {
++    .probe = ftspi020_nand_probe,
++    .remove = __devexit_p(ftnandc023_nand_remove),
++    .driver = {
++               .name = "ftnandc023_nand",
++               .owner = THIS_MODULE,
++               },
++};
++
++static int __init ftspi020_nand_init(void)
++{
++    int ret = 0;
++
++    /* check if the system is running NAND system 
++     */
++    if (platform_check_flash_type() != 1) {
++        printk(KERN_INFO "Not for SPI-NAND pin mux\n");
++        return 0;
++    }
++
++    /* Register PMU and turn on gate clock
++     */
++    nand_fd = ftpmu010_register_reg(&pmu_reg_info);
++    if (nand_fd < 0) {
++        printk(KERN_ERR "Warning............SPI-NAND: register PMU fail");
++        return 0;
++    }
++
++#ifdef CONFIG_GPIO_WP
++    if ((ret = gpio_request(GPIO_PIN, PIN_NAME)) != 0) {
++        printk("gpio request fail\n");
++        return ret;
++    }
++    printk("register GPIO for NAND write protect\n");
++#endif
++
++    if (platform_device_register(&ftnandc023_device)) {
++        printk(KERN_ERR "device register failed\n");
++        ret = -ENODEV;
++    }
++    if (platform_driver_register(&ftnandc023_nand_driver)) {
++        printk(KERN_ERR "driver register failed\n");
++        ret = -ENODEV;
++    }
++    return ret;
++}
++
++static void __exit ftspi020_nand_exit(void)
++{
++    /* check if the system is running NAND system 
++     */
++    if (platform_check_flash_type() != 0)
++        return;
++
++    /* Deregister PMU
++     */
++    ftpmu010_deregister_reg(nand_fd);
++
++    platform_driver_unregister(&ftnandc023_nand_driver);
++    platform_device_unregister(&ftnandc023_device);
++}
++
++module_init(ftspi020_nand_init);
++module_exit(ftspi020_nand_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Te-Chen Ying");
++MODULE_DESCRIPTION("FTNANDC023 V2.0 NAND driver");
++MODULE_ALIAS("platform:ftnandc023_nand");
+diff --git a/drivers/mtd/nand/ftspi020_nand.h b/drivers/mtd/nand/ftspi020_nand.h
+new file mode 100644
+index 00000000..a46ce9d9
+--- /dev/null
++++ b/drivers/mtd/nand/ftspi020_nand.h
+@@ -0,0 +1,264 @@
++/**
++ * Command arguments definition for FTSPI020.
++ *
++ * Author: Justin Shih <wdshih@faraday-tech.com> 
++ *
++ * Copyright (c) 2013, Faraday Technology Corp.
++ *
++ */  
++    
++/* FIX_FLOW_INDEX for ONFI change mode */ 
++#define		ONFI_FIXFLOW_GETFEATURE		0x34B
++#define		ONFI_FIXFLOW_SETFEATURE		0x352
++#define		ONFI_FIXFLOW_SYNCRESET		0x33A
++    
++#define		MAX_CE				1       //4
++#define		MAX_CHANNEL			1       //2
++//#define               NAND_USE_AHBDMA_CHANNEL         0
++    
++/*
++ * Settings value required to send command.
++ */ 
++    typedef struct ftspi020_cmd {
++    
char flags;
++    
++        /* offset 0x00: CMD Queue first word */ 
++     u32 spi_addr;
++    
++        /* offset 0x04: CMD Queue second word */ 
++     u32 addr_len;
++    
 u32 dum_2nd_cyc;
++    
 u32 ins_len;
++    
 u32 conti_read_mode_en;
++    
++        /* offset 0x08: CMD queue third word */ 
++     u32 data_cnt;
++    
++        /* offset 0x0C: CMD queue fourth word */ 
++     u32 intr_en;
++    
 u32 write_en;
++    
 u32 read_status_en;
++    
 u32 read_status;
++    
 u32 dtr_mode;
++    
 u32 spi_mode;
++    
 u32 start_ce;
++    
 u32 conti_read_mode_code;
++    
 u32 ins_code;
++    
 
++        /* User data buffer pointer */ 
++    const void *tx_buf;
++    
 void *rx_buf;
++
 
} ftspi020_cmd_t;
++
++#ifndef CONFIG_FTNANDC023_DEBUG
++#define CONFIG_FTNANDC023_DEBUG			0
++#endif  /* 
 */
++#if CONFIG_FTNANDC023_DEBUG > 0
++#define ftnandc023_dbg(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__);
++#else   /* 
 */
++#define ftnandc023_dbg(fmt, ...) do {} while (0);
++#endif  /* 
 */
++    
++#if CONFIG_FTNANDC023_DEBUG > 0
++#define DBGLEVEL1(x)	x
++#else   /* 
 */
++#define DBGLEVEL1(x)
++#endif  /* 
 */
++    
++#if CONFIG_FTNANDC023_DEBUG > 1
++#define DBGLEVEL2(x)	x
++#else   /* 
 */
++#define DBGLEVEL2(x)
++#endif  /* 
 */
++
typedef enum { 
LEGACY_SMALL = 0, 
LEGACY_LARGE, 
TOGGLE, 
ONFI, 
++} flashtype;
++

struct ftnandc023_nandchip_attr {
++    
char *name;
++    
 int sparesize;
++    
 int pagesize;
++    
 int blocksize;
++    
 int flashsize;
++    
 flashtype legacy;
++
};
++
++/******************************************************************************
++ * SPI COMMAND
++ *****************************************************************************/ 
++#define COMMAND_READ_ID							0x9f
++#define COMMAND_WRITE_ENABLE        0x06
++#define COMMAND_WRITE_DISABLE       0x04
++#define COMMAND_ERASE_SECTOR        0x20
++#define COMMAND_ERASE_128K_BLOCK    0xD8
++#define COMMAND_ERASE_CHIP          0xC7
++#define COMMAND_READ_STATUS1        0x05
++#define COMMAND_READ_STATUS2        0x35
++#define COMMAND_WRITE_STATUS        0x01
++#define COMMAND_WRITE_PAGE          0x02
++#define COMMAND_WINBOND_QUAD_WRITE_PAGE     0x32
++#define COMMAND_QUAD_WRITE_PAGE     0x38
++#define COMMAND_READ_DATA           0x03
++#define COMMAND_FAST_READ           0x0B
++#define COMMAND_FAST_READ_DUAL	    0x3B
++#define COMMAND_FAST_READ_DUAL_IO   0xBB
++#define COMMAND_FAST_READ_QUAD	    0x6B
++#define COMMAND_FAST_READ_QUAD_IO   0xEB
++#define COMMAND_WORD_READ_QUAD_IO   0xE7
++#define COMMAND_READ_UNIQUE_ID	    0x4B
++#define COMMAND_EN4B                0xB7        //enter 4 byte mode
++#define COMMAND_EX4B                0xE9        //exit 4 byte mode
++#define COMMAND_RESET               0xFF
++    
++/******************************************************************************
++ * SPI NAND COMMAND
++ *****************************************************************************/ 
++#define COMMAND_ERASE_128K_BLOCK    0xD8
++#define COMMAND_GET_FEATURES        0x0F
++#define COMMAND_SET_FEATURES        0x1F
++#define COMMAND_PAGE_READ           0x13
++#define COMMAND_PROGRAM_LOAD        0x02
++#define COMMAND_PROGRAM_EXECUTE     0x10
++#define COMMAND_BLOCK_ERASE         0xD8
++    
++/* Status register 1 bits */ 
++#define FLASH_STS_BUSY              (0x1 << 0)
++#define FLASH_STS_WE_LATCH          (0x1 << 1)
++#define FLASH_STS_REG_PROTECT0	    (0x1 << 7)
++    
++/* Status register 2 bits */ 
++#define FLASH_STS_REG_PROTECT1	    (0x1 << 0)
++#define FLASH_STS_QUAD_ENABLE       (0x1 << 6)
++#define FLASH_WINBOND_STS_QUAD_ENABLE   (0x1 << 1)
++/******************************************************************************
++ * SPI020 definitions
++ *****************************************************************************/ 
++#define	FTSPI020_REG_CMD0		0x00	/* Flash address */
++#define	FTSPI020_REG_CMD1		0x04
++#define	FTSPI020_REG_CMD2		0x08
++#define	FTSPI020_REG_CMD3		0x0c
++#define	FTSPI020_REG_CTRL		0x10	/* Control */
++#define	FTSPI020_REG_AC_TIME		0x14
++#define	FTSPI020_REG_STS		0x18	/* Status */
++#define	FTSPI020_REG_ICR		0x20	/* Interrupt Enable */
++#define	FTSPI020_REG_ISR		0x24	/* Interrupt Status */
++#define	FTSPI020_REG_READ_STS		0x28
++#define FTSPI020_REG_REVISION		0x50
++#define FTSPI020_REG_FEATURE		0x54
++#define FTSPI020_REG_DATA_PORT		0x100
++    
++/*
++ * Control Register offset 0x10
++ */ 
++#define	FTSPI020_CTRL_READY_LOC_MASK	~(0x7 << 16)
++#define	FTSPI020_CTRL_READY_LOC(x)	(((x) & 0x7) << 16)
++    
++#define	FTSPI020_CTRL_ABORT		(1 << 8)
++    
++#define	FTSPI020_CTRL_CLK_MODE_MASK	~(1 << 4)
++#define	FTSPI020_CTRL_CLK_MODE_0	(0 << 4)
++#define	FTSPI020_CTRL_CLK_MODE_3	(1 << 4)
++    
++#define	FTSPI020_CTRL_CLK_DIVIDER_MASK	~(3 << 0)
++#define	FTSPI020_CTRL_CLK_DIVIDER_2	(0 << 0)
++#define FTSPI020_CTRL_CLK_DIVIDER_4	(1 << 0)
++#define FTSPI020_CTRL_CLK_DIVIDER_6	(2 << 0)
++#define FTSPI020_CTRL_CLK_DIVIDER_8	(3 << 0)
++    
++/*
++ * Status Register offset 0x18
++ */ 
++#define	FTSPI020_STS_RFR	(1 << 1) /* RX FIFO ready */
++#define	FTSPI020_STS_TFR	(1 << 0) /* TX FIFO ready */
++    
++/*
++ * Interrupt Control Register
++ */ 
++#define	FTSPI020_ICR_RFTH(x)	(((x) & 0x3) << 12)	/* RX FIFO threshold interrupt */
++#define	FTSPI020_ICR_TFTH(x)	(((x) & 0x3) << 8)	/* TX FIFO threshold interrupt */
++#define	FTSPI020_ICR_DMA	(1 << 0)		/* DMA handshake enable */
++    
++/*
++ * Interrupt Status Register
++ */ 
++#define	FTSPI020_ISR_CMD_CMPL	(1 << 0)	/* Command complete interrupt  */
++    
++/*
++ * Feature Register
++ */ 
++#define FTSPI020_FEATURE_CLK_MODE(reg)		(((reg) >> 25) & 0x1)
++#define FTSPI020_FEATURE_DTR_MODE(reg)		(((reg) >> 24) & 0x1)
++#define FTSPI020_FEATURE_CMDQ_DEPTH(reg)	(((reg) >> 16) & 0xff)
++#define FTSPI020_FEATURE_RXFIFO_DEPTH(reg)	(((reg) >>  8) & 0xff)
++#define FTSPI020_FEATURE_TXFIFO_DEPTH(reg)	(((reg) >>  0) & 0xff)
++    
++/*
++ * In what state this command belong ?
++ */ 
++#define FTSPI020_XFER_BEGIN			0x01
++#define FTSPI020_XFER_END			0x02
++#define FTSPI020_XFER_CMD_STATE			0x04
++#define FTSPI020_XFER_DATA_STATE		0x08
++#define FTSPI020_XFER_CHECK_CMD_COMPLETE	0x10
++    
++/*
++ * CMD1 Register offset 4: Command Queue Second Word
++ */ 
++//#define FTSPI020_CMD1_CONT_READ_MODE_EN               (1 << 28)
++//#define FTSPI020_CMD1_CONT_READ_MODE_DIS      (0 << 28)
++    
++#define FTSPI020_CMD1_OP_CODE_0_BYTE		0
++#define FTSPI020_CMD1_OP_CODE_1_BYTE		1
++#define FTSPI020_CMD1_OP_CODE_2_BYTE		2
++    
++#define FTSPI020_CMD1_DUMMY_CYCLE(x)	(((x) & 0xff) << 16)
++    
++#define FTSPI020_CMD1_NO_ADDR			0
++#define FTSPI020_CMD1_ADDR_1BYTE	1
++#define FTSPI020_CMD1_ADDR_2BYTE	2
++#define FTSPI020_CMD1_ADDR_3BYTE	3
++#define FTSPI020_CMD1_ADDR_4BYTE	4
++    
++/*
++ * CMD3 Register offset 0xc: Command Queue Fourth Word
++ */ 
++#define FTSPI020_CMD3_INSTR_CODE(x)	(((x) & 0xff) << 24)
++#define FTSPI020_CMD3_CONT_READ_CODE(x)	(((x) & 0xff) << 16)
++    
++#define FTSPI020_CMD3_CE(x)		(((x) & 0x3) << 8)
++    
++#define FTSPI020_CMD3_SERIAL_MODE	  0
++#define FTSPI020_CMD3_DUAL_MODE		  1
++#define FTSPI020_CMD3_QUAD_MODE		  2
++#define FTSPI020_CMD3_DUAL_IO_MODE	3
++#define FTSPI020_CMD3_QUAD_IO_MODE	4
++    
++#define FTSPI020_CMD3_DTR_MODE_EN		1
++#define FTSPI020_CMD3_DTR_MODE_DIS	0
++    
++#define FTSPI020_CMD3_STS_SW_READ	1
++#define FTSPI020_CMD3_STS_HW_READ	0
++    
++#define FTSPI020_CMD3_RD_STS_EN		1
++#define FTSPI020_CMD3_RD_STS_DIS	0
++    
++#define	FTSPI020_CMD3_WRITE		1
++#define	FTSPI020_CMD3_READ		0
++    
++#define FTSPI020_CMD3_CMD_COMPL_INTR	(1 << 0)
++    
++#define FLASH_NAND_BLOCK_PG 64
++#define FLASH_NAND_PAGE_SZ  2048
++#define FLASH_NAND_SPARE_SZ 64
++    
++#define FLASH_NAND_P_FAIL 	0x8
++#define FLASH_NAND_E_FAIL 	0x4
++#define FLASH_NAND_R_FAIL 	0x20
++#define FLASH_NAND_R_FIELD 	0x30
++#define FLASH_NAND_R_ECC_LIMIT 	0x10
++#define FLASH_NAND_R_ECC_LIMIT_GD 	0x30
++
++/* PRIVATE use */ 
++#define SPI_XFER_CMD_STATE              0x00000002
++//#define SPI_XFER_DATA_STATE               0x00000004
++#define SPI_XFER_CHECK_CMD_COMPLETE     0x00000008
++#define SPI_XFER_DATA_IN_STATE          0x00000010
++#define SPI_XFER_DATA_OUT_STATE         0x00000020
+diff --git a/drivers/mtd/nand/ftspi020_nand_v2.c b/drivers/mtd/nand/ftspi020_nand_v2.c
+new file mode 100644
+index 00000000..61890d2c
+--- /dev/null
++++ b/drivers/mtd/nand/ftspi020_nand_v2.c
+@@ -0,0 +1,2713 @@
++/*
++ * SPI NAND driver
++ *
++ * 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 <linux/version.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/vmalloc.h>
++#include <linux/dma-mapping.h>
++#include <linux/jiffies.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <mach/platform/platform_io.h>
++#include <mach/platform/board.h>
++#include <mach/ftpmu010.h>
++//#include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/spi/spi.h>
++#include "ftspi020_nand.h"
++#include <linux/delay.h>
++
++#define CONFIG_FTSPI_NAND_DEBUG			0
++#if CONFIG_FTSPI_NAND_DEBUG > 0
++#define ftspi_nand_dbg(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__);
++#else
++#define ftspi_nand_dbg(fmt, ...) do {} while (0);
++#endif
++/*
++ * Local function or variables declaration
++ */
++
++#define CONFIG_NAND_DISTRUB
++//#define CONFIG_SPI_NAND_USE_AHBDMA//???
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++#include <linux/dmaengine.h>
++
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++#include <mach/ftdmac020.h>
++#else
++#include <mach/ftdmac030.h>
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136) || defined(CONFIG_PLATFORM_GM8220)
++#define AHBMASTER_R_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_R_DST   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_SRC   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_DST   FTDMA020_AHBMASTER_0
++#define SPI020_REQ    8
++#endif
++
++#endif
++
++#define PORTING
++static int ftnandc023v2_block_markbad(struct mtd_info *mtd, loff_t ofs);
++static int calc_new_page(struct mtd_info *mtd, int page_addr);
++int ftnandc_spi_read_bbt(struct mtd_info *mtd, loff_t offs);
++static int nand_fd, cmdfunc_status = NAND_STATUS_READY;
++
++#define FLASH_PAGESIZE  256
++#define IDCODE_LEN		4
++
++/* Flash opcodes. */
++#define	OPCODE_WREN		0x06    /* Write enable */
++#define	OPCODE_RDSR		0x05    /* Read status register */
++#define	OPCODE_RDSR2	0x35
++#define	OPCODE_WRSR		0x01    /* Write status register 1 byte */
++#define	OPCODE_EN4B		0xB7
++#define	OPCODE_EX4B		0xE9
++
++#define	OPCODE_BE_32K		0x52    /* Erase 32KiB block */
++#define	OPCODE_BE_64K		0xd8    /* Erase 64KiB block */
++
++/* 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	30000
++#define	CMD_SIZE		    4
++
++#define SPI_NAME	"SPI_NAND_FLASH"
++#define BLOCK_ALIGN(base, blk_shift) ((((base) + (0x1 << (blk_shift)) - 1) >> (blk_shift)) << (blk_shift))
++
++/*
++ * Macro definitions
++ */
++#define DEFAULT_BLOCK_SIZE  0x20000
++#define MTD_CFG_SZ          (6 * DEFAULT_BLOCK_SIZE)    //2 block + reserved
++
++#define CONFIG_FTNANDC023_START_CHANNEL     0
++#define BLOCK_ALIGN(base, blk_shift) ((((base) + (0x1 << (blk_shift)) - 1) >> (blk_shift)) << (blk_shift))
++
++#define FTSPI020_FEATURE_RXFIFO_DEPTH(reg)	(((reg) >>  8) & 0xff)
++#define FTSPI020_FEATURE_TXFIFO_DEPTH(reg)	(((reg) >>  0) & 0xff)
++
++static uint8_t ftnandc023_bbt_pattern[] = { 'B', 'b', 't', '0' };
++static uint8_t ftnandc023_mirror_pattern[] = { '1', 't', 'b', 'B' };
++
++#ifdef CONFIG_GPIO_WP
++#define GPIO_PIN      28
++#define PIN_NAME      "gpio28"
++#endif
++
++//=============================================================================
++// System Header, size = 512 bytes
++//=============================================================================
++
++static int read_id_time = 0, ID_point = 0;
++static int startchn = CONFIG_FTNANDC023_START_CHANNEL;
++static int legacy;
++
++static u8 idcode[IDCODE_LEN];
++static struct mtd_partition PORTING ftnandc023_partition_info[25];
++
++int show_one_time = 1;
++extern int root_mtd_num;
++
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++static void ftspi020_dma_callback(void *param);
++static unsigned int dma_trigger_flag = 0;
++static wait_queue_head_t dma_queue;
++#endif
++
++/******************************************************************************
++ * spi private data
++ *****************************************************************************/
++typedef struct spi_nand_sys_header {
++    char signature[8];          /* Signature is "GM8xxx" */
++    struct {
++        unsigned int addr;          /* partition address */
++        unsigned int size;          /* partition size */
++        unsigned char name[8];      /* partition name */
++        unsigned int img_size;		/* image size */
++    } image[23];
++    
++    struct {
++        unsigned int nand_numblks;      //number of blocks in chip
++        unsigned int nand_numpgs_blk;   //how many pages in a block
++        unsigned int nand_pagesz;       //real size in bytes                        
++        unsigned int nand_sparesz_inpage;       //64bytes for 2k, ...... needed for NANDC023
++        unsigned int nand_numce;        //how many CE in chip
++        unsigned int nand_clkdiv;				// 2/4/6/8
++        unsigned int nand_ecc_capability;   
++        unsigned int nand_sparesz_insect;
++    } nandfixup;
++    
++    unsigned int reserved1; 	// unused
++    unsigned char function[4];
++    unsigned char reserved2[2];	// unused
++    unsigned char last_511[2];  // byte510:0x55, byte511:0xAA
++} spi_nand_sys_header_t;
++
++struct common_spi_flash {
++    struct spi_device *spi;
++    struct mutex lock;
++    struct mtd_info mtd;
++    spi_nand_sys_header_t *sys_hdr;      /* system header */
++
++    u8 erase_opcode;
++    u8 mode_3_4;
++    u8 flash_type;              //1:winbond, status register is different
++};
++
++static struct resource ftnandc023_resource[] = {
++    [0] = {
++           .start = SPI_FTSPI020_PA_BASE,
++           .end = SPI_FTSPI020_PA_LIMIT,
++           .flags = IORESOURCE_MEM,
++           },
++    [1] = {
++           .start = SPI_FTSPI020_IRQ,
++           .end = SPI_FTSPI020_IRQ,
++           .flags = IORESOURCE_IRQ,
++           }
++};
++
++static struct nand_ecclayout nand_0_hw_eccoob = {
++    .eccbytes = 16,    
++    .eccpos = {
++               },        
++    .oobfree = {
++                {.offset = 4,.length = 12,},
++                {.offset = 20,.length = 12,},
++                {.offset = 36,.length = 12,},
++                {.offset = 52,.length = 12,}
++                },
++};
++
++static struct nand_ecclayout nand_1_hw_eccoob = {
++    .eccbytes = 16,    
++    .eccpos = {
++               /* at the end of spare sector */
++               12, 13, 14, 15,
++               28, 29, 30, 31,
++               44, 45, 46, 47,
++               60, 61, 62, 63,
++               },        
++    .oobfree = {
++                {.offset = 4,.length = 8},
++                {.offset = 20,.length = 8},
++                {.offset = 36,.length = 8},
++                {.offset = 52,.length = 8}
++                },
++};
++
++static struct nand_ecclayout nand_2_hw_eccoob = {
++    .eccbytes = 12,    
++    .eccpos = {
++               /* at the end of spare sector */
++               1, 2, 3,
++               17, 18, 19,
++               33, 34, 35,
++               49, 50, 51,
++               },
++    .oobfree = {
++                {.offset = 8,.length = 8,},
++                {.offset = 24,.length = 8,},
++                {.offset = 40,.length = 8,},
++                {.offset = 56,.length = 8,}
++                },
++};
++
++static struct nand_ecclayout nand_3_hw_eccoob = {
++    .eccbytes = 24,    
++    .eccpos = {
++               /* at the end of spare sector */
++               8, 9, 10, 11, 12, 13,
++               24, 25, 26, 27, 28, 29,
++               40, 41, 42, 43, 44, 45,
++               56, 57, 58, 59, 60, 61,
++               },        
++    .oobfree = {
++                {.offset = 4,.length = 4,},
++                {.offset = 20,.length = 4,},
++                {.offset = 36,.length = 4,},
++                {.offset = 52,.length = 4,}
++                },
++};
++
++static struct nand_ecclayout nand_4_hw_eccoob = {
++    .eccbytes = 28,    
++    .eccpos = {
++               /* at the end of spare sector */
++               18, 19, 20, 21, 22, 23, 24,
++               25, 26, 27, 28, 29, 30, 31,
++               50, 51, 52, 53, 54, 55, 56,
++               57, 58, 59, 60, 61, 62, 63,
++               },        
++    .oobfree = {/* chip & datasheet not match */
++                {.offset = 2,.length = 8,},
++                {.offset = 10,.length = 8,},
++                {.offset = 34,.length = 8,},
++                {.offset = 42,.length = 8,}
++                },
++};
++
++static struct nand_bbt_descr ftnandc023_bbt_mirror_descr = {
++    .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++        | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++    .offs = 0,
++    .len = 4,
++    .veroffs = 4,
++    .maxblocks = 4,
++    .pattern = ftnandc023_mirror_pattern
++};
++
++static struct nand_bbt_descr ftnandc023_bbt_main_descr = {
++    .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++        | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
++    .offs = 0,
++    .len = 4,
++    .veroffs = 4,
++    .maxblocks = 4,
++    .pattern = ftnandc023_bbt_pattern
++};
++
++static uint8_t ftnandc023_scan_ff_pattern[] = { 0xff };
++
++static struct nand_bbt_descr ftnandc023_largepage_flashbased = {
++    .options = NAND_BBT_SCAN2NDPAGE,
++    .offs = 0,
++    .len = 1,
++    .pattern = ftnandc023_scan_ff_pattern
++};
++
++//=============================================================================
++// BI table, size = 1024 bytes
++//=============================================================================
++typedef struct bi_table {
++    /* This array size is related to USB_BUFF_SZ defined in usb_scsi.h */
++    unsigned int bi_status[256];        //each bit indicates a block. 1 for good, 0 for bad
++} bi_table_t;
++
++typedef struct lookup_table
++{
++    unsigned short physical[8192];
++} lookup_table_t;
++
++struct ftnandc023_nand_data {
++    struct nand_chip chip;
++    struct mtd_info mtd;
++    void __iomem *io_base;
++    int sel_chip;
++    int cur_cmd;
++    int page_addr;
++    int column;
++    int byte_ofs;
++    u32 *buf;            
++    struct device *dev;
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    struct dma_chan *dma_chan;
++    dma_cap_mask_t cap_mask;
++#ifdef CONFIG_SPI_NAND_USE_AXIDMA
++    struct ftdmac030_dma_slave dma_slave_config;
++#else
++    struct ftdmac020_dma_slave dma_slave_config;
++#endif
++    dma_cookie_t cookie;
++    dma_addr_t mem_dmaaddr;
++    dma_addr_t nand_dmaaddr;
++    unsigned char *mem_dmabuf;
++    unsigned char *sg_dmabuf;
++#endif
++    dma_addr_t syshd_dmaaddr;
++    dma_addr_t bitab_dmaaddr;
++    dma_addr_t lookuptab_dmaaddr;
++       
++    unsigned int ce;
++    unsigned int erase_sector_size;
++    unsigned short page_size;
++    unsigned int nr_pages;
++    unsigned int size;          //chip size
++    unsigned int mode_3_4;      //addres length = 3 or 4 bytes
++    unsigned short chip_type;
++    
++    struct {
++        unsigned int block_pg;
++        unsigned int page_size;
++        unsigned int spare_size;
++        unsigned int block_size;
++    } nand_parm;
++
++    int rxfifo_depth;
++    int txfifo_depth;
++
++    int cur_chan;
++    int valid_chip[MAX_CHANNEL];
++    int scan_state;
++    int flash_type;
++    int large_page;
++    int lookup_flag;
++    unsigned char ecc_type;
++    unsigned short block_limit;
++    spi_nand_sys_header_t *sys_hdr;      /* system header */
++    bi_table_t *bi_table;       /* bad block table next to sys_hdr */
++    lookup_table_t *lookup_table;
++    int (*write_oob) (struct mtd_info * mtd, const u_char * buf, int len);
++    int (*read_oob) (struct mtd_info * mtd, u_char * buf);
++    int (*write_page) (struct mtd_info * mtd, const uint8_t * buf);
++    int (*read_page) (struct mtd_info * mtd, u_char * buf);
++};
++
++static int ftspi020_data_access(struct ftnandc023_nand_data *data, u8 direction, u8 * addr, u32 len);
++static int spi_flash_cmd_read_fast(struct ftnandc023_nand_data *data, u32 offset, size_t len, u8 *buf);
++/******************************************************************************
++ * internal functions for FTSPI020
++ *****************************************************************************/
++#ifdef CONFIG_PLATFORM_GM8139
++static pmuReg_t pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x54, (0x3F << 26), 0, (0x15 << 26), (0x3F << 26)},        /* pinMux with NAND */
++    {0x58, (0x3 << 0), (0x3 << 0), (0x1 << 0), (0x3 << 0)},     /* DMA ack selection */
++    {0x6C, (0x7 << 0), (0x7 << 0), (0x7 << 0), (0x7 << 0)},
++    {0xB4, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, /* AHB clock gate */
++};
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8136
++static pmuReg_t pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x6C, (0x7 << 0), (0x7 << 0), (0x7 << 0), (0x7 << 0)},
++    {0xB4, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)}, /* AHB clock gate */
++};
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8220
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x1A4, (0xFFFF << 14), (0xFFFF << 14), (0x5555 << 14), (0xFFFF << 14)},   /* pinMux */
++    //{0x1A4, (0xFFFF << 14), (0xFFFF << 14), (0xAAAA << 14), (0xFFFF << 14)},   /* pinMux, 4-bit mode */
++    {0x68, (0x1 << 17), (0x1 << 17), (0x0 << 17), (0x1 << 17)},   /* AHB clock gate */
++};
++#endif
++
++static pmuRegInfo_t pmu_reg_info = {
++    "SPI020_NAND",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++static void ftspi020_dma_disable(void __iomem * base)
++{
++    unsigned int tmp = inl(base + FTSPI020_REG_ICR);
++
++    tmp &= ~FTSPI020_ICR_DMA;
++    outl(tmp, base + FTSPI020_REG_ICR);
++}
++
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++static void ftspi020_dma_enable(void __iomem * base)
++{
++    unsigned int tmp = inl(base + FTSPI020_REG_ICR);
++
++    tmp |= FTSPI020_ICR_DMA;
++    outl(tmp, base + FTSPI020_REG_ICR);
++}
++
++static int ftspi020_dma_wait(void)
++{
++    int rc = 0;
++
++    rc = wait_event_timeout(dma_queue, dma_trigger_flag == 1, 10 * HZ);
++    if (rc == 0) {
++        printk(KERN_ERR "SPI-NAND queue wake up timeout signal arrived\n");
++        return 1;
++    }
++
++    dma_trigger_flag = 0;
++    return 0;
++}
++
++#else
++
++static void ftspi020_wait_rxfifo_ready(void __iomem * base)
++{
++    volatile u32 value;
++    unsigned long timeo = jiffies;
++    int ret = 1;
++
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        //udelay (1);
++        value = inl(base + FTSPI020_REG_STS);
++        if (value & FTSPI020_STS_RFR)
++            break;
++    }
++    if (!(value & FTSPI020_STS_RFR))
++        printk(KERN_ERR "Wait RX FIFO timeout!\n");
++    else
++        ret = 0
++
++    return ret;        
++}
++
++static int ftspi020_wait_txfifo_ready(void __iomem * base)
++{
++    volatile u32 value;
++    int ret = 1;
++
++    unsigned long timeo = jiffies;
++
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        //udelay (1);
++        value = inl(base + FTSPI020_REG_STS);
++        if (value & FTSPI020_STS_TFR)
++            break;
++    }
++    if (!(value & FTSPI020_STS_TFR))
++        printk(KERN_ERR "Wait TX FIFO timeout!\n");
++    else
++        ret = 0
++
++    return ret;
++}
++#endif
++
++static unsigned int ftspi020_read_feature(void __iomem * base)
++{
++    return inl(base + FTSPI020_REG_FEATURE);
++}
++
++static int ftspi020_txfifo_depth(void __iomem * base)
++{
++    return FTSPI020_FEATURE_TXFIFO_DEPTH(ftspi020_read_feature(base));
++}
++
++static int ftspi020_rxfifo_depth(void __iomem * base)
++{
++    return FTSPI020_FEATURE_RXFIFO_DEPTH(ftspi020_read_feature(base));
++}
++
++static unsigned char ftspi020_read_status(void __iomem * base)
++{
++    return inb(base + FTSPI020_REG_READ_STS);
++}
++
++static void ftspi020_clk_divider(void __iomem * base, char div)
++{
++	unsigned int tmp = inl(base + FTSPI020_REG_CTRL);
++
++	tmp &= FTSPI020_CTRL_CLK_DIVIDER_MASK;
++	tmp |= div;
++	outl(tmp, base + FTSPI020_REG_CTRL);
++}
++
++static void setup_clk(void __iomem * base)
++{
++    int CLK, SCU_DIV, SPI_DIV, mod, max_speed_hz;
++
++#ifdef CONFIG_PLATFORM_GM8139
++    max_speed_hz = 45 * 1000 * 1000; //45MHz
++
++    if(ftpmu010_read_reg(0x28) & (1 << 13))
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL2) / 4;
++    else
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL1) / 2;
++#endif
++#ifdef CONFIG_PLATFORM_GM8136
++    max_speed_hz = 45 * 1000 * 1000; //45MHz
++
++    if(ftpmu010_read_reg(0x28) & (1 << 10))
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL1);
++    else
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL2);
++#endif
++#ifdef CONFIG_PLATFORM_GM8220
++    max_speed_hz = 100 * 1000 * 1000; //90MHz
++	CLK = ftpmu010_get_attr(ATTR_TYPE_AHB);
++#endif
++
++	//printk("CLK = %d\n", CLK);
++    SCU_DIV = CLK / 2;
++    mod = do_div(SCU_DIV, max_speed_hz);
++    
++    if(mod == 0)
++        SCU_DIV -= 1;
++
++    if(SCU_DIV > 7){
++        printk(KERN_ERR "SPI clock too quick\n");
++        SPI_DIV = FTSPI020_CTRL_CLK_DIVIDER_4;
++        SCU_DIV = 3;
++    }
++    else {
++        SPI_DIV = FTSPI020_CTRL_CLK_DIVIDER_2;
++    }
++    
++    CLK = CLK / ((1 << (SPI_DIV + 1)) * (SCU_DIV + 1));
++    ftpmu010_write_reg(nand_fd, 0x6C, SCU_DIV, 0x7);
++
++    printk(KERN_INFO "CLK scu div %d, spi div %d, clock = %dHz\n", SCU_DIV, SPI_DIV, CLK);
++	ftspi020_clk_divider(base, SPI_DIV);
++}
++
++/* polling command complete interrupt until the interrupt comes.
++ */
++static int ftspi020_wait_cmd_complete(struct ftnandc023_nand_data *data)
++{
++    u32 value = 0;
++    int ret = 1;
++    unsigned long timeo = jiffies;
++
++    ftspi_nand_dbg("wait_cmd_complete\n");
++
++    timeo += HZ;
++    while (time_before(jiffies, timeo)) {
++        //udelay (1);
++        value = inl(data->io_base + FTSPI020_REG_ISR);
++        if (value & FTSPI020_ISR_CMD_CMPL) {
++            outl(value, data->io_base + FTSPI020_REG_ISR);
++            break;
++        }
++    }
++    if (!(value & FTSPI020_ISR_CMD_CMPL))
++        printk(KERN_ERR "Wait command complete timeout!\n");
++    else
++        ret = 0;
++        
++    return ret;
++}
++
++void ftspi020_issue_cmd(struct ftnandc023_nand_data *data, struct ftspi020_cmd *command)
++{
++    u32 cmd_feature1, cmd_feature2;
++
++    outl(command->spi_addr, data->io_base + FTSPI020_REG_CMD0);
++
++    cmd_feature1 = ((command->conti_read_mode_en & 0x1) << 28) |
++        ((command->ins_len & 0x3) << 24) | ((command->dum_2nd_cyc & 0xFF) << 16) | 
++        ((command->addr_len & 0x7) << 0);
++    outl(cmd_feature1, data->io_base + FTSPI020_REG_CMD1);
++
++    outl(command->data_cnt, data->io_base + FTSPI020_REG_CMD2);
++
++    cmd_feature2 = ((command->ins_code & 0xFF) << 24) |
++        ((command->conti_read_mode_code & 0xFF) << 16) |
++        ((command->start_ce & 0x3) << 8) |
++        ((command->spi_mode & 0x7) << 5) |
++        ((command->dtr_mode & 0x1) << 4) |
++        ((command->read_status & 0x1) << 3) |
++        ((command->read_status_en & 0x1) << 2) | ((command->write_en & 0x1) << 1) | 
++        ((command->intr_en & 0x1) << 0);
++    ftspi_nand_dbg("spi reg 0x%x = 0x%x, reg 0x%x = 0x%x\n", FTSPI020_REG_ICR,
++                   inl(data->io_base + FTSPI020_REG_ICR), FTSPI020_REG_ISR,
++                   inl(data->io_base + FTSPI020_REG_ISR));
++    ftspi_nand_dbg("spi cmd queue = 0x%x, 0x%x, 0x%x, 0x%x\n", command->spi_addr, cmd_feature1,
++                   command->data_cnt, cmd_feature2);
++    outl(cmd_feature2, data->io_base + FTSPI020_REG_CMD3);
++}
++
++void ftspi020_setup_cmdq(struct ftnandc023_nand_data *data, ftspi020_cmd_t * spi_cmd, int ins_code,
++                         int ins_len, int write_en, int spi_mode, int data_cnt)
++{
++    memset(spi_cmd, 0x0, sizeof(ftspi020_cmd_t));
++//SPI_DEBUG("<ftspi020_setup_cmdq=0x%x>",ins_code);      
++    spi_cmd->start_ce = 0;      //only one CE???
++    spi_cmd->ins_code = ins_code;
++    spi_cmd->intr_en = FTSPI020_CMD3_CMD_COMPL_INTR;
++    spi_cmd->ins_len = ins_len;
++    spi_cmd->write_en = write_en;       //0 for the read ata or read status, others are 1.
++    spi_cmd->dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++    spi_cmd->spi_mode = spi_mode;
++    spi_cmd->data_cnt = data_cnt;
++
++    switch (ins_code) {
++    case COMMAND_READ_ID:
++        spi_cmd->spi_addr = 0x00;
++        spi_cmd->addr_len = FTSPI020_CMD1_ADDR_1BYTE;
++        break;
++    case COMMAND_SET_FEATURES:
++        spi_cmd->spi_addr = 0xA0;       // to disble write protect
++        spi_cmd->addr_len = FTSPI020_CMD1_ADDR_1BYTE;
++        break;
++    default:
++        break;
++    }
++
++    /* update to the controller */
++    ftspi020_issue_cmd(data, spi_cmd);
++}
++
++static int spi_xfer(struct ftnandc023_nand_data *data, unsigned int len, const void *dout, void *din,
++             unsigned long flags)
++{
++    struct ftspi020_cmd spi_cmd;
++    u8 *u8_data_out = (u8 *) dout;
++    int ret = 0;
++
++    memset(&spi_cmd, 0, sizeof(struct ftspi020_cmd));
++
++    /* send the instruction */
++    if (flags & SPI_XFER_CMD_STATE) {
++
++        spi_cmd.ins_code = *u8_data_out;
++        //printk("dout=0x%x,din=0x%x,%d,%d\n",*(UINT8 *)dout,*(UINT8 *)din, len, spi->cs);
++        spi_cmd.intr_en = FTSPI020_ISR_CMD_CMPL;
++#ifdef CONFIG_CMD_FPGA
++        spi_cmd.start_ce = 0;
++#endif
++        ftspi_nand_dbg("spi cmd = 0x%x\n", spi_cmd.ins_code);
++        switch (spi_cmd.ins_code) {
++        case COMMAND_READ_ID:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            spi_cmd.data_cnt = IDCODE_LEN;
++            spi_cmd.spi_addr = (u32) * (u8_data_out + 1);
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_1BYTE;
++            break;
++        case COMMAND_RESET:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_WRITE_ENABLE:
++        case COMMAND_WRITE_DISABLE:
++            //if (write_enable == spi_cmd.ins_code){
++            //          printk("exit\n");
++            //    goto exit;
++            //  }
++            //write_enable = spi_cmd.ins_code;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_ERASE_128K_BLOCK:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_ERASE_CHIP:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_WRITE_STATUS:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            spi_cmd.data_cnt = len;
++            break;
++        case COMMAND_READ_STATUS1:
++        case COMMAND_READ_STATUS2:
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_EN;
++            spi_cmd.read_status = FTSPI020_CMD3_STS_SW_READ;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_WRITE_PAGE:       //cmd as the same with COMMAND_PROGRAM_EXECUTE
++            spi_cmd.spi_addr = (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_2BYTE;
++
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_WINBOND_QUAD_WRITE_PAGE:
++        case COMMAND_QUAD_WRITE_PAGE:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_QUAD_MODE;
++            break;
++        case COMMAND_FAST_READ_QUAD_IO:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++
++            spi_cmd.dum_2nd_cyc = 4;
++            spi_cmd.conti_read_mode_en = 1;
++            spi_cmd.conti_read_mode_code = 0;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_QUAD_MODE;
++            break;
++        case COMMAND_READ_DATA:
++        case COMMAND_FAST_READ:
++            spi_cmd.spi_addr = (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_2BYTE;
++
++            spi_cmd.dum_2nd_cyc = 8;
++            spi_cmd.conti_read_mode_en = 0;
++            spi_cmd.conti_read_mode_code = 0;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_FAST_READ_DUAL:
++            spi_cmd.spi_addr = (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_2BYTE;
++
++            spi_cmd.dum_2nd_cyc = 8;
++            spi_cmd.conti_read_mode_en = 0;
++            spi_cmd.conti_read_mode_code = 0;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_DUAL_MODE;
++            break;
++        case COMMAND_GET_FEATURES:
++            spi_cmd.spi_addr = (u32) * (u8_data_out + 1);
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_1BYTE;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.write_en = FTSPI020_CMD3_READ;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_EN;
++            spi_cmd.read_status = FTSPI020_CMD3_STS_SW_READ;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_PAGE_READ:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = 0;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        case COMMAND_PROGRAM_EXECUTE:
++            spi_cmd.spi_addr =
++                (*(u8_data_out + 3) << 16) | (*(u8_data_out + 2) << 8) | (*(u8_data_out + 1));
++            spi_cmd.addr_len = FTSPI020_CMD1_ADDR_3BYTE;
++            spi_cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++            spi_cmd.data_cnt = len;
++            spi_cmd.write_en = FTSPI020_CMD3_WRITE;
++            spi_cmd.read_status_en = FTSPI020_CMD3_RD_STS_DIS;
++            spi_cmd.dtr_mode = FTSPI020_CMD3_DTR_MODE_DIS;
++            spi_cmd.spi_mode = FTSPI020_CMD3_SERIAL_MODE;
++            break;
++        default:
++            printk(KERN_ERR "Not define this command 0x%x!!!!!!!\n", spi_cmd.ins_code);
++            goto xfer_exit;
++            break;
++        }
++        /* sent the command out */
++        ftspi020_issue_cmd(data, &spi_cmd);
++
++    }
++    else if (flags & SPI_XFER_DATA_IN_STATE) {
++        /* read the data */
++        //printk("read len = %d, buf = 0x%x\n", len, din);
++        ret = ftspi020_data_access(data, 1, (u8 *) din, len);
++        if(ret)
++            return ret;
++        ftspi_nand_dbg("read data finish\n");
++    }
++    else if (flags & SPI_XFER_DATA_OUT_STATE) {
++        /* send the data */
++        ftspi_nand_dbg("write len = %d, buf = 0x%x\n", len, dout);
++        ret = ftspi020_data_access(data, 0, (u8 *) dout, len);
++        if(ret)
++            return ret;        
++        ftspi_nand_dbg("write data finish\n");
++    }
++
++    /* check command complete */
++    if (flags & SPI_XFER_CHECK_CMD_COMPLETE)
++        ret = ftspi020_wait_cmd_complete(data);
++
++xfer_exit:
++    return ret;
++}
++
++/******************************************************************************
++ * workqueue
++ *****************************************************************************/
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++
++static int setup_dma(struct ftnandc023_nand_data *ctrl, int direct)
++{
++    struct dma_slave_config *common;
++
++    ctrl->dma_slave_config.id = -1;
++    ctrl->dma_slave_config.handshake = SPI020_REQ;      //enable
++
++    common = &ctrl->dma_slave_config.common;
++
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++    ctrl->dma_slave_config.src_size = FTDMAC020_BURST_SZ_4;     //64x4=256
++
++    if (direct == DMA_DEV_TO_MEM) {
++        ctrl->dma_slave_config.src_sel = AHBMASTER_R_SRC;
++        ctrl->dma_slave_config.dst_sel = AHBMASTER_R_DST;
++    } else {
++        ctrl->dma_slave_config.src_sel = AHBMASTER_W_SRC;
++        ctrl->dma_slave_config.dst_sel = AHBMASTER_W_DST;
++    }
++#else
++    common->dst_maxburst = 4;
++    common->src_maxburst = 4;
++#endif
++
++    if (direct == DMA_MEM_TO_DEV) {
++        common->src_addr = ctrl->mem_dmaaddr;
++        common->dst_addr = ctrl->nand_dmaaddr;
++    } else {
++        common->src_addr = ctrl->nand_dmaaddr;
++        common->dst_addr = ctrl->mem_dmaaddr;
++    }
++
++    /* SPI kernel maybe send len = 2011, so can't div 4 */
++    common->dst_addr_width = 1;
++    common->src_addr_width = 1;
++
++    common->direction = direct;
++
++    return dmaengine_slave_config(ctrl->dma_chan, common);      //step 2
++}
++
++static int spi020_dma_start(struct ftnandc023_nand_data *ctrl, size_t len, int direct)
++{
++    int ret;
++    enum dma_ctrl_flags flags;
++    struct dma_async_tx_descriptor *desc;
++
++    ret = setup_dma(ctrl, direct);
++    if (ret)
++        return ret;
++
++    flags =
++        DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++
++    desc = dmaengine_prep_slave_single(ctrl->dma_chan, (void *)ctrl->sg_dmabuf, len, direct, flags);    //step 3
++
++    if (!desc)
++        return -1;
++
++    desc->callback = ftspi020_dma_callback;
++    desc->callback_param = &ctrl;
++    ctrl->cookie = dmaengine_submit(desc);      //step 4
++    dma_async_issue_pending(ctrl->dma_chan);    //step 5
++
++    return 0;
++}
++
++static void ftspi020_dma_callback(void *param)
++{
++    //printk("<D>\n");
++
++    dma_trigger_flag = 1;
++    wake_up(&dma_queue);
++
++    return;
++}
++#endif
++
++/* direction: 1 is read, 0 is write */
++static int ftspi020_data_access(struct ftnandc023_nand_data *data, u8 direction, u8 * addr, u32 len)
++{
++    u32 *tmp;
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++    int ret = -1;
++#endif
++
++    tmp = (u32 *) addr;
++
++    if (direction) {
++        /* read direction */
++        if (len == IDCODE_LEN) {        // read ID
++            *tmp++ = *(volatile unsigned *)(data->chip.IO_ADDR_R);
++            return 0;
++        }
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++
++//printk("len=%d\n",len); 
++        ret = spi020_dma_start(data, len, DMA_DEV_TO_MEM);
++        if (ret < 0) {
++            printk(KERN_ERR "spi020 dma read fail\n");
++            return ret;
++        }
++
++        if(ftspi020_dma_wait())
++            return ret;
++
++        memcpy(addr, data->mem_dmabuf, len);
++#else
++        {
++            int i, j, tmp_size;
++            //printk("len = %d, one time %d, tmp = 0x%x\n",len,data->rxfifo_depth * 4, tmp);
++
++            tmp_size = len % (data->rxfifo_depth * 4);
++            //read 2048 bytes       
++            for (i = 0; i < (len / (data->rxfifo_depth * 4)); i++) {
++                ret = ftspi020_wait_rxfifo_ready(data->io_base);
++                if(ret)
++                    return ret;                
++                for (j = 0; j < data->rxfifo_depth; j++, tmp++) {
++                    *tmp = inl(data->io_base + 0x100);
++                    //printk("<%x>", *tmp);
++                }
++                //printk("\n");
++            }
++            //read 64 bytes
++            if (tmp_size) {
++                ret = ftspi020_wait_rxfifo_ready(data->io_base);
++                if(ret)
++                    return ret;                  
++                for (i = 0; i < (tmp_size / 4); i++, tmp++) {
++                    *tmp = inl(data->io_base + 0x100);
++                    //printk("<%x>", *tmp);
++                }
++            }
++            //printk("\n");
++        }
++#endif
++    } else {
++        /* write direction */
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++
++        memcpy(data->mem_dmabuf, addr, len);
++        ret = spi020_dma_start(data, len, DMA_MEM_TO_DEV);
++        if (ret < 0) {
++            printk(KERN_ERR "spi020 dma write fail\n");
++            return ret;
++        }
++        if(ftspi020_dma_wait())
++            return ret;
++#else
++        int i, j, tmp_size;
++
++        tmp_size = len % (data->txfifo_depth * 4);
++        //write 2048 bytes      
++        for (i = 0; i < (len / (data->txfifo_depth * 4)); i++) {
++            ret = ftspi020_wait_txfifo_ready(data->io_base);
++            if(ret)
++                return ret;
++            for (j = 0; j < data->txfifo_depth; j++, tmp++)
++                //*(volatile u32 *)(data->chip.IO_ADDR_R) = *tmp++;
++                outl(*tmp, data->io_base + 0x100);
++        }
++        //write 64 bytes
++        //*tmp = 0xFF;//good block//??? set bad block?
++        if (tmp_size) {
++            ret = ftspi020_wait_txfifo_ready(data->io_base);
++            if(ret)
++                return ret;
++            for (i = 0; i < (tmp_size / 4); i++, tmp++) {
++                outl(*tmp, data->io_base + 0x100);
++                //printk("<%x>", *tmp);
++            }
++        }
++#endif
++    }
++    return 0;
++}
++
++static inline struct common_spi_flash *mtd_to_common_spi_flash(struct mtd_info *mtd)
++{
++    return container_of(mtd, struct common_spi_flash, 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 common_spi_flash *flash, u8 ins_cmd)
++{
++    u8 val;
++    struct ftspi020_cmd cmd[2];
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    memset(&cmd[0], 0, sizeof(struct ftspi020_cmd));
++    cmd[0].ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd[0].write_en = FTSPI020_CMD3_READ;
++    cmd[0].read_status_en = FTSPI020_CMD3_RD_STS_EN;
++    cmd[0].read_status = FTSPI020_CMD3_STS_SW_READ;
++    cmd[0].ins_code = FTSPI020_CMD3_INSTR_CODE(ins_cmd);
++    cmd[0].flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    memset(&cmd[1], 0, sizeof(struct ftspi020_cmd));
++    cmd[1].rx_buf = &val;
++    cmd[1].data_cnt = 1;
++    cmd[1].read_status_en = FTSPI020_CMD3_RD_STS_EN;
++    cmd[1].read_status = FTSPI020_CMD3_STS_SW_READ;;
++    cmd[1].flags = FTSPI020_XFER_DATA_STATE;
++
++    return val;
++}
++
++/*
++ * Write status register 1 byte
++ * Returns negative if error occurred.
++ */
++static int write_sr(struct common_spi_flash *flash, u8 * val, u8 len)
++{
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WRSR);
++    cmd.tx_buf = val;
++    cmd.data_cnt = len;
++    cmd.flags =
++        (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_DATA_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    return 0;
++}
++
++static inline int change_4b(struct common_spi_flash *flash, u8 val)
++{
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    if (val)
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_EN4B);
++    else
++        cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_EX4B);
++        
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    return 0;
++}
++
++/*
++ * Set write enable latch with Write Enable command.
++ * Returns negative if error occurred.
++ */
++static inline int write_enable(struct common_spi_flash *flash)
++{
++    struct ftspi020_cmd cmd;
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    memset(&cmd, 0, sizeof(struct ftspi020_cmd));
++    cmd.ins_len = FTSPI020_CMD1_OP_CODE_1_BYTE;
++    cmd.write_en = FTSPI020_CMD3_WRITE;
++    cmd.ins_code = FTSPI020_CMD3_INSTR_CODE(OPCODE_WREN);
++    cmd.flags = (FTSPI020_XFER_CMD_STATE | FTSPI020_XFER_CHECK_CMD_COMPLETE);
++
++    return 0;
++}
++
++/*
++ * Service routine to read status register until ready, or timeout occurs.
++ * Returns non-zero if error.
++ */
++static int wait_till_ready(struct common_spi_flash *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++) {
++        if ((sr = read_sr(flash, OPCODE_RDSR)) < 0)
++            break;
++        else if (!(sr & SR_WIP))
++            return 0;
++
++        /* REVISIT sometimes sleeping would be best */
++        ndelay(10);
++    }
++
++    return 1;
++}
++
++static inline int flash_set_quad_enable(struct common_spi_flash *flash)
++{
++    u8 sr[2];
++
++    pr_debug("%s: %s\n", dev_name(&flash->spi->dev), __func__);
++
++    /* Wait until finished previous write command. */
++    if (wait_till_ready(flash))
++        return 1;
++
++    if ((sr[0] = read_sr(flash, OPCODE_RDSR)) < 0)
++        return 1;
++
++    if (flash->flash_type == 1) {       //winbond
++        if ((sr[1] = read_sr(flash, OPCODE_RDSR2)) < 0)
++            return 1;
++        if (sr[1] & (1 << 1))   //has enable
++            return 0;
++    } else {
++        if (sr[0] & (1 << 6))   //has enable
++            return 0;
++    }
++    /* Send write enable, then erase commands. */
++    write_enable(flash);
++    
++    if (flash->flash_type == 1) //winbond
++        write_sr(flash, &sr[0], 2);
++    else
++        write_sr(flash, &sr[0], 1);
++
++    return 0;
++}
++
++static int partition_check(struct mtd_partition *partitions, struct ftnandc023_nand_data *data,
++                           int block_size)
++{
++    int i, num = 1;
++    int j, A_begin, A_end, B_begin, B_end;
++    unsigned int backup_offset = 0, addr;
++
++    spi_nand_sys_header_t *sys_hdr;
++
++    sys_hdr = data->sys_hdr;
++
++    if (sys_hdr->image[0].size == 0) {
++        printk(KERN_WARNING "Warning...Not find partition message, use default setting\n");
++        partitions[0].name = "a";
++        partitions[0].offset = 0x140000;
++        partitions[0].size = 0x200000;
++
++        partitions[1].name = "b";
++        partitions[1].offset = 0x500000;
++        partitions[1].size = 0x200000;
++
++        num = 2;
++    } else {
++        for (i = 0; i < ARRAY_SIZE(ftnandc023_partition_info); i++) {
++            if ((sys_hdr->image[i].size == 0) || ((sys_hdr->image[i].addr % block_size) != 0)) //compatible with 8136, so set 2048
++                continue;
++
++            partitions[num].offset = sys_hdr->image[i].addr + backup_offset;
++
++            partitions[num].size = sys_hdr->image[i].size;
++            partitions[num].name = sys_hdr->image[i].name;
++ 
++            //printk("MTD%d addr = 0x%x, size = 0x%x\n", num, (unsigned int)partitions[num].offset, (unsigned int)sys_hdr->image[i].size);     
++            if (sys_hdr->image[i].addr % block_size) {
++                printk(KERN_WARNING "Warning... partition %d addr 0x%x not block alignment, one block = 0x%x\n",
++                       i, sys_hdr->image[i].addr, block_size);
++                partitions[i].offset = BLOCK_ALIGN(sys_hdr->image[i].addr, block_size);
++            }
++            if (sys_hdr->image[i].size % block_size) {
++                printk(KERN_WARNING "Warning... partition %d size 0x%x not block alignment, one block = 0x%x\n",
++                       i, sys_hdr->image[i].size, block_size);
++                partitions[i].size = BLOCK_ALIGN(sys_hdr->image[i].size, block_size);
++            }
++            if(data->lookup_flag) {
++            	addr = sys_hdr->image[i].addr + partitions[i].size;
++            	if(addr > data->nand_parm.page_size * data->nand_parm.block_pg * data->block_limit)
++            		printk(KERN_WARNING "Warning... partition %d addr 0x%x overlap with reserve addr 0x%x to end\n", i, addr, data->nand_parm.page_size * data->nand_parm.block_pg * data->block_limit);
++        	}
++            num++;
++        }
++#if 0
++        /* system header image */
++        partitions[0].offset = 0;
++        partitions[0].size = block_size;
++        partitions[0].name = "SYSHDR";
++#endif
++        /* nsboot image */
++        partitions[0].offset = block_size;
++        partitions[0].size = block_size;
++        partitions[0].name = "NSBOOT";
++
++        for (i = 0; i < ARRAY_SIZE(ftnandc023_partition_info); i++)
++            ftspi_nand_dbg("partation %d addr = 0x%x, size = 0x%x, name = %s\n", i,
++                           sys_hdr->image[i].addr, sys_hdr->image[i].size, sys_hdr->image[i].name);
++
++    //overlap check
++    for (i = 0; i < (num - 3); i++) {
++        A_begin = partitions[i].offset;
++        A_end = A_begin + partitions[i].size;
++        //printk("A %x,%x\n",A_begin,A_end);
++
++        for (j = (i + 1); j < num; j++) {
++            B_begin = partitions[j].offset;
++            B_end = B_begin + partitions[j].size;
++            //printk("B %x,%x\n",B_begin,B_end);
++
++            /* A_end between B_end and B_begin */
++            if ((B_end >= A_end) && (A_end > B_begin))
++                goto check_fail;
++            /* A_begin between B_end and B_begin */
++            if ((B_end > A_begin) && (A_begin >= B_begin))
++                goto check_fail;
++            /* B between A */
++            if ((A_end >= B_end) && (B_begin >= A_begin))
++                goto check_fail;
++        }
++    }
++    }
++    return num;
++check_fail:
++    printk(KERN_WARNING "Warning ============> partition %d overlap with %d\n", i, j);
++    return num;
++}
++
++/* low enable write protect, high disable write protect */
++static void write_protect(int mode)
++{
++#ifdef CONFIG_GPIO_WP
++    if (mode)
++        gpio_direction_output(GPIO_PIN, 0);
++    else
++        gpio_direction_output(GPIO_PIN, 1);
++#endif
++}
++
++int spi020_flash_cmd(struct ftnandc023_nand_data *data, uint8_t * u8_cmd, void *response,
++                     size_t len)
++{
++    int ret;
++
++    ret = spi_xfer(data, len, u8_cmd, NULL, SPI_XFER_CMD_STATE | SPI_XFER_CHECK_CMD_COMPLETE);
++    if (ret) {
++        printk(KERN_ERR "SF: Failed to send command %02x: %d\n", u8_cmd[0], ret);
++        return ret;
++    }
++
++    if (len && response != NULL) {
++        ret = spi_xfer(data, len, NULL, response, SPI_XFER_DATA_IN_STATE);
++        if (ret) {
++            printk(KERN_ERR "SF: Failed to read response (%zu bytes): %d\n", len, ret);
++        }
++    } else if ((len && response == NULL) || (!len && response != NULL)) {
++        printk
++            (KERN_ERR "SF: Failed to read response due to the mismatch of len and response (%zu bytes): %d\n",
++             len, ret);
++    }
++
++    return ret;
++}
++
++/* Wait until BUSY bit clear
++ */
++static int flash_wait_busy_ready(struct ftnandc023_nand_data *data)
++{
++    unsigned long timeo = jiffies;
++    u8 rd_sts_cmd[1];
++    u8 status = 0xFF;
++
++    rd_sts_cmd[0] = COMMAND_GET_FEATURES;
++    rd_sts_cmd[1] = 0xC0;
++
++    timeo += (10 * HZ);
++    while (time_before(jiffies, timeo)) {
++        if (spi020_flash_cmd(data, rd_sts_cmd, NULL, 0)) {
++            printk(KERN_ERR "Failed to check status!\n");
++            break;
++        }
++
++        status = ftspi020_read_status(data->io_base);
++        if (!(status & FLASH_STS_BUSY))
++            break;
++    };
++    if (status & FLASH_STS_BUSY) {
++        printk(KERN_ERR "Wait bus busy timeout!\n");
++        return 0xFF;
++    } else {
++        ftspi_nand_dbg("get feature = 0x%x\n", status);
++        //printk("<get feature = 0x%x>", status);
++    }
++
++    return status;
++}
++
++static int ftnandc023_nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
++{
++    ftspi_nand_dbg("%s\n", __FUNCTION__);
++    return cmdfunc_status;
++}
++
++static int ftnandc023_available_oob(struct ftnandc023_nand_data *data)
++{
++    int ret = 0;
++
++    ret = data->chip.ecc.layout->oobfree[0].length * 4;
++
++        /*----------------------------------------------------------
++	 * YAFFS require 16 bytes OOB without ECC, 28 bytes with
++	 * ECC enable.
++	 * BBT require 5 bytes for Bad Block Table marker.
++	 */
++#ifdef CONFIG_YAFFS_FS
++    if (ret >= 16) {
++        printk(KERN_INFO "NAND(YAFFS): avaliable OOB is %d byte.\n", ret);
++    } else {
++        printk(KERN_INFO
++               "NAND: Not enough OOB:%d bytes(YAFFS requires 16 bytes without software ECC, "
++               "28 bytes with ECC enable), try to reduce ECC correction bits.\n", ret);
++    }
++#else
++    printk(KERN_INFO "Avaliable OOB is %d byte.\n", ret);
++#endif
++    return ret;
++}
++
++static void nand_read_buffer(struct ftnandc023_nand_data *data, int cmd, u_char * buf, int len)
++{
++    if (cmd == NAND_CMD_READID) {
++        ftspi_nand_dbg("read_buffer ID\n");
++        ftspi020_data_access(data, 1, buf, IDCODE_LEN);
++        //*(u32 *)buf=0xF1C8F1C8;
++    }
++}
++
++static uint8_t ftnandc023_read_byte(struct mtd_info *mtd)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    uint8_t b = 0xFF;
++
++    ftspi_nand_dbg("%s, cmd = 0x%x\n", __FUNCTION__, data->cur_cmd);
++
++    switch (data->cur_cmd) {
++    case NAND_CMD_READID:
++        if (read_id_time == 0) {
++            //buf = *(u32 *)(data->chip.IO_ADDR_R)
++
++            nand_read_buffer(data, NAND_CMD_READID, idcode, IDCODE_LEN);
++            ftspi_nand_dbg("ID = 0x%x,0x%x,0x%x,0x%x\n", idcode[0], idcode[1], idcode[2],
++                           idcode[3]);
++
++            read_id_time = 1;
++        }
++        b = idcode[ID_point++];
++        break;
++    case NAND_CMD_STATUS:
++        /* fail to return 0 */
++        ftspi_nand_dbg("NAND_CMD_STATUS\n");    //not need to implement, r/w/e already do it.
++        break;
++    }
++    
++    return b;
++}
++
++int log_to_phy(struct ftnandc023_nand_data *data, int page_addr)
++{
++    int log_block_num, phy_block_num, ren, new_page_addr;
++    
++    log_block_num = page_addr / data->nand_parm.block_pg;
++    ren = page_addr % data->nand_parm.block_pg;
++
++    /* read system header and lookup tab */
++    if(log_block_num == 0)
++        return page_addr;
++
++    phy_block_num = data->lookup_table->physical[log_block_num];
++
++    if(phy_block_num > 0x8000) {
++        printk(KERN_WARNING "Block %d not be mapping\n", log_block_num);
++        return 0x0FFFFFFF;
++    } else if(phy_block_num == 0xFFFF) {
++        printk(KERN_WARNING "Block %d is bad\n", log_block_num);
++        return 0x0FFFFFFF;
++    }
++
++    new_page_addr = phy_block_num * data->nand_parm.block_pg + ren;
++    
++    ftspi_nand_dbg("page in = %d, log_b = %d, phy_b = %d, page out = %d\n", page_addr, log_block_num, phy_block_num, new_page_addr);
++    return new_page_addr;
++}
++
++static int ftnandc023_nand_read_oob_lp(struct mtd_info *mtd, u_char * buf)
++{
++    int ret, new_page;    
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("%s\n", __FUNCTION__);
++
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, data->page_addr);
++        ftspi_nand_dbg("read_oob page num logical = %d, physical = %d\n", data->page_addr, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to write bad block\n");
++            return -1;
++        }
++        data->page_addr = new_page;
++    }
++    else
++        data->page_addr = calc_new_page(mtd, data->page_addr);
++
++	ret = spi_flash_cmd_read_fast(data, data->page_addr, mtd->oobsize, buf);
++
++    if(ret) {
++        cmdfunc_status = NAND_STATUS_FAIL;
++        return -EIO;
++    } else {
++        cmdfunc_status = NAND_STATUS_READY;
++        return 0;
++    }
++}
++
++static int ftnandc023_nand_read_oob_sp(struct mtd_info *mtd, u_char * buf)
++{
++    printk("%s: not implement.\n", __FUNCTION__);
++    return 0;
++}
++
++static int ftnandc023_nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("read oob page = 0x%x\n", page);
++    data->page_addr = page;
++
++    return data->read_oob(mtd, chip->oob_poi);
++}
++
++static int spi020_flash_cmd_write(struct ftnandc023_nand_data *spi, u8 * u8_cmd, const void *data, int data_len)
++{
++    int ret;
++
++    ret = spi_xfer(spi, data_len, u8_cmd, NULL, SPI_XFER_CMD_STATE);
++    if (ret) {
++        printk(KERN_ERR "SF: Failed to send command %02x: %d\n", u8_cmd[0], ret);
++        return ret;
++    } else if (data_len != 0) {
++        ret = spi_xfer(spi, data_len, data, NULL, SPI_XFER_DATA_OUT_STATE | SPI_XFER_CHECK_CMD_COMPLETE);       //SPI_XFER_CHECK_CMD_COMPLETE);
++        if (ret) {
++            printk(KERN_ERR "SF: Failed to write data (%zu bytes): %d\n", data_len, ret);
++        }
++    }
++
++    return ret;
++}
++
++static int spi020_flash_cmd_read(struct ftnandc023_nand_data *spi, uint8_t * u8_cmd, void *data, int data_len)
++{
++    int ret;
++
++    ret = spi_xfer(spi, data_len, u8_cmd, NULL, SPI_XFER_CMD_STATE);
++//printk("spi020_flash_cmd_read cmd=0x%x,len=0x%x\n",*u8_cmd,data_len);    
++    if (ret) {
++        printk(KERN_ERR "SF: Failed to send command %02x: %d\n", u8_cmd[0], ret);
++    } else if (data_len != 0) {
++        //printk("A0\n");
++        ret =
++            spi_xfer(spi, data_len, NULL, data,
++                     SPI_XFER_DATA_IN_STATE | SPI_XFER_CHECK_CMD_COMPLETE);
++        if (ret) {
++            printk(KERN_ERR "SF: Failed to read data (%zu bytes): %d\n", data_len, ret);
++        }
++    }
++
++    return ret;
++}
++
++static int spi_flash_read_write(struct ftnandc023_nand_data *spi,
++                                const u8 * cmd, size_t cmd_len,
++                                const u8 * data_out, u8 * data_in, size_t data_len)
++{
++    unsigned long flags;
++    int ret;
++
++    if (data_len == 0)
++        flags = (SPI_XFER_CMD_STATE | SPI_XFER_CHECK_CMD_COMPLETE);     //(SPI_XFER_END | SPI_XFER_CHECK_CMD_COMPLETE);
++
++    ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
++    
++    if (ret) {
++        printk(KERN_ERR "SF: Failed to send command (%zu bytes): %d\n", cmd_len, ret);
++    } else if (data_len != 0) {
++        if (data_in == NULL) {  // write
++            if (data_len % 4) {
++                if (*cmd != COMMAND_WRITE_STATUS)
++                    printk(KERN_WARNING "data len %x not 4 times\n", data_len);
++                return ret;
++            }
++        }
++        ret = spi_xfer(spi, data_len * 8, data_out, data_in, SPI_XFER_CHECK_CMD_COMPLETE);      //SPI_XFER_END, 0);
++        if (ret)
++            printk(KERN_ERR "SF: Failed to transfer %zu bytes of data: %d\n", data_len, ret);
++    }
++
++    return ret;
++}
++
++static int spi_flash_cmd(struct ftnandc023_nand_data *spi, u8 * cmd, void *response, size_t len)
++{
++    return spi_flash_read_write(spi, cmd, 1, NULL, response, len);
++}
++
++#ifdef CONFIG_NAND_DISTRUB
++int read_ecc_limit = 0;
++volatile int mm = 0;
++#endif
++
++static int spi_flash_cmd_read_fast(struct ftnandc023_nand_data *data, u32 offset, size_t len, u8 *buf)
++{
++    int ret;
++    u8 u8_rd_cmd[5], status = 0;
++
++    /* send PAGE READ command first for SPI NAND */
++    //flash_wait_busy_ready(flash);
++
++    memset(u8_rd_cmd, 0, 5);
++    u8_rd_cmd[0] = COMMAND_PAGE_READ;
++    /* assign row address */
++    u8_rd_cmd[1] = offset & 0xFF;
++    u8_rd_cmd[2] = ((offset & 0xFF00) >> 8);
++    u8_rd_cmd[3] = ((offset & 0xFF0000) >> 16);
++
++    ret = spi_flash_cmd(data, u8_rd_cmd, NULL, 0);
++    if (ret) {
++        printk(KERN_ERR "Read fast fail\n");
++        return ret;
++    }
++    
++    /* check if the flash is busy */
++    status = flash_wait_busy_ready(data);
++    if ((status & FLASH_NAND_R_FIELD ) == FLASH_NAND_R_FAIL) {
++        printk(KERN_ERR "read offset = 0x%x ECC fail\n", offset * data->nand_parm.page_size);
++#if 0//debug all good
++        if(data->nand_parm.spare_size == len)
++            *buf = 0xFF;
++        return 0;
++#else         
++        return 1;
++#endif
++    }
++
++#ifdef CONFIG_NAND_DISTRUB
++#if 1    
++    if ((status & FLASH_NAND_R_FIELD ) == data->ecc_type)//justin
++    	read_ecc_limit = 1;
++#else //debug
++    mm++;
++    if(mm < 5)
++    	read_ecc_limit = 1;
++#endif
++#endif
++
++    memset(u8_rd_cmd, 0, 5);
++
++#ifdef CONFIG_SPI_QUAD
++    flash_set_quad_enable(data, 1);
++    u8_rd_cmd[0] = COMMAND_FAST_READ_QUAD_IO;
++#else
++	if(idcode[0] == 0x9B)        //ATO not have COMMAND_FAST_READ_DUAL mode
++		u8_rd_cmd[0] = COMMAND_FAST_READ;
++   	else
++		u8_rd_cmd[0] = COMMAND_FAST_READ_DUAL;
++#endif
++
++    /* assign column address */
++    if (len == data->nand_parm.spare_size) {
++        u8_rd_cmd[1] = data->nand_parm.page_size & 0xFF;
++        u8_rd_cmd[2] = ((data->nand_parm.page_size & 0xFF00) >> 8);
++    } else {
++        u8_rd_cmd[1] = 0x00;
++        u8_rd_cmd[2] = 0x00;
++    }    
++
++    ret = spi020_flash_cmd_read(data, u8_rd_cmd, buf, len);
++
++    return ret;
++}
++
++/* 0 is good, 1 is bad */
++static int check_bbt(struct mtd_info *mtd, loff_t offs)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    unsigned int *bi_table = (unsigned int *)data->bi_table;
++    int quotient, remainder, blk_id, result, ret = 0;
++
++    if(!data->lookup_flag) {
++        blk_id = offs >> chip->bbt_erase_shift;
++        quotient = blk_id >> 5;
++        remainder = blk_id & 0x1F;
++        result = (bi_table[quotient] >> remainder) & 0x1;
++        
++        if (result != 1)
++            ret = 1;
++    }
++    return ret;
++}
++
++static int calc_new_page(struct mtd_info *mtd, int page_addr)
++{
++    unsigned int start_addr, end_addr, check_addr, tmp_addr, bad_num = 0;
++    unsigned int block_page_num = mtd->erasesize / mtd->writesize;
++    struct nand_chip *chip = mtd->priv;
++
++    if (root_mtd_num != 0xFFFF) {// is squashfs
++        start_addr = ftnandc023_partition_info[root_mtd_num].offset;
++        end_addr = ftnandc023_partition_info[root_mtd_num].size + start_addr;
++        //printk("squash start addr = 0x%x, end addr = 0x%x\n", start_addr, end_addr); 
++
++        check_addr = page_addr * mtd->writesize;
++        
++        if((check_addr >= start_addr) && (check_addr < end_addr)) {
++            tmp_addr = start_addr;
++            
++            /* have bad block between start to here? */
++            while (check_addr >= tmp_addr) {
++                if(check_bbt(mtd, (loff_t) tmp_addr) != 0) {
++                    bad_num++;
++                    //printk("<ba=0x%x>", tmp_addr);
++                }
++
++                tmp_addr += (0x1 << chip->bbt_erase_shift);
++            }
++            
++            /* move n good block */
++            if(bad_num) {
++                //printk("<br0x%x,bad=%d>",page_addr,bad_num);
++                while(bad_num) {
++                    //printk("<tmp_page = 0x%x>", tmp_addr / mtd->writesize);
++                    if(check_bbt(mtd, (loff_t) tmp_addr) == 0)
++                        bad_num--;
++    
++                    tmp_addr += (0x1 << chip->bbt_erase_shift);
++                    page_addr += block_page_num;                    
++                }
++                //printk("<a=0x%x>\n",page_addr);
++            }                        
++        } else {
++                while(check_bbt(mtd, (loff_t) (page_addr * mtd->writesize)))
++                    page_addr += block_page_num;
++        }
++    }
++
++    return page_addr;
++}
++
++static int ftnandc023_nand_read_page_lp(struct mtd_info *mtd, u_char * buf)
++{
++    int ret, new_page;
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("r:page = 0x%x, size = %d\n", data->page_addr, mtd->writesize);
++
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, data->page_addr);
++        ftspi_nand_dbg("read_page page num logical = %d, physical = %d\n", data->page_addr, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to write bad block\n");
++            return -1;
++        }
++        data->page_addr = new_page;
++    }
++    else
++        data->page_addr = calc_new_page(mtd, data->page_addr);
++    
++    //spi_flash_cmd_read_fast(data, data->page_addr, data_len, data->chip.buffers->databuf);
++    //memcpy(buf, data->chip.buffers->databuf, mtd->writesize);
++    
++    /* nand_do_read_ops will reserve data->chip.buffers->databuf data last time, can't be overlap */
++    ret = spi_flash_cmd_read_fast(data, data->page_addr, mtd->writesize, buf);
++    if(ret) {
++        cmdfunc_status = NAND_STATUS_FAIL;
++        return -EIO;
++    } else {
++        cmdfunc_status = NAND_STATUS_READY;
++        return 0;
++    }
++}
++
++static int ftnandc023_nand_read_page_sp(struct mtd_info *mtd, u_char * buf)
++{
++    printk("%s: not implement.\n", __FUNCTION__);
++    return 0;
++}
++
++static int ftnandc023_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf,
++                                     int page)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("%s, page = 0x%x\n", __FUNCTION__, page);
++    data->buf = (u32 *) buf;
++    data->page_addr = page;
++
++    return data->read_page(mtd, buf);
++}
++
++static int spi_flash_cmd_write(struct ftnandc023_nand_data *data, u32 offset, size_t len,
++                        const uint8_t * buf)
++{
++    int ret = 1;
++    u8 u8_wr_en_cmd[1], u8_wr_cmd[5];
++    u8 *u8_buf = (u8 *) buf;
++
++    /* check if the flash is busy */
++    //flash_wait_busy_ready(flash);
++
++#ifdef CONFIG_SPI_QUAD
++    ret = flash_set_quad_enable(data, 1);
++    if (ret)
++        goto prog0_exit;
++#endif
++
++    u8_wr_en_cmd[0] = COMMAND_WRITE_ENABLE;
++    if (spi020_flash_cmd(data, u8_wr_en_cmd, NULL, 0)) {
++        printk(KERN_ERR "COMMAND_WRITE_ENABLE fail\n");
++        goto prog_exit;
++    }
++
++    /* send PROGRAM LOAD command for SPI NAND */
++    u8_wr_cmd[0] = COMMAND_PROGRAM_LOAD;
++    /* assign column address */
++    if (len == data->nand_parm.spare_size) {
++        u8_wr_cmd[1] = data->nand_parm.page_size & 0xFF;
++        u8_wr_cmd[2] = ((data->nand_parm.page_size & 0xFF00) >> 8);
++    } else {
++        u8_wr_cmd[1] = 0x00;
++        u8_wr_cmd[2] = 0x00;
++    }
++
++    ret = spi020_flash_cmd_write(data, u8_wr_cmd, u8_buf, len);
++    if (ret) {
++        printk(KERN_ERR "COMMAND_WRITE_ENABLE fail\n");
++        goto prog_exit;
++    }
++    //ftspi020_wait_cmd_complete(data);
++
++#ifdef CONFIG_SPI_QUAD
++    //only for QUAD_PROGRAM
++    if (data->chip_type)
++        u8_wr_cmd[0] = COMMAND_WINBOND_QUAD_WRITE_PAGE;
++    else
++        u8_wr_cmd[0] = COMMAND_QUAD_WRITE_PAGE;
++#else
++    u8_wr_cmd[0] = COMMAND_PROGRAM_EXECUTE;
++#endif
++
++    /* assign row address */
++    u8_wr_cmd[1] = offset & 0xFF;
++    u8_wr_cmd[2] = ((offset & 0xFF00) >> 8);
++    u8_wr_cmd[3] = ((offset & 0xFF0000) >> 16);
++
++    if (spi020_flash_cmd(data, u8_wr_cmd, NULL, 0)) {
++        printk(KERN_ERR "COMMAND_PROGRAM_EXECUTE fail\n");
++        goto prog_exit;
++    }
++
++    if (flash_wait_busy_ready(data) & FLASH_NAND_P_FAIL) {
++        printk(KERN_ERR "program result fail\n");
++        ret = 1;
++    } else
++        ret = 0;       
++        
++prog_exit:
++    return ret;
++}
++
++static int ftnandc023_nand_write_oob_lp(struct mtd_info *mtd, const uint8_t * buf, int len)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    int ret, new_page;
++
++    ftspi_nand_dbg("oob w:page = 0x%x, size = %d, data = 0x%x\n", data->page_addr, len, *buf);
++
++    //memcpy(data->chip.buffers->databuf + FLASH_NAND_PAGE_SZ, buf, mtd->oobsize);
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, data->page_addr);
++        ftspi_nand_dbg("write_oob page num logical = %d, physical = %d\n", data->page_addr, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to write bad block\n");
++            return -1;
++        }
++        data->page_addr = new_page;
++    }
++
++	ret = spi_flash_cmd_write(data, data->page_addr, mtd->oobsize, buf);	
++    if(ret) {
++        cmdfunc_status = NAND_STATUS_FAIL;
++        return -EIO;
++    } else {
++        cmdfunc_status = NAND_STATUS_READY;
++        return 0;
++    }
++}
++
++static int ftnandc023_nand_write_oob_sp(struct mtd_info *mtd, const u_char * buf, int len)
++{
++    printk("%s: not implement.\n", __FUNCTION__);
++    return 0;
++}
++
++#if 0
++static int ftnandc023_nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    printk("write oob page = 0x%x\n", page);
++    data->page_addr = page;
++
++    memcpy(data->chip.buffers->databuf + FLASH_NAND_PAGE_SZ, chip->oob_poi, mtd->oobsize);
++    data->write_page(mtd, data->chip.buffers->databuf);
++
++    printk("ddw = 0x%x, 0x%x, 0x%x\n", *(u32 *) chip->oob_poi, *(u32 *) (chip->oob_poi + 1),
++           *(u32 *) (chip->oob_poi + 2));
++    return true;                //data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++}
++#else
++static int ftnandc023_nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page)
++{
++    struct ftnandc023_nand_data *data = chip->priv;
++    //u32 *tmp = (u32 *)chip->oob_poi;
++
++    ftspi_nand_dbg("write oob page = 0x%x\n", page);
++    data->page_addr = page;
++
++    //printk("ddw = 0x%x, 0x%x, 0x%x\n", *tmp, *(tmp + 1), *(tmp + 2));
++    return data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++}
++#endif
++
++static int ftnandc023_nand_write_page_lp(struct mtd_info *mtd, const uint8_t * buf)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    int ret, new_page;
++
++    ftspi_nand_dbg("lp w:page = 0x%x, size = %d, data->column = %d,0x%x\n", data->page_addr,
++                   mtd->writesize, data->column, *buf);
++
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, data->page_addr);
++        ftspi_nand_dbg("write_page page num logical = %d, physical = %d\n", data->page_addr, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to write bad block\n");
++            return -1;
++        }
++        data->page_addr = new_page;
++    }
++  
++    ret = spi_flash_cmd_write(data, data->page_addr, mtd->writesize, buf);    
++#if 0//debug
++	if(mm == 0) {
++		mm ++;
++		return -1;
++	} else {
++		return 0;
++	}
++#else
++    if(ret) {
++        cmdfunc_status = NAND_STATUS_FAIL;
++        return -EIO;
++    } else {
++        cmdfunc_status = NAND_STATUS_READY;
++        return 0;
++    }
++#endif
++}
++
++static int ftnandc023_nand_write_page_sp(struct mtd_info *mtd, const uint8_t * buf)
++{
++    printk("%s: not implement.\n", __FUNCTION__);
++    return 0;
++}
++
++static int ftnandc023_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++                                      const uint8_t * buf, int page, int cached, int raw)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc023_nand_data *data = p->priv;
++    int status = 0;
++
++    ftspi_nand_dbg("%s, page = 0x%x\n", __FUNCTION__, page);
++    data->page_addr = page;
++
++    status = data->write_page(mtd, buf);
++
++    return status;
++}
++
++static void ftnandc023_nand_write_page_lowlevel(struct mtd_info *mtd,
++                                                struct nand_chip *chip, const uint8_t * buf)
++{
++}
++
++/* offset: byte offset
++ * len: how many bytes.
++ */
++static int spi_flash_cmd_erase(struct ftnandc023_nand_data *data, u32 offset)
++{
++    int ret = 1, new_page;
++    u8 u8_er_cmd[5];
++
++    /* check if the flash is busy */
++    //flash_wait_busy_ready(data);
++    if(data->lookup_flag) {
++        new_page = log_to_phy(data, offset);
++        ftspi_nand_dbg("erase page num logical = %d, physical = %d\n", offset, new_page);
++        if(new_page == 0x0FFFFFFF) {
++            printk(KERN_ERR "Try to erase bad block\n");
++            return 1;
++        }
++        offset = new_page;
++    }
++
++    u8_er_cmd[0] = COMMAND_WRITE_ENABLE;
++    ret = spi020_flash_cmd(data, u8_er_cmd, NULL, 0);
++    if (ret) {
++        printk(KERN_ERR "cmd_erase write enable fail\n");
++        return ret;
++    }
++
++    u8_er_cmd[0] = COMMAND_ERASE_128K_BLOCK;
++    u8_er_cmd[1] = offset & 0xFF;
++    u8_er_cmd[2] = ((offset & 0xFF00) >> 8);
++    u8_er_cmd[3] = ((offset & 0xFF0000) >> 16);
++
++    ret = spi020_flash_cmd(data, u8_er_cmd, NULL, 0);
++    if (ret) {
++        printk(KERN_ERR "cmd_erase erase fail\n");
++        return ret;
++    }
++
++    /* check if the flash is busy */
++    if (flash_wait_busy_ready(data) & FLASH_NAND_E_FAIL) {
++        printk(KERN_ERR "erase result fail\n");
++        ret = 1;
++    } else
++        ret = 0;        
++
++#if 0//debug
++	if(mm == 0) {
++		mm ++;
++		ret = 1;
++	} else {
++		ret = 0;
++	}
++#endif
++    return ret;
++}
++
++static void ftnandc023_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
++                                    int column, int page_addr)
++{
++    int ret;
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++
++    ftspi_nand_dbg("%s, cmd = 0x%x\n", __func__, command);
++
++    data->cur_cmd = command;
++
++    switch (command) {
++    case NAND_CMD_READID:
++        {
++            ftspi020_cmd_t spi_cmd;
++
++            read_id_time = 0;
++            ID_point = 0;
++            ftspi020_setup_cmdq(data, &spi_cmd, COMMAND_READ_ID, FTSPI020_CMD1_OP_CODE_1_BYTE,
++                                FTSPI020_CMD3_READ, FTSPI020_CMD3_SERIAL_MODE, IDCODE_LEN);
++            ftspi020_wait_cmd_complete(data);
++        }
++        break;
++    case NAND_CMD_RESET:
++        break;
++    case NAND_CMD_STATUS:
++        break;
++    case NAND_CMD_ERASE1:
++        write_protect(0);
++        //DBGLEVEL2(ftnandc023_dbg("erase page: 0x%x\n", data->page_addr));
++        ftspi_nand_dbg("erase sector: 0x%x\n", page_addr);
++        ret = spi_flash_cmd_erase(data, page_addr);
++        if(ret)
++            cmdfunc_status = NAND_STATUS_FAIL;
++        else
++            cmdfunc_status = NAND_STATUS_READY;
++
++        break;
++    case NAND_CMD_ERASE2:
++    case NAND_CMD_PAGEPROG:
++    case NAND_CMD_SEQIN:
++        break;
++    }
++}
++
++/*
++ * Currently, we have pin mux with SD card
++ */
++static void ftnandc023_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++    struct nand_chip *p = mtd->priv;
++    struct ftnandc023_nand_data *data = p->priv;
++    int chn = 0;
++
++    //DBGLEVEL2(ftnandc023_dbg("chip = %d, ", chip));
++    if (data->scan_state != 1) {
++        while (chip != -1) {
++            if (chip < data->valid_chip[chn]) {
++                break;
++            } else {
++                chip = chip - data->valid_chip[chn];
++                chn++;
++            }
++        }
++        data->cur_chan = chn;
++    }
++#ifdef CONFIG_FTNANDC023_HYNIX_HY27US08561A
++    if (chip == 1)
++        data->sel_chip = 2;
++    else if (chip == 2)
++        data->sel_chip = 1;
++    else
++        data->sel_chip = chip;
++#else
++    data->sel_chip = chip;
++#endif
++
++    //DBGLEVEL2(ftnandc023_dbg("==>chan = %d, ce = %d\n", data->cur_chan, data->sel_chip));
++}
++
++/*
++ * Probe for the NAND device.
++ */
++static int __devinit ftspi020_nand_probe(struct platform_device *pdev)
++{
++    struct ftnandc023_nand_data *data;
++    struct mtd_partition *partitions;
++    int res, chipnum, size;
++    static struct resource *irq;
++    int i;
++    int partitions_num;
++
++    res = chipnum = size = 0;
++    /* Allocate memory for the device structure (and zero it) */
++    data = kzalloc(sizeof(struct ftnandc023_nand_data), GFP_KERNEL);
++    if (!data) {
++        dev_err(&pdev->dev, "failed to allocate device structure.\n");
++        res = -ENOMEM;
++        goto out;
++    }
++
++    data->io_base = ioremap_nocache(pdev->resource[0].start,
++                                    pdev->resource[0].end - pdev->resource[0].start + 1);
++    printk(KERN_INFO "SPI-NAND reg mapping to addr = 0x%x, phy = 0x%x\n", (u32) data->io_base,
++           (u32) pdev->resource[0].start);
++    if (data->io_base == NULL) {
++        dev_err(&pdev->dev, "ioremap failed for register.\n");
++        res = -EIO;
++        goto out_free_data;
++    }
++    
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    init_waitqueue_head(&dma_queue);
++    data->nand_dmaaddr = pdev->resource[0].start + 0x100;
++#endif
++
++    data->chip.IO_ADDR_R = data->io_base + 0x100;
++    printk(KERN_INFO "NAND data port mapping to addr = 0x%x\n", (u32) data->chip.IO_ADDR_R);
++
++    irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++    if (!irq) {
++        printk(KERN_ERR "no irq resource\n");
++        res = -ENODEV;
++        goto out_free_data;
++    }
++
++    setup_clk(data->io_base);
++
++    /* Currently, it is fixed in LEGACY_LARGE
++     */
++    legacy = LEGACY_LARGE;
++	data->flash_type = 0;
++    data->large_page = 1;
++    data->rxfifo_depth = ftspi020_rxfifo_depth(data->io_base);
++    data->txfifo_depth = ftspi020_txfifo_depth(data->io_base);
++    data->chip.priv = data;
++    data->mtd.priv = &data->chip;
++    data->mtd.owner = THIS_MODULE;
++    data->mtd.name = pdev->dev.init_name;
++    data->dev = &pdev->dev;
++    data->chip.IO_ADDR_W = data->chip.IO_ADDR_R;
++    data->chip.select_chip = ftnandc023_nand_select_chip;
++    data->chip.cmdfunc = ftnandc023_nand_cmdfunc;
++    data->chip.read_byte = ftnandc023_read_byte;
++    data->chip.write_page = ftnandc023_nand_write_page;
++    data->chip.waitfunc = ftnandc023_nand_wait;
++    data->chip.block_markbad = ftnandc023v2_block_markbad;
++    data->chip.chip_delay = 0;
++    //data->chip.options = NAND_BBT_USE_FLASH | NAND_NO_SUBPAGE_WRITE | NAND_OWN_BUFFERS;
++    data->chip.options = NAND_NO_SUBPAGE_WRITE | NAND_OWN_BUFFERS;      /* remove NAND_BBT_USE_FLASH */
++
++    platform_set_drvdata(pdev, data);
++
++    data->scan_state = 1;
++    
++    /* read ID disable DMA */
++    ftspi020_dma_disable(data->io_base);
++    
++    /* Scan to find existance of the device */
++    for (i = startchn; i < MAX_CHANNEL; i++) {
++        printk(KERN_INFO "NAND: Scan Channel %d...\n", i);
++        data->cur_chan = i;
++        if (!nand_scan_ident(&data->mtd, MAX_CE, NULL)) {
++            if ((0xFFFFFFFF - size) > (data->mtd.size)
++                && ((chipnum + data->chip.numchips) <= NAND_MAX_CHIPS)) {
++                data->valid_chip[i] = data->chip.numchips;
++                chipnum += data->chip.numchips;
++                size += (chipnum * data->chip.chipsize);
++            } else {
++                printk(KERN_INFO "Can not accept more flash chips.\n");
++                break;
++            }
++        }
++    }
++    printk(KERN_INFO "NAND: Scan Channel finish, chipnum = %d\n", chipnum);
++    if (chipnum == 0) {
++        res = -ENXIO;
++        goto out_unset_drv;
++    }
++    
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++    ftspi020_dma_enable(data->io_base);
++#endif
++
++    data->chip.numchips = chipnum;
++    data->mtd.size = size;
++    data->scan_state = 0;
++
++	data->ecc_type = FLASH_NAND_R_ECC_LIMIT;
++    if(idcode[1] == 0xF1) {	//GD5F1GQ4UA
++        data->chip.ecc.layout = &nand_1_hw_eccoob;
++    } else if(((idcode[0] == 0xC8) && (idcode[1] == 0x20)) || ((idcode[0] == 0xC8) && (idcode[1] == 0x21))){
++        data->chip.ecc.layout = &nand_2_hw_eccoob;
++    } else if((idcode[0] == 0xEF) || (idcode[0] == 0xC2)) {	//MXIC & Winbond
++        data->chip.ecc.layout = &nand_3_hw_eccoob;
++    } else if(idcode[0] == 0x91) {	//HY
++        data->chip.ecc.layout = &nand_4_hw_eccoob;
++    } else {	//GD5FxGQ4UB
++        data->chip.ecc.layout = &nand_0_hw_eccoob;
++        //data->ecc_type = FLASH_NAND_R_ECC_LIMIT_GD;
++    }
++    data->chip.bbt_td = &ftnandc023_bbt_main_descr;
++    data->chip.bbt_md = &ftnandc023_bbt_mirror_descr;
++    data->chip.badblock_pattern = &ftnandc023_largepage_flashbased;
++
++    data->ce = 0;               //???
++
++    data->chip.ecc.mode = NAND_ECC_HW;
++
++    data->chip.ecc.size = data->mtd.writesize;
++    data->chip.ecc.bytes = 0;
++    data->chip.ecc.read_page = ftnandc023_nand_read_page;
++    data->chip.ecc.write_page = ftnandc023_nand_write_page_lowlevel;
++    data->chip.ecc.read_oob = ftnandc023_nand_read_oob_std;
++    data->chip.ecc.write_oob = ftnandc023_nand_write_oob_std;
++    data->chip.ecc.read_page_raw = ftnandc023_nand_read_page;
++
++    if (data->large_page) {
++        data->read_page = ftnandc023_nand_read_page_lp;
++        data->write_page = ftnandc023_nand_write_page_lp;
++        data->read_oob = ftnandc023_nand_read_oob_lp;
++        data->write_oob = ftnandc023_nand_write_oob_lp;
++    } else {
++        data->read_page = ftnandc023_nand_read_page_sp;
++        data->write_page = ftnandc023_nand_write_page_sp;
++        data->read_oob = ftnandc023_nand_read_oob_sp;
++        data->write_oob = ftnandc023_nand_write_oob_sp;
++    }
++    
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    dma_cap_set(DMA_SLAVE, data->cap_mask);
++
++#ifdef CONFIG_SPI_NAND_USE_AHBDMA
++    printk(KERN_INFO "use AHB DMA mode\n");
++    {
++        struct ftdmac020_dma_slave slave;
++        memset(&slave, 0, sizeof(slave));
++        data->dma_chan = dma_request_channel(data->cap_mask, ftdmac020_chan_filter, (void *)&slave);    //step 1
++    }
++#else
++    ftpmu010_write_reg(nand_fd, 0xA4, (0x0 << 27), (0x1 << 27));
++    printk(KERN_INFO "use AXI DMA mode\n");
++    {
++        struct ftdmac030_dma_slave slave;
++        memset(&slave, 0, sizeof(slave));
++        data->dma_chan = dma_request_channel(data->cap_mask, ftdmac030_chan_filter, (void *)&slave);    //step 1
++    }
++#endif
++
++    if (!data->dma_chan) {
++        dev_err(&pdev->dev, "DMA channel allocation failed\n");
++        res = -ENODEV;
++        goto out_free_buf;
++    }
++    printk(KERN_INFO "Nand get DMA channel %d\n", data->dma_chan->chan_id);
++
++    data->mem_dmabuf =
++        dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->mem_dmaaddr, GFP_KERNEL);
++    if (!data->mem_dmabuf) {
++        dev_err(&pdev->dev, "failed to allocate dma buffers.\n");
++        res = -ENOMEM;
++        goto out_free_dma;
++    }
++    data->sg_dmabuf = dma_to_virt(&pdev->dev, data->mem_dmaaddr);
++
++    //printk("sg mem pa = 0x%x, va = 0x%x\n", (u32)data->mem_dmaaddr, (u32)data->sg_dmabuf);
++#else
++    printk(KERN_INFO "use PIO mode\n");
++#endif
++
++    /* read the system header first 
++     */
++    if (1) {
++        /* read system header 
++         */
++        //data->sys_hdr = kzalloc(data->mtd.writesize, GFP_KERNEL);
++        data->sys_hdr =
++            dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->syshd_dmaaddr, GFP_KERNEL);
++        if (data->sys_hdr == NULL) {
++            printk(KERN_ERR "Warning............SPI-NAND: can't alloc memory");
++            return -ENOMEM;
++        }
++        
++        data->chip.buffers = kmalloc(sizeof(struct nand_buffers), GFP_KERNEL);//kmalloc(data->mtd.writesize + (spare << 2), GFP_KERNEL);
++        if (!data->chip.buffers) {
++            dev_err(&pdev->dev, "failed to allocate chip buffers.\n");
++            res = -ENOMEM;
++            goto out_unset_drv;
++        }
++        else if((sizeof(struct nand_buffers) <  data->mtd.writesize)) {
++    		dev_err(&pdev->dev, "Please adjust the NAND_MAX_OOBSIZE & NAND_MAX_PAGESIZE\n");
++    		dev_err(&pdev->dev, "Flash Page size:%d, but NAND_MAX_PAGESIZE is %d\n", data->mtd.writesize, NAND_MAX_PAGESIZE);
++    		res = -ENOMEM;
++    		goto out_unset_drv;
++	    }
++
++        data->page_addr = 0;
++        data->chip.oob_poi = data->chip.buffers->databuf + data->mtd.writesize;
++
++        printk(KERN_INFO "NAND: read system header\n");
++        if (data->read_page(&data->mtd, (u_char *) data->sys_hdr) < 0) {
++            printk(KERN_ERR "Warning............SPI-NAND: read system header fail!");
++            return -ENODEV;
++        }
++        data->nand_parm.page_size = data->sys_hdr->nandfixup.nand_pagesz;
++        data->nand_parm.spare_size = data->sys_hdr->nandfixup.nand_sparesz_inpage;
++        data->nand_parm.block_pg = data->sys_hdr->nandfixup.nand_numpgs_blk;
++
++        data->lookup_flag = data->sys_hdr->function[0];
++        /* empty flash */
++        if(data->lookup_flag == 0xFF)
++            data->lookup_flag = 0;
++
++        data->bi_table =
++            dma_alloc_coherent(&pdev->dev, data->mtd.writesize, &data->bitab_dmaaddr, GFP_KERNEL);
++        if (data->bi_table == NULL) {
++            printk(KERN_ERR "Warning............SPI-NAND: can't alloc bi table memory");
++            return -ENOMEM;
++        }
++
++		memset(data->bi_table, 0, sizeof(bi_table_t));
++        if(data->lookup_flag) {
++            data->lookup_table = kzalloc(8192*2, GFP_KERNEL);
++        	if (!data->lookup_table) {
++        		printk(KERN_ERR "SF: Failed to allocate lookup table\n");
++        		return -ENOMEM;
++        	} else {
++        	    int i, num, loop;
++        	    u8 *buf;
++        	    
++        	    num = data->sys_hdr->nandfixup.nand_pagesz;
++        	    if(data->sys_hdr->nandfixup.nand_numblks == 512) {
++        	        loop = 1;
++        	        data->block_limit = 500;
++        	    } else {
++        	        loop = data->sys_hdr->nandfixup.nand_numblks / 1024;
++        	        data->block_limit = data->sys_hdr->nandfixup.nand_numblks - (data->sys_hdr->nandfixup.nand_numblks % 1000);
++        	    }
++
++                buf = (u8 *)data->lookup_table;
++        	    for(i = 0; i < loop; i++) {
++        	        //printk("lookup addr = 0x%x, spi_pgbuf addr = 0x%x\n", nand_lookup + (i * num / 4), spi_pgbuf);
++        	        data->page_addr = i + 1;
++                    if (data->read_page(&data->mtd, buf) < 0) {
++                        printk(KERN_ERR "Warning............SPI-NAND: read lookup table fail!");
++                        return -ENODEV;
++                    }
++        
++                    buf += num;
++                }
++
++                num *= data->sys_hdr->nandfixup.nand_numpgs_blk;
++                for(i = 0; i < data->sys_hdr->nandfixup.nand_numblks; i++)
++                    ftspi_nand_dbg("<B l:0x%4x, p:0x%4x>", i * num, data->lookup_table->physical[i] * num);
++            }            
++        }
++
++        partitions = ftnandc023_partition_info;
++        partitions_num = partition_check(partitions, data, data->mtd.erasesize);
++
++        /* restore the orginal setting */
++        data->page_addr = 0;
++    }
++    
++    i = ftnandc023_available_oob(data);
++	data->mtd.oobsize = data->nand_parm.spare_size;
++
++    printk(KERN_INFO "NAND Chip: oobsize:%#x, pagesize:%#x, blocksize:%#x, chipsize:%#x\n",
++           (int)data->mtd.oobsize, (int)data->mtd.writesize, (int)data->mtd.erasesize, (int)data->chip.chipsize);
++
++    /* Scan bad block and create bbt table
++     */
++    nand_scan_tail(&data->mtd);
++
++        /*----------------------------------------------------------
++	 * ONFI synch mode means High Speed. If fails to change to
++	 * Synch mode, then use flash as Async mode(Normal speed) and
++	 * use LEGACY_LARGE fix flow.
++	 */
++    //if (type == ONFI)
++    //    data->flash_type = ONFI;
++
++    res = mtd_device_parse_register(&data->mtd, NULL, 0, partitions, partitions_num);
++    if (!res)
++        return res;
++
++    nand_release(&data->mtd);
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++out_free_dma:
++    if (data->dma_chan)
++        dma_release_channel(data->dma_chan);
++out_free_buf:
++#endif
++    kfree(data->chip.buffers);
++
++out_unset_drv:
++    platform_set_drvdata(pdev, NULL);
++
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    if (data->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->mem_dmabuf, data->mem_dmaaddr);
++#endif
++    iounmap(data->io_base);
++out_free_data:
++    if (data->sys_hdr)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->sys_hdr, data->syshd_dmaaddr);
++    if (data->bi_table)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->bi_table, data->bitab_dmaaddr);
++    if (data->lookup_table)
++        kfree(data->lookup_table);
++    kfree(data);
++out:
++    return res;
++}
++
++/*
++ * @consult with bad block table about this block is good or bad.
++ *
++ * @ftnandc_spi_read_bbt(struct mtd_info *mtd, loff_t offs)
++ * @param mtd: MTD device structure
++ * @param offs: block base address
++ * @return: 1 for bad block, 0 for good block
++*/
++int ftnandc_spi_read_bbt(struct mtd_info *mtd, loff_t offs)
++{
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    struct bi_table *bi = (bi_table_t *) data->bi_table;
++    int ret = 0, blk_id, result;
++
++    if(!data->lookup_flag) {
++        blk_id = offs >> chip->bbt_erase_shift;
++        data->page_addr = blk_id << (chip->bbt_erase_shift - chip->page_shift);
++    
++        ftspi_nand_dbg("%s, offs = 0x%x, page = 0x%x\n", __FUNCTION__, (u32) offs, data->page_addr);
++    
++        if (data->read_oob(&data->mtd, data->chip.oob_poi) < 0) {
++            //printk("NAND: read system header fail!");
++            return 1;
++        }
++    
++        result = bi->bi_status[blk_id / 32];
++    
++        if (*data->chip.oob_poi == 0xFF) {
++            bi->bi_status[blk_id / 32] = result;
++            result |= (1 << (blk_id % 32));
++            ret = 0;                /* good */
++        } else {
++            result &= ~(1 << (blk_id % 32));
++            ret = 1;                /* bad */
++        }
++        bi->bi_status[blk_id / 32] = result;
++    }
++
++    return ret;
++}
++
++/**
++ * ftnandc023v2_default_block_markbad - mark a block bad
++ * @mtd:	MTD device structure
++ * @ofs:	offset from device start
++ *
++ * This is the default implementation, which can be overridden by
++ * a hardware specific driver.
++*/
++static int ftnandc023v2_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++    int ret = 0;
++    struct nand_chip *chip = mtd->priv;
++    struct ftnandc023_nand_data *data = chip->priv;
++    unsigned int *bi_table = (unsigned int *)data->bi_table;
++    int quotient, remainder, blk_id, result;
++    int i, num, loop, value;
++    u8 *buf;    
++
++    printk(KERN_INFO "%s, addr = 0x%x\n", __FUNCTION__, (int)ofs);
++
++    /* Get block number */
++    blk_id = (int)(ofs >> chip->bbt_erase_shift);
++
++    if(!data->lookup_flag) {
++        if (data->bi_table) {
++            blk_id = ofs >> chip->bbt_erase_shift;
++            quotient = blk_id >> 5;
++            remainder = blk_id & 0x1F;
++            result = (bi_table[quotient] >> remainder) & 0x1;
++            //printk("BI table %dth, bit %d, data = 0x%x, result = %d\n", quotient, remainder, bi_table[quotient], result);
++            if (result == 0)        /* bad block, not need to do it */
++                return 0;
++    
++            bi_table[quotient] &= ~(1 << remainder);        /* Write the block mark. */
++            blk_id <<= 1;
++            //printk("blk_id %dth, data = 0x%x, result = %x\n", blk_id, chip->bbt[blk_id >> 3], (0x3 << (blk_id & 0x06)));
++            chip->bbt[blk_id >> 3] |= (0x3 << (blk_id & 0x06));
++        }
++        /* write 1 to 0, not need to erase first */
++        data->page_addr = (int)ofs / mtd->writesize;
++        *chip->oob_poi = 0x0;
++        ret = data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++        if (!ret)
++            mtd->ecc_stats.badblocks++;
++
++    } else {
++        /* set BI field */
++        data->page_addr = (int)ofs / mtd->writesize;
++        *chip->oob_poi = 0x0;
++        ret = data->write_oob(mtd, chip->oob_poi, mtd->oobsize);
++        if (!ret)
++            mtd->ecc_stats.badblocks++;
++
++        /* use another block to replace it */
++        for(i = data->block_limit; i < data->sys_hdr->nandfixup.nand_numblks; i++) {
++            value = data->lookup_table->physical[i];
++            if((value != 0xFFFF) && (value & 0x8000)) {
++                value &= ~0x8000;
++                data->lookup_table->physical[blk_id] = value;
++                data->lookup_table->physical[i] = 0xFFFF;
++                printk(KERN_NOTICE "Use physical block %d replace logical block %d\n", value, blk_id);
++                break;
++            }
++        }
++        if(i == data->sys_hdr->nandfixup.nand_numblks){
++            printk(KERN_ERR "Can't find good block to replace it");
++            return -EIO;            
++        }
++
++        data->page_addr = 0;
++        data->page_addr = 0;
++        data->sel_chip = 0;
++        data->flash_type = 0;
++        
++        chip->cmdfunc(mtd, NAND_CMD_ERASE1, 0, 0);
++        if (data->write_page(mtd, (const uint8_t *)data->sys_hdr) < 0) {
++                printk(KERN_ERR "Warning............SPI-NAND: write system header fail!");
++                return -ENODEV;
++        }
++   
++        num = data->sys_hdr->nandfixup.nand_pagesz;
++        if(data->sys_hdr->nandfixup.nand_numblks <= 1024)
++            loop = 1;
++        else
++            loop = data->sys_hdr->nandfixup.nand_numblks / 1024;
++        
++        buf = (u8 *)data->lookup_table;
++        for(i = 0; i < loop; i++) {
++            data->page_addr = i + 1;
++            if (data->write_page(mtd, buf) < 0) {
++                printk(KERN_ERR "Warning............SPI-NAND: write lookup table fail!");
++                return -ENODEV;
++            }
++        
++            buf += num;
++        }
++    }
++    return ret;
++}
++
++/*
++ * Remove a NAND device.
++ */
++int __devexit ftnandc023_nand_remove(struct platform_device *pdev)
++{
++    struct ftnandc023_nand_data *data = platform_get_drvdata(pdev);
++
++#if defined(CONFIG_SPI_NAND_USE_AHBDMA) || defined(CONFIG_SPI_NAND_USE_AXIDMA)
++    if (data->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->mem_dmabuf, data->mem_dmaaddr);
++    if (data->dma_chan)
++        dma_release_channel(data->dma_chan);
++#endif
++    if (data->sys_hdr)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->sys_hdr, data->syshd_dmaaddr);
++    if (data->bi_table)
++        dma_free_coherent(&pdev->dev, data->mtd.writesize, data->bi_table, data->bitab_dmaaddr);
++    if (data->lookup_table)
++        kfree(data->lookup_table);
++
++    nand_release(&data->mtd);
++    iounmap(data->io_base);
++    kfree(data->chip.buffers);
++    kfree(data);
++
++    return 0;
++}
++
++static void ftnandc023_release(struct device *dev)
++{
++}
++
++static u64 ftnandc023_dmamask = DMA_BIT_MASK(32);
++
++static struct platform_device ftnandc023_device = {
++    .name = "ftnandc023_nand",
++    .id = -1,
++    .num_resources = ARRAY_SIZE(ftnandc023_resource),
++    .resource = ftnandc023_resource,
++    .dev = {
++            .dma_mask = &ftnandc023_dmamask,
++            .coherent_dma_mask = DMA_BIT_MASK(32),
++            .release = ftnandc023_release,
++            },
++};
++
++static struct platform_driver ftnandc023_nand_driver = {
++    .probe = ftspi020_nand_probe,
++    .remove = __devexit_p(ftnandc023_nand_remove),
++    .driver = {
++               .name = "ftnandc023_nand",
++               .owner = THIS_MODULE,
++               },
++};
++
++static int __init ftspi020_nand_init(void)
++{
++    int ret = 0;
++
++    /* check if the system is running NAND system 
++     */
++    if (platform_check_flash_type() != 1) {
++        printk(KERN_INFO "Not for SPI-NAND pin mux\n");
++        return 0;
++    }
++
++    /* Register PMU and turn on gate clock
++     */
++    nand_fd = ftpmu010_register_reg(&pmu_reg_info);
++    if (nand_fd < 0) {
++        printk(KERN_ERR "Warning............SPI-NAND: register PMU fail");
++        return 0;
++    }
++
++#ifdef CONFIG_GPIO_WP
++    if ((ret = gpio_request(GPIO_PIN, PIN_NAME)) != 0) {
++        printk("gpio request fail\n");
++        return ret;
++    }
++    printk("register GPIO for NAND write protect\n");
++#endif
++
++    if (platform_device_register(&ftnandc023_device)) {
++        printk(KERN_ERR "device register failed\n");
++        ret = -ENODEV;
++    }
++    if (platform_driver_register(&ftnandc023_nand_driver)) {
++        printk(KERN_ERR "driver register failed\n");
++        ret = -ENODEV;
++    }
++    return ret;
++}
++
++static void __exit ftspi020_nand_exit(void)
++{
++    /* check if the system is running NAND system 
++     */
++    if (platform_check_flash_type() != 0)
++        return;
++
++    /* Deregister PMU
++     */
++    ftpmu010_deregister_reg(nand_fd);
++
++    platform_driver_unregister(&ftnandc023_nand_driver);
++    platform_device_unregister(&ftnandc023_device);
++}
++
++module_init(ftspi020_nand_init);
++module_exit(ftspi020_nand_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Te-Chen Ying");
++MODULE_DESCRIPTION("FTNANDC023 V2.0 NAND driver");
++MODULE_ALIAS("platform:ftnandc023_nand");
+diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
+index 8a393f9e..70b5ef0d 100644
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -3069,6 +3069,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
+ 			mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
+ 		}
+ 	}
++	if (mtd->erasesize == 0) /* error configuration in nand_flash_ids[] table */
++		panic("NAND: wrong configuration in nand_flash_ids[] table!");
++        	
+ 	/* Get chip options, preserve non chip based options */
+ 	chip->options &= ~NAND_CHIPOPTIONS_MSK;
+ 	chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
+@@ -3144,6 +3147,7 @@ ident_done:
+ 				 *maf_id == NAND_MFR_HYNIX ||
+ 				 *maf_id == NAND_MFR_TOSHIBA ||
+ 				 *maf_id == NAND_MFR_AMD ||
++				 *maf_id == NAND_MFR_SPINAND ||
+ 				 *maf_id == NAND_MFR_MACRONIX)) ||
+ 			(mtd->writesize == 2048 &&
+ 			 *maf_id == NAND_MFR_MICRON))
+diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
+index 20a112f5..4ed3eabe 100644
+--- a/drivers/mtd/nand/nand_bbt.c
++++ b/drivers/mtd/nand/nand_bbt.c
+@@ -68,6 +68,7 @@
+ #include <linux/delay.h>
+ #include <linux/vmalloc.h>
+ #include <linux/export.h>
++#include <mach/ftpmu010.h>
+ 
+ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
+ {
+@@ -416,13 +417,38 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
+ 	return 0;
+ }
+ 
++#define NAND_OWN_BBT
+ /* Scan a given block partially */
+ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
+ 			   loff_t offs, uint8_t *buf, int len)
+ {
+ 	struct mtd_oob_ops ops;
+ 	int j, ret;
+-
++	
++#ifdef NAND_OWN_BBT
++    {
++        /*
++         * In romcode stage, we already built a block status table. So we need 
++         * to redirect the checking function to own checking function.
++         */
++#ifdef CONFIG_MTD_NAND_FTSPINAND020
++        {
++        extern int ftnandc_spi_read_bbt(struct mtd_info *mtd, loff_t offs);
++        
++        if (platform_check_flash_type() == 1)
++            return ftnandc_spi_read_bbt(mtd, offs);  
++        }      
++#endif
++#if defined(CONFIG_MTD_NAND_FTNANDC023) || defined(CONFIG_MTD_NAND_FTNANDC024V2)
++        {
++        extern int ftnandc_read_bbt(struct mtd_info *mtd, loff_t offs);
++
++        if (platform_check_flash_type() == 0)
++            return ftnandc_read_bbt(mtd, offs);
++        }
++#endif
++    }
++#endif
+ 	ops.ooblen = mtd->oobsize;
+ 	ops.oobbuf = buf;
+ 	ops.ooboffs = 0;
+@@ -1131,8 +1157,10 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+ 	 * table.
+ 	 */
+ 	this->bbt = kzalloc(len, GFP_KERNEL);
+-	if (!this->bbt)
++	if (!this->bbt){
++		printk(KERN_ERR "nand_scan_bbt: Out of memory in allocating %d bytes!\n", len);
+ 		return -ENOMEM;
++	}
+ 
+ 	/*
+ 	 * If no primary table decriptor is given, scan the device to build a
+@@ -1385,7 +1413,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+ 	uint8_t res;
+ 
+ 	/* Get block number * 2 */
+-	block = (int)(offs >> (this->bbt_erase_shift - 1));
++	block = (int)(offs) >> (this->bbt_erase_shift - 1);
+ 	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
+ 
+ 	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: "
+diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
+index af4fe8ca..ea973453 100644
+--- a/drivers/mtd/nand/nand_ids.c
++++ b/drivers/mtd/nand/nand_ids.c
+@@ -59,6 +59,16 @@ struct nand_flash_dev nand_flash_ids[] = {
+ 	{"NAND 128MiB 1,8V 8-bit",	0x78, 512, 128, 0x4000, 0},
+ 	{"NAND 128MiB 1,8V 8-bit",	0x39, 512, 128, 0x4000, 0},
+ 	{"NAND 128MiB 3,3V 8-bit",	0x79, 512, 128, 0x4000, 0},
++	{"NAND 64MiB 3,3V 8-bit",	0x20, 2048, 64, 0x20000, 0},//spi_nand second ID
++	{"NAND 128MiB 3,3V 8-bit",	0x21, 2048, 128, 0x20000, 0},//spi_nand second ID
++	{"NAND 128MiB 3,3V 8-bit",	0xF1, 2048, 128, 0x20000, 0},//spi_nand second ID
++	{"NAND 128MiB 3,3V 8-bit",	0xD1, 2048, 128, 0x20000, 0},//spi_nand second ID
++	{"NAND 128MiB 3,3V 8-bit",	0x12, 2048, 128, 0x20000, 0},//spi_nand second ID
++	{"NAND 128MiB 3,3V 8-bit",	0x41, 2048, 128, 0x20000, 0},//spi_nand second ID
++	{"NAND 128MiB 3,3V 8-bit",	0xAA, 2048, 128, 0x20000, 0},//spi_nand second ID
++	{"NAND 256MiB 3,3V 8-bit",	0x42, 2048, 256, 0x20000, 0},//spi_nand second ID
++	{"NAND 256MiB 3,3V 8-bit",	0xD2, 2048, 256, 0x20000, 0},//spi_nand second ID
++	{"NAND 256MiB 3,3V 8-bit",	0x22, 2048, 256, 0x20000, 0},//spi_nand second ID
+ 	{"NAND 128MiB 1,8V 16-bit",	0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ 	{"NAND 128MiB 1,8V 16-bit",	0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ 	{"NAND 128MiB 3,3V 16-bit",	0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+@@ -86,6 +96,7 @@ struct nand_flash_dev nand_flash_ids[] = {
+ 
+ 	/* 1 Gigabit */
+ 	{"NAND 128MiB 1,8V 8-bit",	0xA1, 0, 128, 0, LP_OPTIONS},
++	{"NAND 128MiB 3,3V 8-bit", 	0xF1, 2048, 128, 0x20000, LP_OPTIONS}, /* Samsung K9F1G08U0C, 9500F1EC */
+ 	{"NAND 128MiB 3,3V 8-bit",	0xF1, 0, 128, 0, LP_OPTIONS},
+ 	{"NAND 128MiB 3,3V 8-bit",	0xD1, 0, 128, 0, LP_OPTIONS},
+ 	{"NAND 128MiB 1,8V 16-bit",	0xB1, 0, 128, 0, LP_OPTIONS16},
+@@ -100,6 +111,7 @@ struct nand_flash_dev nand_flash_ids[] = {
+ 
+ 	/* 4 Gigabit */
+ 	{"NAND 512MiB 1,8V 8-bit",	0xAC, 0, 512, 0, LP_OPTIONS},
++	{"NAND 512MiB ?.?V 8-bit", 	0xDC, 2048, 512, 0x20000, LP_OPTIONS},	/* Samsung K9F4G08U0A */
+ 	{"NAND 512MiB 3,3V 8-bit",	0xDC, 0, 512, 0, LP_OPTIONS},
+ 	{"NAND 512MiB 1,8V 16-bit",	0xBC, 0, 512, 0, LP_OPTIONS16},
+ 	{"NAND 512MiB 3,3V 16-bit",	0xCC, 0, 512, 0, LP_OPTIONS16},
+@@ -118,10 +130,14 @@ struct nand_flash_dev nand_flash_ids[] = {
+ 
+ 	/* 32 Gigabit */
+ 	{"NAND 4GiB 1,8V 8-bit",	0xA7, 0, 4096, 0, LP_OPTIONS},
++	{"NAND 4GiB 3.3V 8-bit",   	0xD7, 4096, 512 /*4096*/   , 0x80000,  LP_OPTIONS},	/* Samsung K9LBG08U0M */
++	{"NAND 4GiB 3.3V 8-bit", 	0xD7, 8192, 1024 /*4096 */ , 0x100000, LP_OPTIONS},	/* Samsung K9HDGD8XM (toggle) */	
+ 	{"NAND 4GiB 3,3V 8-bit",	0xD7, 0, 4096, 0, LP_OPTIONS},
+ 	{"NAND 4GiB 1,8V 16-bit",	0xB7, 0, 4096, 0, LP_OPTIONS16},
+-	{"NAND 4GiB 3,3V 16-bit",	0xC7, 0, 4096, 0, LP_OPTIONS16},
+-
++	{"NAND 4GiB 3,3V 16-bit",	0xC7, 0, 4096, 0, LP_OPTIONS16},	
++	{"NAND 4GiB 3.3V 8-bit", 	0x68, 4096, 512 /*4096 */  , 0x100000, LP_OPTIONS},	/* Micron 29F32G08CBABB (ONFI) */
++	{"NAND 4GiB ?.?V 8-bit", 	0xD5, 8192, 2048 /*4096 */ , 0x100000, LP_OPTIONS},	/* Toshiba TF14G2GADA */
++	
+ 	/* 64 Gigabit */
+ 	{"NAND 8GiB 1,8V 8-bit",	0xAE, 0, 8192, 0, LP_OPTIONS},
+ 	{"NAND 8GiB 3,3V 8-bit",	0xDE, 0, 8192, 0, LP_OPTIONS},
+@@ -178,6 +194,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
+ 	{NAND_MFR_MICRON, "Micron"},
+ 	{NAND_MFR_AMD, "AMD"},
+ 	{NAND_MFR_MACRONIX, "Macronix"},
++	{NAND_MFR_SPINAND, "SPI-NAND"},
+ 	{0x0, "Unknown"}
+ };
+ 
+diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig
+index b8974b9e..c4bb2e56 100644
+--- a/drivers/net/ethernet/faraday/Kconfig
++++ b/drivers/net/ethernet/faraday/Kconfig
+@@ -18,23 +18,143 @@ config NET_VENDOR_FARADAY
+ 
+ if NET_VENDOR_FARADAY
+ 
+-config FTMAC100
+-	tristate "Faraday FTMAC100 10/100 Ethernet support"
+-	depends on ARM
++config FTGMAC100
++	tristate "Faraday FTGMAC100 support"
++	help
++	  This driver supports Faraday(R) FTGMAC100 gigabit ethernet family of
++	  adapters.  
++	  For general information and support, go to the Faraday support
++	  website at:
++	  <http://www.faraday-tech.com>
++	 
++	  To compile this driver as a module, choose M here and read
++	  <file:Documentation/networking/net-modules.txt>.  The module
++	  will be called ftgmac100.
++
++if FTGMAC100
++if PLATFORM_GM8210
++
++config FTGMAC100_DRIVER_0_MASTER
++	bool "Enable GMAC 0 for 726"
++	default y
++	help
++	  If we want to use GMAC driver 0 for 726, say Y; otherwise say N.	  
++config FTGMAC100_DRIVER_0_SLAVE
++	bool "Enable GMAC 0 for 626"
++	default y
++	help
++	  If we want to use GMAC driver 0 for 626, say Y; otherwise say N.
++config FTGMAC100_DRIVER_1_MASTER
++	bool "Enable GMAC 1 for 726"
++	default y
++	help
++	  If we want to use GMAC driver 1 for 726, say Y; otherwise say N.
++config FTGMAC100_DRIVER_1_SLAVE
++	bool "Enable GMAC 1 for 626"
++	default y
++	help
++	  If we want to use GMAC driver 1 for 626, say Y; otherwise say N.
++endif	# if PLATFORM_GM8210
++
++if !PLATFORM_GM8210
++config FTGMAC100_DRIVER_0_MASTER
++	bool "Enable GMAC 0"
++	default y
++	help
++	  If we want to use GMAC driver 0, say Y; otherwise say N.
++
++config FTMAC_TINY
++    bool "Less queue number"
++    default n
++	depends on FTGMAC100_DRIVER_0_MASTER
++	help
++	    Use less queue number, if user application is not enough,
++	    please disable it.
++endif
++
++endif	# if FTGMAC100
++
++config FTGMAC030
++	tristate "Faraday FTGMAC030 support"
++	default n
++	help
++	  This driver supports Faraday(R) FTGMAC030 gigabit ethernet family of
++	  adapters.  
++	  For general information and support, go to the Faraday support
++	  website at:
++	  <http://www.faraday-tech.com>
++	 
++	  To compile this driver as a module, choose M here and read
++	  <file:Documentation/networking/net-modules.txt>.  The module
++	  will be called ftgmac030.
++
++if FTGMAC030
++if PLATFORM_GM8220
++
++config FTGMAC030_DRIVER_0
++	bool "Enable GMAC 0"
++	default y
++	help
++	  If we want to use GMAC driver 0, say Y; otherwise say N.	  
++config FTGMAC030_DRIVER_1
++	bool "Enable GMAC 1"
++	default y
++	help
++	  If we want to use GMAC driver 1, say Y; otherwise say N.
++endif	# if PLATFORM_GM8220
++
++endif	# if FTGMAC030
++
++config FTMAC110
++	tristate "Faraday FTMAC110 support"
+ 	select NET_CORE
+ 	select MII
+-	---help---
+-	  This driver supports the FTMAC100 10/100 Ethernet controller
+-	  from Faraday. It is used on Faraday A320, Andes AG101 and some
+-	  other ARM/NDS32 SoC's.
++	help
++	  This driver supports Faraday(R) FTMAC110 10/100 ethernet family of
++	  adapters.  
++	  For general information and support, go to the Faraday support
++	  website at:
++	  <http://www.faraday-tech.com>
++	 
++	  To compile this driver as a module, choose M here and read
++	  <file:Documentation/networking/net-modules.txt>.  The module
++	  will be called ftmac110.
+ 
+-config FTGMAC100
+-	tristate "Faraday FTGMAC100 Gigabit Ethernet support"
+-	depends on ARM
+-	select PHYLIB
+-	---help---
+-	  This driver supports the FTGMAC100 Gigabit Ethernet controller
+-	  from Faraday. It is used on Faraday A369, Andes AG102 and some
+-	  other ARM/NDS32 SoC's.
++if FTMAC110
++
++config FTMAC110_PHYADDR
++	int "PHY Address"
++	default 1
++	depends on FTMAC110
++	
++config FTMAC110_PHYMON
++	bool "PHY Monitor"
++	default n
++	depends on FTMAC110
++	help
++	  If ftmac110 is connected with a single phy, say Y; otherwise say N.
++	
++config FTMAC110_NDESC_TX
++	int "Tx Descriptor Number"
++	default 256
++	depends on FTMAC110
++	
++config FTMAC110_NDESC_RX
++	int "Rx Descriptor Number"
++	default 256
++	depends on FTMAC110
++
++config FTMAC110_NAPI
++	bool "NAPI(New API) support"
++	default y
++	depends on FTMAC110
++	
++config FTMAC110_NAPI_LRO
++	bool "LRO(Large Receive Offload) support"
++	default y
++	select INET_LRO
++	depends on FTMAC110_NAPI
++
++endif	# if FTMAC110
+ 
+ endif # NET_VENDOR_FARADAY
+diff --git a/drivers/net/ethernet/faraday/Makefile b/drivers/net/ethernet/faraday/Makefile
+index 408b5398..aaebe0b8 100644
+--- a/drivers/net/ethernet/faraday/Makefile
++++ b/drivers/net/ethernet/faraday/Makefile
+@@ -2,5 +2,8 @@
+ # Makefile for the Faraday device drivers.
+ #
+ 
+-obj-$(CONFIG_FTGMAC100) += ftgmac100.o
+-obj-$(CONFIG_FTMAC100) += ftmac100.o
++obj-$(CONFIG_FTGMAC100) += gmac100.o
++obj-$(CONFIG_FTGMAC030) += gmac030.o
++obj-$(CONFIG_FTMAC110) += ftmac110.o
++gmac100-objs		:= ftgmac100_platform.o ftgmac100.o
++gmac030-objs		:= ftgmac030_platform.o ftgmac030.o #ptp.o
+\ No newline at end of file
+diff --git a/drivers/net/ethernet/faraday/ftgmac030.c b/drivers/net/ethernet/faraday/ftgmac030.c
+new file mode 100644
+index 00000000..89c37404
+--- /dev/null
++++ b/drivers/net/ethernet/faraday/ftgmac030.c
+@@ -0,0 +1,2195 @@
++/*
++ * Faraday ftgmac030 Gigabit Ethernet
++ *
++ * (C) Copyright 2014-2016 Faraday Technology
++ * Bing-Yao Luo <bjluo@faraday-tech.com>
++ *
++ * 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.
++ */
++
++#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
++
++#include <linux/crc32.h>
++#include <linux/version.h>
++#include <linux/dma-mapping.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/phy.h>
++#include <linux/platform_device.h>
++#include <linux/proc_fs.h>
++#include <asm/setup.h>
++#include <net/ip.h>
++#include <net/ipv6.h>
++
++#include "ftgmac030.h"
++
++#define DRV_VERSION	"0.1"
++
++#define MAX_PKT_SIZE		1518
++#define RX_BUF_SIZE		PAGE_SIZE	/* must be smaller than 0x3fff */
++
++static bool ftgmac030_tx_complete_packet(struct ftgmac030 *priv);
++static int ftgmac030_alloc_rx_page(struct ftgmac030 *priv,
++				   struct ftgmac030_rxdes *rxdes, gfp_t gfp);
++
++char mdc_cycthr;
++static char show_tx_pkg = 0, show_rx_pkg = 0, show_phy = 0, show_rx_dbg = 0;
++static struct proc_dir_entry *ftgmac_proc = NULL, *ftgmac_tx_pkg_debug = NULL;
++static struct proc_dir_entry *ftgmac_rx_pkg_debug = NULL, *ftgmac_phy_debug = NULL, *ftgmac_rx_debug = NULL, *ftgmac_reg_debug = NULL;
++static char *command_line = NULL;
++
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/ 
++
++static u64 ftgmac030_dmamask = DMA_BIT_MASK(32);
++#ifdef CONFIG_FTGMAC030_DRIVER_0
++/*GMAC 0*/
++static struct resource ftgmac030_0_resource[] = {
++	{
++         .start  = MAC_FTGMAC030_0_PA_BASE,
++         .end        = MAC_FTGMAC030_0_PA_LIMIT,
++         .flags  = IORESOURCE_MEM,
++	},
++	{
++         .start  = MAC_FTGMAC030_0_IRQ,
++         .end        = MAC_FTGMAC030_0_IRQ,
++         .flags  = IORESOURCE_IRQ,
++	},
++};
++
++static void ftgmac030_0_release(struct device *dev)
++{
++    return;
++}
++
++static struct platform_device ftgmac030_0_device = {
++	.name	= DRV_NAME,
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgmac030_0_resource),
++	.resource	= ftgmac030_0_resource,
++        .dev = {
++        	.dma_mask = &ftgmac030_dmamask,
++        	.coherent_dma_mask = DMA_BIT_MASK(32),
++        	.release = ftgmac030_0_release,
++        }, 	
++};
++#endif
++
++#ifdef CONFIG_FTGMAC030_DRIVER_1
++/*GMAC 1*/
++static struct resource ftgmac030_1_resource[] = {
++	{
++         .start  = MAC_FTGMAC030_1_PA_BASE,
++         .end        = MAC_FTGMAC030_1_PA_LIMIT,
++         .flags  = IORESOURCE_MEM,
++	},
++	{
++         .start  = MAC_FTGMAC030_1_IRQ,
++         .end        = MAC_FTGMAC030_1_IRQ,
++         .flags  = IORESOURCE_IRQ,
++	},
++};
++
++static void ftgmac030_1_release(struct device *dev)
++{
++    return;
++}
++
++static struct platform_device ftgmac030_1_device = {
++	.name	= DRV_1_NAME,
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgmac030_1_resource),
++	.resource	= ftgmac030_1_resource,
++        .dev = {
++        	.dma_mask = &ftgmac030_dmamask,
++        	.coherent_dma_mask = DMA_BIT_MASK(32),
++        	.release = ftgmac030_1_release,
++        }, 	
++};
++#endif
++/******************************************************************************
++ * internal functions (hardware register access)
++ *****************************************************************************/
++#define INT_MASK_ALL_ENABLED	(FTGMAC030_INT_RPKT_LOST	| \
++				 FTGMAC030_INT_AHB_ERR		| \
++				 FTGMAC030_INT_RPKT_BUF		| \
++				 FTGMAC030_INT_NO_RXBUF)
++
++static void ftgmac030_set_rx_ring_base(struct ftgmac030 *priv, dma_addr_t addr)
++{
++	iowrite32(addr, priv->base + FTGMAC030_REG_RXR_BADR);
++}
++
++static void ftgmac030_set_rx_buffer_size(struct ftgmac030 *priv,
++		unsigned int size)
++{
++	size = FTGMAC030_RBSR_SIZE(size);
++	iowrite32(size, priv->base + FTGMAC030_REG_RBSR);
++}
++
++static void ftgmac030_set_normal_prio_tx_ring_base(struct ftgmac030 *priv,
++						   dma_addr_t addr)
++{
++	iowrite32(addr, priv->base + FTGMAC030_REG_NPTXR_BADR);
++}
++
++static void ftgmac030_txdma_normal_prio_start_polling(struct ftgmac030 *priv)
++{
++	iowrite32(1, priv->base + FTGMAC030_REG_NPTXPD);
++}
++
++static int ftgmac030_reset_hw(struct ftgmac030 *priv)
++{
++	struct net_device *netdev = priv->netdev;
++	int i;
++
++	/* NOTE: reset clears all registers */
++	iowrite32(FTGMAC030_MACCR_SW_RST, priv->base + FTGMAC030_REG_MACCR);
++	for (i = 0; i < 5; i++) {
++		unsigned int maccr;
++
++		maccr = ioread32(priv->base + FTGMAC030_REG_MACCR);
++		if (!(maccr & FTGMAC030_MACCR_SW_RST))
++			return 0;
++
++		udelay(1000);
++	}
++
++	netdev_err(netdev, "software reset failed\n");
++	return -EIO;
++}
++
++static void ftgmac030_set_mac(struct ftgmac030 *priv, const unsigned char *mac)
++{
++	unsigned int maddr = mac[0] << 8 | mac[1];
++	unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
++
++	iowrite32(maddr, priv->base + FTGMAC030_REG_MAC_MADR);
++	iowrite32(laddr, priv->base + FTGMAC030_REG_MAC_LADR);
++}
++
++static void ftgmac030_init_hw(struct ftgmac030 *priv)
++{
++	/* setup ring buffer base registers */
++	ftgmac030_set_rx_ring_base(priv,
++				   priv->descs_dma_addr +
++				   offsetof(struct ftgmac030_descs, rxdes));
++	ftgmac030_set_normal_prio_tx_ring_base(priv,
++					       priv->descs_dma_addr +
++					       offsetof(struct ftgmac030_descs, txdes));
++
++	ftgmac030_set_rx_buffer_size(priv, RX_BUF_SIZE);
++
++	iowrite32(FTGMAC030_APTC_RXPOLL_CNT(0xF), priv->base + FTGMAC030_REG_APTC);
++	set_MDC_CLK(priv);
++#if 1
++    {
++	unsigned int value;        
++  // enable flow control
++	value = ioread32(priv->base + FTGMAC030_REG_FCR);			
++	iowrite32(value | 0x1, priv->base + FTGMAC030_REG_FCR);
++
++  // enable back pressure register
++	value = ioread32(priv->base + FTGMAC030_REG_BPR);			
++	iowrite32(value | 0x1, priv->base + FTGMAC030_REG_BPR);
++    }
++#endif
++	ftgmac030_set_mac(priv, priv->netdev->dev_addr);
++}
++
++#if 1
++#define MACCR_ENABLE_ALL	(FTGMAC030_MACCR_TXDMA_EN	| \
++				 FTGMAC030_MACCR_RXDMA_EN	| \
++				 FTGMAC030_MACCR_TXMAC_EN	| \
++				 FTGMAC030_MACCR_RXMAC_EN	| \
++				 FTGMAC030_MACCR_RX_ALL         | \
++				 FTGMAC030_MACCR_CRC_APD	| \
++				 FTGMAC030_MACCR_RX_RUNT	| \
++				 FTGMAC030_MACCR_RX_BROADPKT)
++#else
++#define MACCR_ENABLE_ALL	(FTGMAC030_MACCR_RX_ALL         | \
++				 FTGMAC030_MACCR_FULLDUP	| \
++				 FTGMAC030_MACCR_CRC_APD	| \
++				 FTGMAC030_MACCR_RX_RUNT	| \
++				 FTGMAC030_MACCR_RX_BROADPKT)
++
++#define MACCR_ENABLE_DMA	(FTGMAC030_MACCR_TXDMA_EN	| \
++				 FTGMAC030_MACCR_RXDMA_EN	| \
++				 FTGMAC030_MACCR_TXMAC_EN	| \
++				 FTGMAC030_MACCR_RXMAC_EN)	 
++#endif
++
++static void ftgmac030_set_fifo_size(struct ftgmac030 *priv)
++{
++	int tfifo, rfifo, tpafcr;
++	
++	tfifo = FTGMAC030_FEAR_TFIFO_RSIZE(ioread32(priv->base + FTGMAC030_REG_FEAR));
++	rfifo = FTGMAC030_FEAR_RFIFO_RSIZE(ioread32(priv->base + FTGMAC030_REG_FEAR));
++	
++	tpafcr = ioread32(priv->base + FTGMAC030_REG_TPAFCR) & 0x00FFFFFF;
++	tpafcr = tpafcr | (tfifo << 27) | (rfifo << 24);
++	iowrite32(tpafcr, priv->base + FTGMAC030_REG_TPAFCR);
++}
++
++static void ftgmac030_start_hw(struct ftgmac030 *priv, int speed, int duplex)
++{
++	int maccr = MACCR_ENABLE_ALL;
++
++	switch (speed) {
++	default:
++	case 10:
++		break;
++
++	case 100:
++		maccr |= FTGMAC030_MACCR_FAST_MODE;
++		break;
++
++	case 1000:
++		maccr |= FTGMAC030_MACCR_GIGA_MODE;
++		break;
++	}
++
++	if(duplex)
++		maccr |= FTGMAC030_MACCR_FULLDUP;
++
++	iowrite32(maccr, priv->base + FTGMAC030_REG_MACCR);
++#if 0		
++	maccr |= MACCR_ENABLE_DMA;
++	iowrite32(maccr, priv->base + FTGMAC030_REG_MACCR);
++#endif
++	ftgmac030_set_fifo_size(priv);
++}
++
++static void ftgmac030_stop_hw(struct ftgmac030 *priv)
++{
++#if 1
++	u32 maccr;
++	struct net_device *netdev = priv->netdev;
++	unsigned long deadline;
++
++	maccr = ioread32(priv->base + FTGMAC030_REG_MACCR);
++	/* Stop TX DMA and RX MAC */
++	maccr &= ~(FTGMAC030_MACCR_TXDMA_EN | FTGMAC030_MACCR_RXMAC_EN);
++	iowrite32(maccr, priv->base + FTGMAC030_REG_MACCR);
++
++	deadline = jiffies + HZ;
++	while (1) {	
++		unsigned long now;
++		u32 fifo;
++
++		now = jiffies;
++		fifo = ioread32(priv->base + FTGMAC030_REG_DMAFIFOS);
++		if ((fifo & FTGMAC030_DMAFIFOS_TXFIFO_EMPTY) &&
++		    (fifo & FTGMAC030_DMAFIFOS_RXFIFO_EMPTY)) {
++			break;
++
++		}
++
++		if (time_after(now, deadline)) {
++			netdev_err(netdev, "Wait FIFO empty timeout -> 0x%08x\n", fifo);
++			break;
++		}
++	}
++
++	/* Stop transmission to ethernet and RX DMA */
++	maccr &= ~(FTGMAC030_MACCR_RXDMA_EN | FTGMAC030_MACCR_TXMAC_EN);
++	iowrite32(maccr, priv->base + FTGMAC030_REG_MACCR);
++#else
++	iowrite32(0, priv->base + FTGMAC030_REG_MACCR);
++#endif
++}
++
++/******************************************************************************
++ * internal functions (receive descriptor)
++ *****************************************************************************/
++static bool ftgmac030_rxdes_first_segment(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_FRS);
++}
++
++static bool ftgmac030_rxdes_last_segment(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_LRS);
++}
++
++static bool ftgmac030_rxdes_packet_ready(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_RXPKT_RDY);
++}
++
++static void ftgmac030_rxdes_set_dma_own(struct ftgmac030_rxdes *rxdes)
++{
++	/* clear status bits */
++	rxdes->rxdes0 &= cpu_to_le32(FTGMAC030_RXDES0_EDORR);
++}
++
++static bool ftgmac030_rxdes_rx_error(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_RX_ERR);
++}
++
++static bool ftgmac030_rxdes_fifo_error(struct ftgmac030_rxdes *rxdes)
++{
++    return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_FIFO_FULL);
++}
++
++static bool ftgmac030_rxdes_crc_error(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_CRC_ERR);
++}
++
++static bool ftgmac030_rxdes_frame_too_long(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_FTL);
++}
++
++static bool ftgmac030_rxdes_runt(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_RUNT);
++}
++
++static bool ftgmac030_rxdes_odd_nibble(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_RX_ODD_NB);
++}
++
++static unsigned int ftgmac030_rxdes_data_length(struct ftgmac030_rxdes *rxdes)
++{
++	return le32_to_cpu(rxdes->rxdes0) & FTGMAC030_RXDES0_VDBC;
++}
++
++static bool ftgmac030_rxdes_multicast(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes0 & cpu_to_le32(FTGMAC030_RXDES0_MULTICAST);
++}
++
++static void ftgmac030_rxdes_set_end_of_ring(struct ftgmac030_rxdes *rxdes)
++{
++	rxdes->rxdes0 |= cpu_to_le32(FTGMAC030_RXDES0_EDORR);
++}
++
++static void ftgmac030_rxdes_set_dma_addr(struct ftgmac030_rxdes *rxdes,
++					 dma_addr_t addr)
++{
++	rxdes->rxdes3 = cpu_to_le32(addr);
++}
++
++static dma_addr_t ftgmac030_rxdes_get_dma_addr(struct ftgmac030_rxdes *rxdes)
++{
++	return le32_to_cpu(rxdes->rxdes3);
++}
++
++static bool ftgmac030_rxdes_is_tcp(struct ftgmac030_rxdes *rxdes)
++{
++	return (rxdes->rxdes1 & cpu_to_le32(FTGMAC030_RXDES1_PROT_MASK)) ==
++	       cpu_to_le32(FTGMAC030_RXDES1_PROT_TCPIP);
++}
++
++static bool ftgmac030_rxdes_is_udp(struct ftgmac030_rxdes *rxdes)
++{
++	return (rxdes->rxdes1 & cpu_to_le32(FTGMAC030_RXDES1_PROT_MASK)) ==
++	       cpu_to_le32(FTGMAC030_RXDES1_PROT_UDPIP);
++}
++
++static bool ftgmac030_rxdes_tcpcs_err(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes1 & cpu_to_le32(FTGMAC030_RXDES1_TCP_CHKSUM_ERR);
++}
++
++static bool ftgmac030_rxdes_udpcs_err(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes1 & cpu_to_le32(FTGMAC030_RXDES1_UDP_CHKSUM_ERR);
++}
++
++static bool ftgmac030_rxdes_ipcs_err(struct ftgmac030_rxdes *rxdes)
++{
++	return rxdes->rxdes1 & cpu_to_le32(FTGMAC030_RXDES1_IP_CHKSUM_ERR);
++}
++
++/*
++ * rxdes2 is not used by hardware. We use it to keep track of page.
++ * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
++ */
++static void ftgmac030_rxdes_set_page(struct ftgmac030_rxdes *rxdes, struct page *page)
++{
++	rxdes->rxdes2 = (unsigned int)page;
++}
++
++static struct page *ftgmac030_rxdes_get_page(struct ftgmac030_rxdes *rxdes)
++{
++	return (struct page *)rxdes->rxdes2;
++}
++
++/******************************************************************************
++ * internal functions (receive)
++ *****************************************************************************/
++static int ftgmac030_next_rx_pointer(int pointer)
++{
++	return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
++}
++
++static void ftgmac030_rx_pointer_advance(struct ftgmac030 *priv)
++{
++	priv->rx_pointer = ftgmac030_next_rx_pointer(priv->rx_pointer);
++}
++
++static struct ftgmac030_rxdes *ftgmac030_current_rxdes(struct ftgmac030 *priv)
++{
++	return &priv->descs->rxdes[priv->rx_pointer];
++}
++
++static struct ftgmac030_rxdes *
++ftgmac030_rx_locate_first_segment(struct ftgmac030 *priv)
++{
++	struct ftgmac030_rxdes *rxdes = ftgmac030_current_rxdes(priv);
++
++	while (ftgmac030_rxdes_packet_ready(rxdes)) {
++		if (ftgmac030_rxdes_first_segment(rxdes))
++			return rxdes;
++
++		ftgmac030_rxdes_set_dma_own(rxdes);
++		ftgmac030_rx_pointer_advance(priv);
++		rxdes = ftgmac030_current_rxdes(priv);
++	}
++
++	return NULL;
++}
++
++static bool ftgmac030_rx_packet_error(struct ftgmac030 *priv,
++				      struct ftgmac030_rxdes *rxdes)
++{
++	struct net_device *netdev = priv->netdev;
++	bool error = false;
++
++	if (unlikely(ftgmac030_rxdes_fifo_error(rxdes))) {
++		if (show_rx_dbg)
++			netdev_info(netdev, "MAC rx fifo full, lose\n");
++
++		error = true;
++	} else {
++    	if (unlikely(ftgmac030_rxdes_rx_error(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx err\n");
++
++    		error = true;
++    	} else if (unlikely(ftgmac030_rxdes_crc_error(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx crc err\n");
++    
++    		netdev->stats.rx_crc_errors++;
++    		error = true;
++    	} else if (unlikely(ftgmac030_rxdes_ipcs_err(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx IP checksum err\n");
++    
++    		netdev->stats.rx_frame_errors++;
++    		error = true;
++    	} else if (unlikely(ftgmac030_rxdes_frame_too_long(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx frame too long\n");
++    
++    		netdev->stats.rx_length_errors++;
++    		error = true;
++    	} else if (unlikely(ftgmac030_rxdes_runt(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx runt\n");
++    
++    		netdev->stats.rx_length_errors++;
++    		error = true;
++    	} else if (unlikely(ftgmac030_rxdes_odd_nibble(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx odd nibble\n");
++    
++    		netdev->stats.rx_length_errors++;
++    		error = true;
++    	}
++    }
++
++    if(error)
++        netdev->stats.rx_errors++;
++
++	return error;
++}
++
++static void ftgmac030_rx_drop_packet(struct ftgmac030 *priv)
++{
++	struct net_device *netdev = priv->netdev;
++	struct ftgmac030_rxdes *rxdes = ftgmac030_current_rxdes(priv);
++	bool done = false;
++
++	if (show_rx_dbg)
++		netdev_info(netdev, "drop packet %p\n", rxdes);
++
++	do {
++		if (ftgmac030_rxdes_last_segment(rxdes))
++			done = true;
++
++		ftgmac030_rxdes_set_dma_own(rxdes);
++		ftgmac030_rx_pointer_advance(priv);
++		rxdes = ftgmac030_current_rxdes(priv);
++	} while (!done && ftgmac030_rxdes_packet_ready(rxdes));
++
++	netdev->stats.rx_dropped++;
++}
++
++#ifdef CONFIG_FTGMAC030_PTP
++/**
++ * ftgmac030_rx_hwtstamp - utility function which checks for Rx time stamp
++ * @adapter: board private structure
++ * @skb: particular skb to include time stamp
++ *
++ * If the time stamp is valid, convert it into the timecounter ns value
++ * and store that result into the shhwtstamps structure which is passed
++ * up the network stack.
++ **/
++static void ftgmac030_rx_hwtstamp(struct ftgmac030 *adapter, struct sk_buff *skb)
++{
++	struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
++	unsigned long flags;
++	u64 rxstmp;
++
++	/* The Rx time stamp registers contain the time stamp.  No other
++	 * received packet will be time stamped until the Rx time stamp
++	 * registers are read.  Because only one packet can be time stamped
++	 * at a time, the register values must belong to this packet and
++	 * therefore none of the other additional attributes need to be
++	 * compared.
++	 */
++	spin_lock_irqsave(&adapter->systim_lock, flags);
++	rxstmp = ioread32(adapter->base + FTGMAC030_REG_PTP_RX_SEC) * NSEC_PER_SEC;
++	rxstmp += ioread32(adapter->base + FTGMAC030_REG_PTP_RX_NSEC);
++	spin_unlock_irqrestore(&adapter->systim_lock, flags);
++
++	memset(hwtstamps, 0, sizeof(*hwtstamps));
++	hwtstamps->hwtstamp = ns_to_ktime(rxstmp);
++
++}
++#endif
++
++static bool ftgmac030_rx_packet(struct ftgmac030 *priv, int *processed)
++{
++	struct net_device *netdev = priv->netdev;
++	struct ftgmac030_rxdes *rxdes;
++	struct sk_buff *skb;
++	bool done = false;
++	int i;
++
++	rxdes = ftgmac030_rx_locate_first_segment(priv);
++	if (!rxdes)
++		return false;
++
++	if (unlikely(ftgmac030_rx_packet_error(priv, rxdes))) {
++		ftgmac030_rx_drop_packet(priv);
++		netdev->stats.rx_dropped++;
++		return true;
++	}
++
++	/* start processing */
++	skb = netdev_alloc_skb_ip_align(netdev, 128);
++	if (unlikely(!skb)) {
++		netdev_err(netdev, "rx skb alloc failed\n");
++
++		ftgmac030_rx_drop_packet(priv);
++		netdev->stats.rx_dropped++;
++		return true;
++	}
++
++	if (unlikely(ftgmac030_rxdes_multicast(rxdes)))
++		netdev->stats.multicast++;
++
++	/*
++	 * It seems that HW does checksum incorrectly with fragmented packets,
++	 * so we are conservative here - if HW checksum error, let software do
++	 * the checksum again.
++	 */
++	if ((ftgmac030_rxdes_is_tcp(rxdes) && !ftgmac030_rxdes_tcpcs_err(rxdes)) ||
++	    (ftgmac030_rxdes_is_udp(rxdes) && !ftgmac030_rxdes_udpcs_err(rxdes)))
++		skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++	do {
++		dma_addr_t map = ftgmac030_rxdes_get_dma_addr(rxdes);
++		struct page *page = ftgmac030_rxdes_get_page(rxdes);
++		unsigned int size;
++
++		dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
++
++		size = ftgmac030_rxdes_data_length(rxdes);
++		skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 0, size);
++
++		skb->len += size;
++		skb->data_len += size;
++		skb->truesize += PAGE_SIZE;
++
++		if (ftgmac030_rxdes_last_segment(rxdes))
++			done = true;
++
++		ftgmac030_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
++
++		ftgmac030_rx_pointer_advance(priv);
++		rxdes = ftgmac030_current_rxdes(priv);
++	} while (!done);
++
++	/* Small frames are copied into linear part of skb to free one page */
++	if (skb->len <= 128) {
++		skb->truesize -= PAGE_SIZE;
++		__pskb_pull_tail(skb, skb->len);
++	} else {
++		/* We pull the minimum amount into linear part */
++		__pskb_pull_tail(skb, ETH_HLEN);
++	}
++
++#ifdef CONFIG_FTGMAC030_PTP
++	ftgmac030_rx_hwtstamp(priv, skb);
++#endif
++	skb->protocol = eth_type_trans(skb, netdev);
++
++	netdev->stats.rx_packets++;
++	netdev->stats.rx_bytes += skb->len;
++
++	if(show_rx_pkg) {
++	    printk("<rx pkg=");
++	    for(i = 0; i < 10; i++)
++	        printk("0x%02x ", *(skb->data + i));
++        printk(">\n");
++    }
++
++	/* push packet to protocol stack */
++	napi_gro_receive(&priv->napi, skb);
++
++	(*processed)++;
++	return true;
++}
++
++/******************************************************************************
++ * internal functions (transmit descriptor)
++ *****************************************************************************/
++static void ftgmac030_txdes_reset(struct ftgmac030_txdes *txdes)
++{
++	/* clear all except end of ring bit */
++	txdes->txdes0 &= cpu_to_le32(FTGMAC030_TXDES0_EDOTR);
++	txdes->txdes1 = 0;
++	txdes->txdes2 = 0;
++	txdes->txdes3 = 0;
++}
++
++static bool ftgmac030_txdes_owned_by_dma(struct ftgmac030_txdes *txdes)
++{
++	return txdes->txdes0 & cpu_to_le32(FTGMAC030_TXDES0_TXDMA_OWN);
++}
++
++static void ftgmac030_txdes_set_dma_own(struct ftgmac030_txdes *txdes)
++{
++	/*
++	 * Make sure dma own bit will not be set before any other
++	 * descriptor fields.
++	 */
++	wmb();
++	txdes->txdes0 |= cpu_to_le32(FTGMAC030_TXDES0_TXDMA_OWN);
++}
++
++static void ftgmac030_txdes_set_end_of_ring(struct ftgmac030_txdes *txdes)
++{
++	txdes->txdes0 |= cpu_to_le32(FTGMAC030_TXDES0_EDOTR);
++}
++
++static void ftgmac030_txdes_set_first_segment(struct ftgmac030_txdes *txdes)
++{
++	txdes->txdes0 |= cpu_to_le32(FTGMAC030_TXDES0_FTS);
++}
++
++static void ftgmac030_txdes_set_last_segment(struct ftgmac030_txdes *txdes)
++{
++	txdes->txdes0 |= cpu_to_le32(FTGMAC030_TXDES0_LTS);
++}
++
++static void ftgmac030_txdes_set_buffer_size(struct ftgmac030_txdes *txdes,
++					    unsigned int len)
++{
++	txdes->txdes0 |= cpu_to_le32(FTGMAC030_TXDES0_TXBUF_SIZE(len));
++}
++
++static void ftgmac030_txdes_set_txint(struct ftgmac030_txdes *txdes)
++{
++	txdes->txdes1 |= cpu_to_le32(FTGMAC030_TXDES1_TXIC);
++}
++
++static void ftgmac030_txdes_set_tcpcs(struct ftgmac030_txdes *txdes)
++{
++	txdes->txdes1 |= cpu_to_le32(FTGMAC030_TXDES1_TCP_CHKSUM);
++}
++
++static void ftgmac030_txdes_set_udpcs(struct ftgmac030_txdes *txdes)
++{
++	txdes->txdes1 |= cpu_to_le32(FTGMAC030_TXDES1_UDP_CHKSUM);
++}
++
++static void ftgmac030_txdes_set_ipcs(struct ftgmac030_txdes *txdes)
++{
++	txdes->txdes1 |= cpu_to_le32(FTGMAC030_TXDES1_IP_CHKSUM);
++}
++
++static void ftgmac030_txdes_set_ipv6(struct ftgmac030_txdes *txdes)
++{
++	txdes->txdes1 |= cpu_to_le32(FTGMAC030_TXDES1_IPV6_PKT);
++}
++
++static void ftgmac030_txdes_set_dma_addr(struct ftgmac030_txdes *txdes,
++					 dma_addr_t addr)
++{
++	txdes->txdes3 = cpu_to_le32(addr);
++}
++
++static dma_addr_t ftgmac030_txdes_get_dma_addr(struct ftgmac030_txdes *txdes)
++{
++	return le32_to_cpu(txdes->txdes3);
++}
++
++/*
++ * txdes2 is not used by hardware. We use it to keep track of socket buffer.
++ * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu().
++ */
++static void ftgmac030_txdes_set_skb(struct ftgmac030_txdes *txdes,
++				    struct sk_buff *skb)
++{
++	txdes->txdes2 = (unsigned int)skb;
++}
++
++static struct sk_buff *ftgmac030_txdes_get_skb(struct ftgmac030_txdes *txdes)
++{
++	return (struct sk_buff *)txdes->txdes2;
++}
++
++/******************************************************************************
++ * internal functions (transmit)
++ *****************************************************************************/
++static int ftgmac030_next_tx_pointer(int pointer)
++{
++	return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
++}
++
++static void ftgmac030_tx_pointer_advance(struct ftgmac030 *priv)
++{
++	priv->tx_pointer = ftgmac030_next_tx_pointer(priv->tx_pointer);
++}
++
++static void ftgmac030_tx_clean_pointer_advance(struct ftgmac030 *priv)
++{
++	priv->tx_clean_pointer = ftgmac030_next_tx_pointer(priv->tx_clean_pointer);
++}
++
++static struct ftgmac030_txdes *ftgmac030_current_txdes(struct ftgmac030 *priv)
++{
++	return &priv->descs->txdes[priv->tx_pointer];
++}
++
++static struct ftgmac030_txdes *
++ftgmac030_current_clean_txdes(struct ftgmac030 *priv)
++{
++	return &priv->descs->txdes[priv->tx_clean_pointer];
++}
++
++static bool ftgmac030_tx_complete_packet(struct ftgmac030 *priv)
++{
++	struct net_device *netdev = priv->netdev;
++	struct ftgmac030_txdes *txdes;
++	struct sk_buff *skb;
++	dma_addr_t map;
++
++	spin_lock(&priv->tx_lock);
++	if (priv->tx_pending == 0)
++		goto out;
++
++	txdes = ftgmac030_current_clean_txdes(priv);
++
++	if (ftgmac030_txdes_owned_by_dma(txdes))
++		goto out;
++
++	spin_unlock(&priv->tx_lock);
++
++	skb = ftgmac030_txdes_get_skb(txdes);
++	map = ftgmac030_txdes_get_dma_addr(txdes);
++
++	netdev->stats.tx_packets++;
++	netdev->stats.tx_bytes += skb->len;
++
++	dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
++
++	dev_kfree_skb(skb);
++
++	ftgmac030_txdes_reset(txdes);
++
++	ftgmac030_tx_clean_pointer_advance(priv);
++
++	spin_lock(&priv->tx_lock);
++	priv->tx_pending--;
++	spin_unlock(&priv->tx_lock);
++
++	return true;
++
++out:
++	spin_unlock(&priv->tx_lock);
++	return false;
++}
++
++#ifdef CONFIG_FTGMAC030_PTP
++/**
++ * ftgmac030_tx_hwtstamp_work - check for Tx time stamp
++ * @work: pointer to work struct
++ *
++ * This work function polls the TSYNCTXCTL valid bit to determine when a
++ * timestamp has been taken for the current stored skb.  The timestamp must
++ * be for this skb because only one such packet is allowed in the queue.
++ */
++static void ftgmac030_tx_hwtstamp_work(struct work_struct *work)
++{
++	struct ftgmac030 *priv = container_of(work, struct ftgmac030,
++					      tx_hwtstamp_work);
++	u32 tsmp_valid;
++
++	if (!priv->tx_hwtstamp_skb)
++		return;
++
++	tsmp_valid = ioread32(priv->base + FTGMAC030_REG_ISR);
++	tsmp_valid &= FTGMAC030_INT_TX_TMSP_VALID;
++	if (tsmp_valid) {
++		struct skb_shared_hwtstamps hwtstamps;
++		unsigned long flags;
++		u64 txstmp;
++
++		spin_lock_irqsave(&priv->systim_lock, flags);
++		txstmp = ioread32(priv->base + FTGMAC030_REG_PTP_TX_SEC) * NSEC_PER_SEC;
++		txstmp += ioread32(priv->base + FTGMAC030_REG_PTP_TX_NSEC);
++		spin_unlock_irqrestore(&priv->systim_lock, flags);
++
++		memset(&hwtstamps, 0, sizeof(hwtstamps));
++		hwtstamps.hwtstamp = ns_to_ktime(txstmp);
++
++		skb_tstamp_tx(priv->tx_hwtstamp_skb, &hwtstamps);
++		dev_kfree_skb_any(priv->tx_hwtstamp_skb);
++		priv->tx_hwtstamp_skb = NULL;
++
++		iowrite32(tsmp_valid, priv->base + FTGMAC030_REG_ISR);
++	} else {
++		/* reschedule to check later */
++		schedule_work(&priv->tx_hwtstamp_work);
++	}
++}
++#endif
++
++static void ftgmac030_tx_complete(struct ftgmac030 *priv)
++{
++	struct net_device *netdev = priv->netdev;
++
++	while (ftgmac030_tx_complete_packet(priv)) {
++		netif_wake_queue(netdev);
++	}
++}
++
++static int ftgmac030_xmit(struct ftgmac030 *priv, struct sk_buff *skb,
++			  dma_addr_t map)
++{
++	struct net_device *netdev = priv->netdev;
++	struct ftgmac030_txdes *txdes;
++	int i;
++	unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
++
++	txdes = ftgmac030_current_txdes(priv);
++	ftgmac030_tx_pointer_advance(priv);
++
++	/* setup TX descriptor */
++	ftgmac030_txdes_set_skb(txdes, skb);
++	ftgmac030_txdes_set_dma_addr(txdes, map);
++	ftgmac030_txdes_set_buffer_size(txdes, len);
++
++	ftgmac030_txdes_set_first_segment(txdes);
++	ftgmac030_txdes_set_last_segment(txdes);
++	ftgmac030_txdes_set_txint(txdes);
++	if (skb->ip_summed == CHECKSUM_PARTIAL) {
++		__be16 protocol = skb->protocol;
++
++		if (protocol == cpu_to_be16(ETH_P_IP)) {
++			u8 ip_proto = ip_hdr(skb)->protocol;
++
++			ftgmac030_txdes_set_ipcs(txdes);
++
++			if (ip_proto == IPPROTO_TCP)
++				ftgmac030_txdes_set_tcpcs(txdes);
++			else if (ip_proto == IPPROTO_UDP)
++				ftgmac030_txdes_set_udpcs(txdes);
++		} else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
++			ftgmac030_txdes_set_ipv6(txdes);
++			ftgmac030_txdes_set_tcpcs(txdes);
++			ftgmac030_txdes_set_udpcs(txdes);
++		}
++	}
++
++#ifdef CONFIG_FTGMAC030_PTP
++	if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
++		     !priv->tx_hwtstamp_skb)) {
++		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
++		priv->tx_hwtstamp_skb = skb_get(skb);
++		schedule_work(&priv->tx_hwtstamp_work);
++	} else {
++		skb_tx_timestamp(skb);
++	}
++#endif
++	spin_lock(&priv->tx_lock);
++
++	/* start transmit */
++	ftgmac030_txdes_set_dma_own(txdes);
++
++	priv->tx_pending++;
++	if (priv->tx_pending == TX_QUEUE_ENTRIES) {
++		netif_stop_queue(netdev);
++		if (show_rx_dbg)
++			printk("MAC tx queue full, stop\n");
++	}
++
++	spin_unlock(&priv->tx_lock);
++
++	if(show_tx_pkg) {
++	    printk("<tx pkg=");
++	    for(i = 0; i < len; i++)
++	        printk("0x%02x ", *(skb->data + i));
++        printk(">\n");
++    }
++
++	ftgmac030_txdma_normal_prio_start_polling(priv);
++
++	return NETDEV_TX_OK;
++}
++
++/******************************************************************************
++ * internal functions (buffer)
++ *****************************************************************************/
++static int ftgmac030_alloc_rx_page(struct ftgmac030 *priv,
++				   struct ftgmac030_rxdes *rxdes, gfp_t gfp)
++{
++	struct net_device *netdev = priv->netdev;
++	struct page *page;
++	dma_addr_t map;
++
++	page = alloc_page(gfp);
++	if (!page) {
++		if (net_ratelimit())
++			netdev_err(netdev, "failed to allocate rx page\n");
++		return -ENOMEM;
++	}
++
++	map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
++	if (unlikely(dma_mapping_error(priv->dev, map))) {
++		if (net_ratelimit())
++			netdev_err(netdev, "failed to map rx page\n");
++		__free_page(page);
++		return -ENOMEM;
++	}
++
++	ftgmac030_rxdes_set_page(rxdes, page);
++	ftgmac030_rxdes_set_dma_addr(rxdes, map);
++	ftgmac030_rxdes_set_dma_own(rxdes);
++	return 0;
++}
++
++static void ftgmac030_free_buffers(struct ftgmac030 *priv)
++{
++	int i;
++
++	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
++		struct ftgmac030_rxdes *rxdes = &priv->descs->rxdes[i];
++		struct page *page = ftgmac030_rxdes_get_page(rxdes);
++		dma_addr_t map = ftgmac030_rxdes_get_dma_addr(rxdes);
++
++		if (!page)
++			continue;
++
++		dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
++		__free_page(page);
++	}
++
++	for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
++		struct ftgmac030_txdes *txdes = &priv->descs->txdes[i];
++		struct sk_buff *skb = ftgmac030_txdes_get_skb(txdes);
++		dma_addr_t map = ftgmac030_txdes_get_dma_addr(txdes);
++
++		if (!skb)
++			continue;
++
++		dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
++		dev_kfree_skb(skb);
++	}
++
++	dma_free_coherent(priv->dev, sizeof(struct ftgmac030_descs),
++			  priv->descs, priv->descs_dma_addr);
++}
++
++static int ftgmac030_alloc_buffers(struct ftgmac030 *priv)
++{
++	int i;
++
++	priv->descs = dma_zalloc_coherent(priv->dev,
++					  sizeof(struct ftgmac030_descs),
++					  &priv->descs_dma_addr, GFP_ATOMIC);
++	if (!priv->descs)
++		return -ENOMEM;
++
++	netdev_info(priv->netdev, "rx descs %p, tx descs %p\n",
++		    &priv->descs->rxdes[0], &priv->descs->txdes[0]);
++
++	/* initialize RX ring */
++	ftgmac030_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
++
++	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
++		struct ftgmac030_rxdes *rxdes = &priv->descs->rxdes[i];
++
++		if (ftgmac030_alloc_rx_page(priv, rxdes, GFP_ATOMIC))
++			goto err;
++	}
++
++	/* initialize TX ring */
++	ftgmac030_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
++	return 0;
++
++err:
++	ftgmac030_free_buffers(priv);
++	return -ENOMEM;
++}
++
++/******************************************************************************
++ * internal functions (mdio)
++ *****************************************************************************/
++static void ftgmac030_adjust_link(struct net_device *netdev)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	struct phy_device *phydev = priv->phydev;
++	int ier;
++
++#if 0//ndef CONFIG_PLATFORM_GM8210
++	if (phydev->speed == 1000) {//justin
++//gisr = (gisr == 2) ? PHY_INTERFACE_MODE_RGMII_RXID : (gisr == 1) ? PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_GMII;	    
++	    if(interface_type())
++		    return;
++	}
++#endif	
++	if (phydev->speed == priv->old_speed && phydev->duplex == priv->old_duplex)
++		return;
++
++	if (phydev->speed == 0)
++		    return;
++
++	printk("phy speed is %d, %s duplex\n", phydev->speed, phydev->duplex ? "full" : "half");
++	
++	priv->old_speed = phydev->speed;
++	priv->old_duplex = phydev->duplex;
++
++	ier = ioread32(priv->base + FTGMAC030_REG_IER);
++
++	/* disable all interrupts */
++	iowrite32(0, priv->base + FTGMAC030_REG_IER);
++
++	netif_stop_queue(netdev);
++#if 1
++	ftgmac030_stop_hw(priv);
++#else
++	priv->rx_pointer = 0;
++	priv->tx_clean_pointer = 0;
++	priv->tx_pointer = 0;
++	priv->tx_pending = 0;
++
++	ftgmac030_reset_hw(priv);
++#endif
++	netif_start_queue(netdev);
++	ftgmac030_init_hw(priv);
++	ftgmac030_start_hw(priv, phydev->speed, phydev->duplex);
++
++	/* re-enable interrupts */
++	iowrite32(ier, priv->base + FTGMAC030_REG_IER);
++}
++
++static int ftgmac030_mii_probe(struct ftgmac030 *priv)
++{
++	struct net_device *netdev = priv->netdev;
++	struct phy_device *phydev = NULL;
++	int i, gisr;
++
++	/* search for connect PHY device */
++	for (i = 0; i < PHY_MAX_ADDR; i++) {
++		struct phy_device *tmp = priv->mii_bus->phy_map[i];
++
++		if (tmp) {
++			phydev = tmp;
++			break;
++		}
++	}
++
++	/* now we are supposed to have a proper phydev, to attach to... */
++	if (!phydev) {
++		netdev_info(netdev, "%s: no PHY found\n", netdev->name);
++		return -ENODEV;
++	}
++
++	gisr = ioread32(priv->base + FTGMAC030_REG_GISR);
++
++	/* RGMII interface about Extened PHY Specific Control Register(offset 20): 
++	 * if need to set RGMII Receive Timing Control use PHY_INTERFACE_MODE_RGMII_RXID
++	 * if need to set RGMII Transmit Timing Control use PHY_INTERFACE_MODE_RGMII_TXID
++	 * If need to set both use PHY_INTERFACE_MODE_RGMII_ID
++	 * Otherwise use PHY_INTERFACE_MODE_RGMII
++	 */
++	gisr = (gisr == 2) ? PHY_INTERFACE_MODE_RGMII_RXID : (gisr == 1) ? PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_GMII;
++	phydev = phy_connect(netdev, dev_name(&phydev->dev),
++			     &ftgmac030_adjust_link, 0, gisr);
++
++	if (IS_ERR(phydev)) {
++		netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
++		return PTR_ERR(phydev);
++	}
++
++	priv->phydev = phydev;
++	return 0;
++}
++
++/******************************************************************************
++ * struct mii_bus functions
++ *****************************************************************************/
++static int ftgmac030_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
++{
++	struct net_device *netdev = bus->priv;
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	unsigned int phycr;
++	int i;
++
++	phycr = FTGMAC030_PHYCR_ST(1) | FTGMAC030_PHYCR_OP(2) |
++		FTGMAC030_PHYCR_PHYAD(phy_addr) |
++		FTGMAC030_PHYCR_REGAD(regnum) |
++		FTGMAC030_PHYCR_MIIRD | mdc_cycthr;
++
++	iowrite32(phycr, priv->base + FTGMAC030_REG_PHYCR);
++
++	for (i = 0; i < 100; i++) {
++		phycr = ioread32(priv->base + FTGMAC030_REG_PHYCR);
++
++		if ((phycr & FTGMAC030_PHYCR_MIIRD) == 0) {
++			int data;
++
++			data = ioread32(priv->base + FTGMAC030_REG_PHYDATA);
++			data = FTGMAC030_PHYDATA_MIIRDATA(data);
++			
++			if(show_phy)
++			    printk("<r:adr=%d,reg=%d,data=0x%x>", phy_addr, regnum, data);
++			    
++			return data;
++		}
++
++		wait_status(1);
++	}
++
++	netdev_err(netdev, "mdio read timed out\n");
++	return -EIO;
++}
++
++static int ftgmac030_mdiobus_write(struct mii_bus *bus, int phy_addr,
++				   int regnum, u16 value)
++{
++	struct net_device *netdev = bus->priv;
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	unsigned int phycr;
++	int data;
++	int i;
++
++    if(show_phy)
++        printk("<w:adr=%d,reg=%d,data=0x%x>", phy_addr, regnum, value);
++
++	phycr = FTGMAC030_PHYCR_ST(1) | FTGMAC030_PHYCR_OP(1) |
++		FTGMAC030_PHYCR_PHYAD(phy_addr) |
++		FTGMAC030_PHYCR_REGAD(regnum) |
++		FTGMAC030_PHYCR_MIIWR | mdc_cycthr;
++
++	data = FTGMAC030_PHYDATA_MIIWDATA(value);
++
++	iowrite32(data, priv->base + FTGMAC030_REG_PHYDATA);
++	iowrite32(phycr, priv->base + FTGMAC030_REG_PHYCR);
++
++	for (i = 0; i < 100; i++) {
++		phycr = ioread32(priv->base + FTGMAC030_REG_PHYCR);
++
++		if ((phycr & FTGMAC030_PHYCR_MIIWR) == 0)
++			return 0;
++
++		wait_status(1);
++	}
++
++	netdev_err(netdev, "mdio write timed out\n");
++	return -EIO;
++}
++
++static int ftgmac030_mdiobus_reset(struct mii_bus *bus)
++{
++	return 0;
++}
++
++/******************************************************************************
++ * struct ethtool_ops functions
++ *****************************************************************************/
++static void ftgmac030_get_drvinfo(struct net_device *netdev,
++				  struct ethtool_drvinfo *info)
++{
++	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
++	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
++	strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
++}
++
++static int ftgmac030_get_settings(struct net_device *netdev,
++				  struct ethtool_cmd *cmd)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++
++	return phy_ethtool_gset(priv->phydev, cmd);
++}
++
++static int ftgmac030_set_settings(struct net_device *netdev,
++				  struct ethtool_cmd *cmd)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++
++	return phy_ethtool_sset(priv->phydev, cmd);
++}
++
++static int ftgmac030_get_regs_len(struct net_device *netdev)
++{
++#define FTGMAC030_REGS_LEN 0x52
++	return FTGMAC030_REGS_LEN * sizeof(u32);
++}
++
++static void ftgmac030_get_regs(struct net_device *netdev,
++			       struct ethtool_regs *regs, void *p)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	u32 *regs_buff = p;
++	int i;
++
++	regs->version = 0x470030;
++
++	for (i=0; i < FTGMAC030_REGS_LEN; i++)
++		regs_buff[i] = ioread32(priv->base + (i * 0x4));
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
++static int e1000e_get_ts_info(struct net_device *netdev,
++			      struct ethtool_ts_info *info)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	u32 maccr;
++
++	info->so_timestamping =
++		SOF_TIMESTAMPING_TX_SOFTWARE |
++		SOF_TIMESTAMPING_RX_SOFTWARE |
++		SOF_TIMESTAMPING_SOFTWARE;
++	info->phc_index = -1;
++
++	maccr = ioread32(priv->base + FTGMAC030_REG_MACCR);
++	if (!(maccr & FTGMAC030_MACCR_PTP_EN))
++		return 0;
++
++	info->so_timestamping |= (SOF_TIMESTAMPING_TX_HARDWARE |
++				  SOF_TIMESTAMPING_RX_HARDWARE |
++				  SOF_TIMESTAMPING_RAW_HARDWARE);
++
++	info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
++
++	info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
++			    (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
++			    (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
++			    (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
++			    (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
++			    (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
++			    (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
++			    (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
++			    (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
++			    (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
++			    (1 << HWTSTAMP_FILTER_ALL));
++
++	if (priv->ptp_clock)
++		info->phc_index = ptp_clock_index(priv->ptp_clock);
++
++	return 0;
++}
++#endif
++
++static void ftgmac030_get_ethtool_stats(struct net_device *netdev,
++		struct ethtool_stats *stats, u64 *data)
++{
++	int i = 0;
++
++    for (i = 0; i < 8; i++)
++        data[i] = ((unsigned long *)&netdev->stats)[i];
++
++    data[i++] = netdev->stats.rx_length_errors;
++    data[i++] = netdev->stats.rx_crc_errors;
++    data[i++] = netdev->stats.rx_frame_errors;
++    data[i++] = netdev->stats.rx_fifo_errors;//justin 0xC8
++}
++
++static const struct {
++	const char name[ETH_GSTRING_LEN];
++} sundance_stats[] = {
++	{ "rx_packets" },
++	{ "tx_packets" },
++	{ "rx_bytes" },
++	{ "tx_bytes" },
++	{ "rx_errors" },
++	{ "tx_errors" },
++	{ "rx_dropped" },
++	{ "tx_dropped" },
++	
++	{ "rx_length_errors" },
++	{ "rx_crc_errors" },
++	{ "rx_frame_errors" },
++	{ "rx_fifo_errors" },	
++};
++
++static void get_strings(struct net_device *dev, u32 stringset,
++		u8 *data)
++{
++	if (stringset == ETH_SS_STATS)
++		memcpy(data, sundance_stats, sizeof(sundance_stats));
++}
++
++static int get_sset_count(struct net_device *dev, int sset)
++{
++	switch (sset) {
++	case ETH_SS_STATS:
++		return ARRAY_SIZE(sundance_stats);
++	default:
++		return -EOPNOTSUPP;
++	}
++}
++
++static const struct ethtool_ops ftgmac030_ethtool_ops = {
++	.set_settings		= ftgmac030_set_settings,
++	.get_settings		= ftgmac030_get_settings,
++	.get_drvinfo		= ftgmac030_get_drvinfo,
++	.get_link		= ethtool_op_get_link,
++	.get_regs_len		= ftgmac030_get_regs_len,
++	.get_regs		= ftgmac030_get_regs,
++	.get_ethtool_stats = ftgmac030_get_ethtool_stats,
++	.get_strings = get_strings,
++	.get_sset_count = get_sset_count,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
++	.get_ts_info		= ftgmac030_get_ts_info,
++#endif
++};
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++static irqreturn_t ftgmac030_interrupt(int irq, void *dev_id)
++{
++	struct net_device *netdev = dev_id;
++	struct ftgmac030 *priv = netdev_priv(netdev);
++
++	/* Disable interrupts for polling */
++	iowrite32(0, priv->base + FTGMAC030_REG_IER);
++
++	if (likely(netif_running(netdev))) {
++		napi_schedule(&priv->napi);
++	}
++
++	return IRQ_HANDLED;
++}
++
++/******************************************************************************
++ * struct napi_struct functions
++ *****************************************************************************/
++static int ftgmac030_poll(struct napi_struct *napi, int budget)
++{
++	struct ftgmac030 *priv = container_of(napi, struct ftgmac030, napi);
++	struct net_device *netdev = priv->netdev;
++	unsigned int status;
++	bool completed = true;
++	int rx = 0;
++
++	status = ioread32(priv->base + FTGMAC030_REG_ISR);
++	iowrite32(status, priv->base + FTGMAC030_REG_ISR);
++
++	if (status & (FTGMAC030_INT_RPKT_BUF | FTGMAC030_INT_NO_RXBUF)) {
++		/*
++		 * FTGMAC030_INT_RPKT_BUF:
++		 *	RX DMA has received packets into RX buffer successfully
++		 *
++		 * FTGMAC030_INT_NO_RXBUF:
++		 *	RX buffer unavailable
++		 */
++		bool retry;
++
++		do {
++			retry = ftgmac030_rx_packet(priv, &rx);
++		} while (retry && rx < budget);
++
++		if (retry && rx == budget)
++			completed = false;
++	}
++
++	if (status & (FTGMAC030_INT_XPKT_ETH | FTGMAC030_INT_XPKT_LOST)) {
++		/*
++		 * FTGMAC030_INT_XPKT_ETH:
++		 *	packet transmitted to ethernet successfully
++		 *
++		 * FTGMAC030_INT_XPKT_LOST:
++		 *	packet transmitted to ethernet lost due to late
++		 *	collision or excessive collision
++		 */
++		ftgmac030_tx_complete(priv);
++	}
++
++	if (status & FTGMAC030_INT_AHB_ERR)
++    	netdev_info(netdev, "AHB bus err\n");
++
++	if (status & FTGMAC030_INT_NO_RXBUF) {
++		/* RX buffer unavailable */
++		netdev->stats.rx_over_errors++;
++	}
++
++	if (status & FTGMAC030_INT_RPKT_LOST) {
++		/* received packet lost due to RX FIFO full */
++		netdev->stats.rx_fifo_errors++;
++    	netdev->stats.rx_errors++;
++    	if (show_rx_dbg)
++    		netdev_info(netdev, "MAC INT rx fifo full, lose\n");
++	}
++
++	if (completed) {
++		napi_complete(napi);
++
++		/* enable all interrupts */
++		iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTGMAC030_REG_IER);
++	}
++
++	return rx;
++}
++
++/******************************************************************************
++ * struct net_device_ops functions
++ *****************************************************************************/
++static int ftgmac030_open(struct net_device *netdev)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	int err;
++
++	err = ftgmac030_alloc_buffers(priv);
++	if (err) {
++		netdev_err(netdev, "failed to allocate buffers\n");
++		goto err_alloc;
++	}
++
++	err = request_irq(priv->irq, ftgmac030_interrupt, 0, netdev->name, netdev);
++	if (err) {
++		netdev_err(netdev, "failed to request irq %d\n", priv->irq);
++		goto err_irq;
++	}
++
++	priv->rx_pointer = 0;
++	priv->tx_clean_pointer = 0;
++	priv->tx_pointer = 0;
++	priv->tx_pending = 0;
++
++	err = ftgmac030_reset_hw(priv);
++	if (err)
++		goto err_hw;
++
++	ftgmac030_init_hw(priv);
++	ftgmac030_start_hw(priv, priv->old_speed, priv->old_duplex);
++
++	phy_start(priv->phydev);
++
++	napi_enable(&priv->napi);
++	netif_start_queue(netdev);
++
++	/* enable all interrupts */
++	iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTGMAC030_REG_IER);
++	return 0;
++
++err_hw:
++	free_irq(priv->irq, netdev);
++err_irq:
++	ftgmac030_free_buffers(priv);
++err_alloc:
++	return err;
++}
++
++static int ftgmac030_stop(struct net_device *netdev)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++
++	/* disable all interrupts */
++	iowrite32(0, priv->base + FTGMAC030_REG_IER);
++
++	netif_stop_queue(netdev);
++	napi_disable(&priv->napi);
++	phy_stop(priv->phydev);
++
++	ftgmac030_stop_hw(priv);
++	free_irq(priv->irq, netdev);
++	ftgmac030_free_buffers(priv);
++
++	return 0;
++}
++
++static int ftgmac030_hard_start_xmit(struct sk_buff *skb,
++				     struct net_device *netdev)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	dma_addr_t map;
++
++	if (unlikely(skb->len > MAX_PKT_SIZE)) {
++		if (net_ratelimit())
++			netdev_dbg(netdev, "tx packet too big\n");
++
++		netdev->stats.tx_dropped++;
++		dev_kfree_skb(skb);
++		return NETDEV_TX_OK;
++	}
++
++	map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
++	if (unlikely(dma_mapping_error(priv->dev, map))) {
++		/* drop packet */
++		if (net_ratelimit())
++			netdev_err(netdev, "map socket buffer failed\n");
++
++		netdev->stats.tx_dropped++;
++		dev_kfree_skb(skb);
++		return NETDEV_TX_OK;
++	}
++	return ftgmac030_xmit(priv, skb, map);
++}
++
++#ifdef CONFIG_FTGMAC030_PTP
++/*
++ *
++ * ftgmac030_config_hwtstamp - configure the hwtstamp registers and enable/disable
++ * @adapter: board private structure
++ * Outgoing time stamping can be enabled and disabled. Play nice and
++ * disable it when requested, although it shouldn't cause any overhead
++ * when no packet needs it. At most one packet in the queue may be
++ * marked for time stamping, otherwise it would be impossible to tell
++ * for sure to which packet the hardware time stamp belongs.
++ *
++ * Incoming time stamping has to be configured via the hardware filters.
++ * Not all combinations are supported, in particular event type has to be
++ * specified. Matching the kind of event packet is not supported, with the
++ * exception of "all V2 events regardless of level 2 or 4".
++ **/
++static int ftgmac030_config_hwtstamp(struct ftgmac030 *adapter)
++{
++	struct hwtstamp_config *config = &adapter->hwtstamp_config;
++	struct timespec now;
++	u32 tsync_tx_ctl = 1;
++	u32 tsync_rx_ctl = 1;
++	u32 maccr;
++
++	switch (config->tx_type) {
++	case HWTSTAMP_TX_OFF:
++		tsync_tx_ctl = 0;
++		break;
++	case HWTSTAMP_TX_ON:
++		break;
++	default:
++		return -ERANGE;
++	}
++
++	switch (config->rx_filter) {
++	case HWTSTAMP_FILTER_NONE:
++		tsync_rx_ctl = 0;
++		break;
++	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
++	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
++	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
++	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
++	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
++	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
++	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
++	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
++	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
++	case HWTSTAMP_FILTER_PTP_V2_EVENT:
++	case HWTSTAMP_FILTER_PTP_V2_SYNC:
++	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
++	case HWTSTAMP_FILTER_ALL:
++		break;
++	default:
++		return -ERANGE;
++	}
++
++	maccr = ioread32(adapter->base + FTGMAC030_REG_MACCR);
++
++	/* enable/disable Tx/Rx h/w time stamping */
++	if (tsync_tx_ctl ||  tsync_rx_ctl) {
++		maccr |= FTGMAC030_MACCR_PTP_EN;
++
++		/* reset the ns time counter */
++		getnstimeofday(&now);
++		iowrite32(now.tv_sec, adapter->base + FTGMAC030_REG_PTP_TM_SEC);
++		iowrite32(now.tv_nsec, adapter->base + FTGMAC030_REG_PTP_TM_NSEC);
++	} else {
++		maccr &= ~FTGMAC030_MACCR_PTP_EN;
++ 	}
++
++	iowrite32(maccr, adapter->base + FTGMAC030_REG_MACCR);
++
++	return 0;
++}
++
++static int ftgmac030_hwtstamp_set(struct net_device *netdev, struct ifreq *ifr)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	struct hwtstamp_config config;
++	int ret_val;
++
++	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
++		return -EFAULT;
++
++	priv->hwtstamp_config = config;
++
++	ret_val = ftgmac030_config_hwtstamp(priv);
++	if (ret_val)
++		return ret_val;
++
++	config = priv->hwtstamp_config;
++
++	switch (config.rx_filter) {
++	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
++	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
++	case HWTSTAMP_FILTER_PTP_V2_SYNC:
++	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
++	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
++	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
++		/* With V2 type filters which specify a Sync or Delay Request,
++		 * Path Delay Request/Response messages are also time stamped
++		 * by hardware so notify the caller the requested packets plus
++		 * some others are time stamped.
++		 */
++		config.rx_filter = HWTSTAMP_FILTER_SOME;
++		break;
++	default:
++		break;
++	}
++
++	return copy_to_user(ifr->ifr_data, &config,
++			    sizeof(config)) ? -EFAULT : 0;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
++static int ftgmac030_hwtstamp_get(struct net_device *netdev, struct ifreq *ifr)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++
++	return copy_to_user(ifr->ifr_data, &priv->hwtstamp_config,
++			    sizeof(priv->hwtstamp_config)) ? -EFAULT : 0;
++}
++#endif
++#endif	//CONFIG_FTGMAC030_PTP
++
++static unsigned int ftgmac030_get_ht_index(unsigned char *mac_addr)
++{
++	unsigned int crc32 = ether_crc(ETH_ALEN, mac_addr);
++	crc32 = ~crc32;
++	crc32 = bitrev8(crc32 & 0xff) |
++			(bitrev8((crc32 >> 8) & 0xff) << 8) |
++			(bitrev8((crc32 >> 16) & 0xff) << 16) |
++			(bitrev8((crc32 >> 24) & 0xff) << 24);
++
++	/* return MSB 6 bits */
++	return ((unsigned char)(crc32 >> 26));
++}
++
++static void ftgmac030_set_rx_mode(struct net_device *netdev)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++	unsigned int maccr = ioread32(priv->base + FTGMAC030_REG_MACCR);
++
++	if (show_rx_dbg)
++		printk("set rx mode = 0x%x\n", netdev->flags);
++
++	/* clear filter flags */
++	maccr &= ~(FTGMAC030_MACCR_RX_BROADPKT | FTGMAC030_MACCR_RX_MULTIPKT | FTGMAC030_MACCR_HT_MULTI_EN | FTGMAC030_MACCR_RX_ALL);
++	if (netdev->flags & IFF_PROMISC) {
++		maccr |= FTGMAC030_MACCR_RX_ALL;
++	}
++
++	if (netdev->flags & IFF_ALLMULTI) {
++		maccr |= FTGMAC030_MACCR_RX_MULTIPKT;
++	}
++
++	if (netdev->flags & IFF_BROADCAST) {
++		maccr |= FTGMAC030_MACCR_RX_BROADPKT;
++	}
++
++	if (netdev->flags & IFF_MULTICAST) {
++		unsigned int maht0 = 0x0;
++		unsigned int maht1 = 0x0;
++		struct netdev_hw_addr *ha;
++
++		maccr |= FTGMAC030_MACCR_HT_MULTI_EN;
++		/* clear hash table*/
++		iowrite32(maht0, priv->base + FTGMAC030_REG_MAHT0);
++		iowrite32(maht1, priv->base + FTGMAC030_REG_MAHT1);
++		/* set hash table */
++		netdev_for_each_mc_addr(ha, netdev) {
++			unsigned char ht_index = ftgmac030_get_ht_index(ha->addr);
++			if (ht_index < 32)
++				maht0 |= (1 << ht_index);
++			else
++				maht1 |= (1 << (ht_index - 32));
++		}
++		iowrite32(maht0, priv->base + FTGMAC030_REG_MAHT0);
++		iowrite32(maht1, priv->base + FTGMAC030_REG_MAHT1);
++	}
++
++	iowrite32(maccr, priv->base + FTGMAC030_REG_MACCR);
++}
++
++/* optional */
++static int ftgmac030_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
++{
++	struct ftgmac030 *priv = netdev_priv(netdev);
++
++	switch (cmd) {
++#ifdef CONFIG_FTGMAC030_PTP
++	case SIOCSHWTSTAMP:
++		return ftgmac030_hwtstamp_set(netdev, ifr);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
++	case SIOCGHWTSTAMP:
++		return ftgmac030_hwtstamp_get(netdev, ifr);
++#endif
++#endif
++	default:
++		return phy_mii_ioctl(priv->phydev, ifr, cmd);
++	}
++}
++
++static const struct net_device_ops ftgmac030_netdev_ops = {
++	.ndo_open		= ftgmac030_open,
++	.ndo_stop		= ftgmac030_stop,
++	.ndo_start_xmit		= ftgmac030_hard_start_xmit,
++	.ndo_set_mac_address	= eth_mac_addr,
++	.ndo_validate_addr	= eth_validate_addr,
++	.ndo_do_ioctl		= ftgmac030_do_ioctl,
++	.ndo_set_rx_mode	= ftgmac030_set_rx_mode,
++};
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftgmac030_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	int irq;
++	struct net_device *netdev;
++	struct ftgmac030 *priv;
++	char *ptr = NULL, *ptr_end;
++    u8 addr[6];
++	char ethaddr[18];
++	int err;
++	int i;
++
++	if (!pdev)
++		return -ENODEV;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res)
++		return -ENXIO;
++
++	irq = platform_get_irq(pdev, 0);
++	if (irq < 0)
++		return irq;
++
++	/* setup net_device */
++	netdev = alloc_etherdev(sizeof(*priv));
++	if (!netdev) {
++		err = -ENOMEM;
++		goto err_alloc_etherdev;
++	}
++
++	SET_NETDEV_DEV(netdev, &pdev->dev);
++
++	SET_ETHTOOL_OPS(netdev, &ftgmac030_ethtool_ops);
++	netdev->netdev_ops = &ftgmac030_netdev_ops;
++	netdev->features = (NETIF_F_IP_CSUM | 
++			    NETIF_F_IPV6_CSUM |
++			    /*NETIF_F_RXCSUM |*/
++			    NETIF_F_GRO);
++
++	platform_set_drvdata(pdev, netdev);
++
++	/* setup private data */
++	priv = netdev_priv(netdev);
++	priv->netdev = netdev;
++	priv->dev = &pdev->dev;
++
++	spin_lock_init(&priv->tx_lock);
++
++	/* initialize NAPI */
++	netif_napi_add(netdev, &priv->napi, ftgmac030_poll, 64);
++
++	/* map io memory */
++	priv->res = request_mem_region(res->start, resource_size(res),
++				       dev_name(&pdev->dev));
++	if (!priv->res) {
++		dev_err(&pdev->dev, "Could not reserve memory region\n");
++		err = -ENOMEM;
++		goto err_req_mem;
++	}
++
++	priv->base = ioremap(res->start, resource_size(res));
++	if (!priv->base) {
++		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
++		err = -EIO;
++		goto err_ioremap;
++	}
++
++	priv->irq = irq;
++	if(mac_scu_init(priv->irq) < 0){
++		err = -EIO;
++		goto err_alloc_mdiobus;
++	}
++	
++	/* initialize mdio bus */
++	set_mac_clock(priv->irq);
++
++#ifdef CONFIG_FTGMAC030_PTP
++	spin_lock_init(&priv->systim_lock);
++	INIT_WORK(&priv->tx_hwtstamp_work, ftgmac030_tx_hwtstamp_work);
++#endif
++
++	i = ioread32(priv->base + FTGMAC030_REG_GISR) & 0x3;
++	mdc_cycthr = (i > 0) ? 0x68 : 0x34;
++
++	/* initialize mdio bus */
++	priv->mii_bus = mdiobus_alloc();
++	if (!priv->mii_bus) {
++		err = -EIO;
++		goto err_alloc_mdiobus;
++	}
++
++	if(irq == MAC_FTGMAC030_0_IRQ){
++		priv->mii_bus->name = "ftgmac030-0-mdio";
++		snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, DRV_NAME);
++	}else{
++		priv->mii_bus->name = "ftgmac030-1-mdio";
++		snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, DRV_1_NAME);	
++	}
++
++	priv->mii_bus->priv = netdev;
++	priv->mii_bus->read = ftgmac030_mdiobus_read;
++	priv->mii_bus->write = ftgmac030_mdiobus_write;
++	priv->mii_bus->reset = ftgmac030_mdiobus_reset;
++	priv->mii_bus->irq = priv->phy_irq;
++
++	for (i = 0; i < PHY_MAX_ADDR; i++)
++		priv->mii_bus->irq[i] = PHY_POLL;
++
++	err = mdiobus_register(priv->mii_bus);
++	if (err) {
++		dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
++		goto err_register_mdiobus;
++	}
++
++	err = ftgmac030_mii_probe(priv);
++	if (err) {
++		dev_err(&pdev->dev, "MII Probe failed!\n");
++		goto err_mii_probe;
++	}
++
++	/* register network device */
++	err = register_netdev(netdev);
++	if (err) {
++		dev_err(&pdev->dev, "Failed to register netdev\n");
++		goto err_register_netdev;
++	}
++
++	netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base);
++
++#ifdef CONFIG_FTGMAC030_PTP
++	/* This is value at the time FPGA verification.
++	 * Change based on SOC real period.
++	 * Inside ftgmac030_ptp_init function, FTGMAC030_REG_PTP_NS_PERIOD 
++	 * will be read, make sure it has valid value. 
++	 */
++	iowrite32(20, priv->base + FTGMAC030_REG_PTP_NS_PERIOD);
++
++	/* init PTP hardware clock */
++	ftgmac030_ptp_init(priv);
++#endif
++
++	if (!is_valid_ether_addr(netdev->dev_addr)) {
++        ethaddr[17] = '\0';	    
++	    	if(irq == MAC_FTGMAC030_0_IRQ){	        
++            ptr = strstr(command_line, "ethaddr=");
++            if (ptr)
++                memcpy(ethaddr, ptr + 8, 17 * sizeof(char));
++        }
++        else{
++            ptr = strstr(command_line, "eth1addr=");
++            if (ptr)
++                memcpy(ethaddr, ptr + 9, 17 * sizeof(char));
++        }
++    
++        if (ptr) {
++            printk(KERN_NOTICE "ethaddr parsed from commandline: %s\n", ethaddr);
++            ptr_end = ethaddr;
++            
++            for (i = 0; i <= 5; i++) {
++                addr[i] = simple_strtol(ptr_end, &ptr_end, 16) |
++                          simple_strtol(ptr_end, &ptr_end, 16) << 4;
++                          ptr_end++; /* skip ":" in  ethaddr */
++                          
++            }
++            memcpy(netdev->dev_addr, addr, sizeof(addr));
++            
++        } else {
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,3,0)
++		    random_ether_addr(netdev->dev_addr);
++#else
++		    eth_hw_addr_random(netdev);
++#endif
++    		netdev_info(netdev, "generated random MAC address %pM\n",
++    			    netdev->dev_addr);
++		}
++	}
++
++	ftgmac_reg_debug->data = netdev;
++	return 0;
++
++err_register_netdev:
++	phy_disconnect(priv->phydev);
++err_mii_probe:
++	mdiobus_unregister(priv->mii_bus);
++err_register_mdiobus:
++	mdiobus_free(priv->mii_bus);
++err_alloc_mdiobus:
++	iounmap(priv->base);
++err_ioremap:
++	release_resource(priv->res);
++err_req_mem:
++	netif_napi_del(&priv->napi);
++	free_netdev(netdev);
++err_alloc_etherdev:
++	return err;
++}
++
++static int __exit ftgmac030_remove(struct platform_device *pdev)
++{
++	struct net_device *netdev;
++	struct ftgmac030 *priv;
++
++	netdev = platform_get_drvdata(pdev);
++	priv = netdev_priv(netdev);
++
++	unregister_netdev(netdev);
++
++	phy_disconnect(priv->phydev);
++	mdiobus_unregister(priv->mii_bus);
++	mdiobus_free(priv->mii_bus);
++
++	mac_scu_close(priv->irq);
++
++	iounmap(priv->base);
++	release_resource(priv->res);
++
++	netif_napi_del(&priv->napi);
++	free_netdev(netdev);
++	return 0;
++}
++
++
++#ifdef CONFIG_FTGMAC030_DRIVER_0
++static struct platform_driver ftgmac030_driver = {
++	.probe		= ftgmac030_probe,
++	.remove		= __exit_p(ftgmac030_remove),
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++#endif
++
++#ifdef CONFIG_FTGMAC030_DRIVER_1
++static struct platform_driver ftgmac030_1_driver = {
++	.probe		= ftgmac030_probe,
++	.remove		= __exit_p(ftgmac030_remove),
++	.driver		= {
++		.name	= DRV_1_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++#endif
++
++static int ftgmac_proc_tx_write(struct file *file, const char *buffer, unsigned long count,
++                                void *data)
++{
++    show_tx_pkg = *buffer - 48;
++    //printk("buf=%d,%d\n", *buffer, show_tx_pkg);
++    return count;
++}
++
++static int ftgmac_proc_rx_write(struct file *file, const char *buffer, unsigned long count,
++                                void *data)
++{
++    show_rx_pkg = *buffer - 48;
++    return count;
++}
++
++static int ftgmac_proc_phy_write(struct file *file, const char *buffer, unsigned long count,
++                                void *data)
++{
++    show_phy = *buffer - 48;
++    return count;
++}
++
++static int ftgmac_proc_rx_dbg_write(struct file *file, const char *buffer, unsigned long count,
++                                void *data)
++{
++    show_rx_dbg = *buffer - 48;
++    //printk("buf=%d,%d\n", *buffer, show_rx_dbg);
++    return count;
++}
++
++static int ftgmac_proc_reg_dbg_read(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    struct net_device *netdev = data;
++    struct ftgmac030 *priv = netdev_priv(netdev);
++    unsigned int i, len = 0;
++
++	len += sprintf(page + len, "GMAC version %s, queue number tx = %d, rx = %d\n", DRV_VERSION, TX_QUEUE_ENTRIES, RX_QUEUE_ENTRIES);
++	for(i = 0; i < 15; i++) {
++    	len += sprintf(page + len, "reg%2x: %8x %8x %8x %8x\n", i * 16, ioread32(priv->base + i * 16 + 0), 
++    			ioread32(priv->base + i * 16 + 4), ioread32(priv->base + i * 16 + 8), ioread32(priv->base + i * 16 + 12));
++	}
++    return len;
++}
++
++int register_mac0 = 0, register_mac1 = 0;
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftgmac030_init(void)
++{
++    int result = -ENODEV;
++  
++    command_line = kmalloc(COMMAND_LINE_SIZE, GFP_ATOMIC);
++    memcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
++     
++	pr_info("Loading version " DRV_VERSION " ...\n");
++	pr_info("Tx queue number = %d, Rx queue number = %d\n", TX_QUEUE_ENTRIES, RX_QUEUE_ENTRIES);
++
++    ftgmac_proc = create_proc_entry("ftgmac", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (ftgmac_proc == NULL) {
++        printk(KERN_ERR "Error to create driver ftgmac proc\n");
++        goto exit_init;
++    }
++    
++    ftgmac_tx_pkg_debug = create_proc_entry("show_tx", S_IRUGO, ftgmac_proc);
++    if (ftgmac_tx_pkg_debug == NULL)
++        panic("Fail to create proc ftgmac tx pkg!\n");
++
++    ftgmac_tx_pkg_debug->write_proc = ftgmac_proc_tx_write;
++
++    ftgmac_rx_pkg_debug = create_proc_entry("show_rx", S_IRUGO, ftgmac_proc);
++    if (ftgmac_rx_pkg_debug == NULL)
++        panic("Fail to create proc ftgmac rx pkg!\n");
++
++    ftgmac_rx_pkg_debug->write_proc = ftgmac_proc_rx_write;
++
++    ftgmac_phy_debug = create_proc_entry("show_phy", S_IRUGO, ftgmac_proc);
++    if (ftgmac_phy_debug == NULL)
++        panic("Fail to create proc ftgmac phy!\n");
++
++    ftgmac_phy_debug->write_proc = ftgmac_proc_phy_write;
++
++    ftgmac_rx_debug = create_proc_entry("show_rx_dbg", S_IRUGO, ftgmac_proc);
++    if (ftgmac_rx_debug == NULL)
++        panic("Fail to create proc ftgmac rx dbg!\n");
++
++    ftgmac_rx_debug->write_proc = ftgmac_proc_rx_dbg_write;
++
++    ftgmac_reg_debug = create_proc_entry("reg_dbg", S_IRUGO, ftgmac_proc);
++    if (ftgmac_reg_debug == NULL)
++        panic("Fail to create proc ftgmac reg dbg!\n");
++
++    ftgmac_reg_debug->read_proc = ftgmac_proc_reg_dbg_read;
++
++#ifdef CONFIG_FTGMAC030_DRIVER_0
++    platform_device_register(&ftgmac030_0_device);
++    
++    result = platform_driver_register(&ftgmac030_driver);
++    if (result < 0) {
++        platform_device_unregister(&ftgmac030_0_device);
++        goto exit_init;
++    }
++#endif
++#ifdef CONFIG_FTGMAC030_DRIVER_1
++    platform_device_register(&ftgmac030_1_device);
++    
++    result = platform_driver_register(&ftgmac030_1_driver);
++    if (result < 0) {
++        platform_device_unregister(&ftgmac030_1_device);
++        goto exit_init;
++    }
++#endif
++
++exit_init:		    	
++	return result;
++}
++
++static void __exit ftgmac030_exit(void)
++{
++    if (ftgmac_tx_pkg_debug != NULL)
++        remove_proc_entry(ftgmac_tx_pkg_debug->name, ftgmac_proc);
++
++    if (ftgmac_rx_pkg_debug != NULL)
++        remove_proc_entry(ftgmac_rx_pkg_debug->name, ftgmac_proc);
++
++    if (ftgmac_phy_debug != NULL)
++        remove_proc_entry(ftgmac_phy_debug->name, ftgmac_proc);
++
++    if (ftgmac_rx_debug != NULL)
++        remove_proc_entry(ftgmac_rx_debug->name, ftgmac_proc);
++
++    if (ftgmac_reg_debug != NULL)
++        remove_proc_entry(ftgmac_reg_debug->name, ftgmac_proc); 
++                
++    if (ftgmac_proc != NULL)
++        remove_proc_entry(ftgmac_proc->name, NULL);
++
++#ifdef CONFIG_FTGMAC030_DRIVER_0
++    platform_driver_unregister(&ftgmac030_driver);
++    platform_device_unregister(&ftgmac030_0_device);
++#endif
++#ifdef CONFIG_FTGMAC030_DRIVER_1
++    platform_driver_unregister(&ftgmac030_1_driver);
++    platform_device_unregister(&ftgmac030_1_device);
++#endif    
++}
++
++module_init(ftgmac030_init);
++module_exit(ftgmac030_exit);
++
++MODULE_AUTHOR("Bing-Yao Luo <bjluo@faraday-tech.com>");
++MODULE_DESCRIPTION("ftgmac030 driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/ethernet/faraday/ftgmac030.h b/drivers/net/ethernet/faraday/ftgmac030.h
+new file mode 100644
+index 00000000..fa0a13b5
+--- /dev/null
++++ b/drivers/net/ethernet/faraday/ftgmac030.h
+@@ -0,0 +1,367 @@
++/*
++ * Faraday FTGMAC030 Gigabit Ethernet
++ *
++ * (C) Copyright 2014-2016 Faraday Technology
++ * Bing-Yao Luo <bjluo@faraday-tech.com>
++ *
++ * 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.
++ */
++
++#ifndef __FTGMAC030_H
++#define __FTGMAC030_H
++
++#include <linux/types.h>
++#include <linux/spinlock.h>
++#include <linux/phy.h>
++#include <linux/netdevice.h>
++#include <linux/clocksource.h>
++#include <linux/net_tstamp.h>
++#include <linux/ptp_clock_kernel.h>
++#include <linux/ptp_classify.h>
++
++#define DRV_NAME	"ftgmac100-0"
++#define DRV_1_NAME	"ftgmac100-1"
++
++#define RX_QUEUE_ENTRIES	256	/* must be power of 2 */
++#define TX_QUEUE_ENTRIES	512	/* must be power of 2 */
++
++//#define CONFIG_FTGMAC030_PTP
++
++#define FTGMAC030_REG_ISR               0x00
++#define FTGMAC030_REG_IER               0x04
++#define FTGMAC030_REG_MAC_MADR          0x08
++#define FTGMAC030_REG_MAC_LADR          0x0c
++#define FTGMAC030_REG_MAHT0             0x10
++#define FTGMAC030_REG_MAHT1             0x14
++#define FTGMAC030_REG_NPTXPD            0x18
++#define FTGMAC030_REG_RXPD              0x1c
++#define FTGMAC030_REG_NPTXR_BADR        0x20
++#define FTGMAC030_REG_RXR_BADR          0x24
++#define FTGMAC030_REG_HPTXPD            0x28
++#define FTGMAC030_REG_HPTXR_BADR	0x2c
++#define FTGMAC030_REG_TXITC		0x30
++#define FTGMAC030_REG_RXITC		0x34
++#define FTGMAC030_REG_APTC		0x38
++#define FTGMAC030_REG_DBLAC		0x3C
++#define FTGMAC030_REG_DMAFIFOS          0x40
++#define FTGMAC030_REG_TPAFCR            0x48
++#define FTGMAC030_REG_RBSR              0x4c
++#define FTGMAC030_REG_MACCR		0x50
++#define FTGMAC030_REG_MACSR		0x54
++#define FTGMAC030_REG_TM		0x58
++#define FTGMAC030_REG_PHYCR		0x60
++#define FTGMAC030_REG_PHYDATA           0x64
++#define FTGMAC030_REG_FCR               0x68
++#define FTGMAC030_REG_BPR               0x6c
++#define FTGMAC030_REG_WOLCR             0x70
++#define FTGMAC030_REG_WOLSR             0x74
++#define FTGMAC030_REG_WFCRC             0x78
++#define FTGMAC030_REG_WFBM1             0x80
++#define FTGMAC030_REG_WFBM2             0x84
++#define FTGMAC030_REG_WFBM3             0x88
++#define FTGMAC030_REG_WFBM4		0x8c
++#define FTGMAC030_REG_NPTXR_PTR	        0x90
++#define FTGMAC030_REG_HPTXR_PTR	        0x94
++#define FTGMAC030_REG_RXR_PTR	        0x98
++#define FTGMAC030_REG_TX_CNT		0xA0
++#define FTGMAC030_REG_TX_MCOL_SCOL	0xA4
++#define FTGMAC030_REG_TX_ECOL_FAIL	0xA8
++#define FTGMAC030_REG_TX_LCOL_UND	0xAc
++#define FTGMAC030_REG_RX_CNT		0xB0
++#define FTGMAC030_REG_RX_BC		0xB4
++#define FTGMAC030_REG_RX_MC		0xB8
++#define FTGMAC030_REG_RX_PF_AEP         0xBC
++#define FTGMAC030_REG_RX_RUNT           0xC0
++#define FTGMAC030_REG_RX_CRCER_FTL      0xC4
++#define FTGMAC030_REG_RX_COL_LOST       0xC8
++#define FTGMAC030_REG_BIST       	0xCC
++#define FTGMAC030_REG_GISR       	0xE8
++#define FTGMAC030_REG_EEE       	0xF0
++#define FTGMAC030_REG_REVR              0xF4
++#define FTGMAC030_REG_FEAR              0xF8
++#define FTGMAC030_REG_PTP_TX_SEC        0x110 /* Sync and Delay_req */
++#define FTGMAC030_REG_PTP_TX_NSEC       0x114
++#define FTGMAC030_REG_PTP_RX_SEC        0x118
++#define FTGMAC030_REG_PTP_RX_NSEC       0x11C
++#define FTGMAC030_REG_PTP_TX_P_SEC      0x120 /* PDelay_req and PDelay_resp */
++#define FTGMAC030_REG_PTP_TX_P_NSEC     0x124
++#define FTGMAC030_REG_PTP_RX_P_SEC      0x128
++#define FTGMAC030_REG_PTP_RX_P_NSEC     0x12C
++#define FTGMAC030_REG_PTP_TM_NNSEC      0x130
++#define FTGMAC030_REG_PTP_TM_NSEC       0x134
++#define FTGMAC030_REG_PTP_TM_SEC        0x138
++#define FTGMAC030_REG_PTP_NS_PERIOD     0x13C /* max is 255 ns */
++#define FTGMAC030_REG_PTP_NNS_PERIOD    0x140 /* max is 0.999999999 ns */
++#define FTGMAC030_REG_PTP_PERIOD_INCR   0x144 /* add xx ns every xx cycles */
++#define FTGMAC030_REG_PTP_ADJ_VAL	0x148
++
++/*
++ * Interrupt status register & interrupt enable register
++ */
++#define FTGMAC030_INT_RPKT_BUF          (1 << 0)
++#define FTGMAC030_INT_RPKT_FIFO         (1 << 1)
++#define FTGMAC030_INT_NO_RXBUF          (1 << 2)
++#define FTGMAC030_INT_RPKT_LOST         (1 << 3)
++#define FTGMAC030_INT_XPKT_ETH          (1 << 4)
++#define FTGMAC030_INT_XPKT_FIFO         (1 << 5)
++#define FTGMAC030_INT_NO_NPTXBUF        (1 << 6)
++#define FTGMAC030_INT_XPKT_LOST         (1 << 7)
++#define FTGMAC030_INT_AHB_ERR           (1 << 8)
++#define FTGMAC030_INT_PHYSTS_CHG        (1 << 9)
++#define FTGMAC030_INT_NO_HPTXBUF        (1 << 10)
++#define FTGMAC030_INT_SYNC_IN           (1 << 17)
++#define FTGMAC030_INT_SYNC_OUT          (1 << 18)
++#define FTGMAC030_INT_DELAY_REQ_IN      (1 << 19)
++#define FTGMAC030_INT_DELAY_REQ_OUT     (1 << 20)
++#define FTGMAC030_INT_PDELAY_REQ_IN     (1 << 21)
++#define FTGMAC030_INT_PDELAY_REQ_OUT    (1 << 22)
++#define FTGMAC030_INT_PDELAY_RESP_IN    (1 << 23)
++#define FTGMAC030_INT_PDELAY_RESP_OUT   (1 << 24)
++#define FTGMAC030_INT_TX_TMSP_VALID     (FTGMAC030_INT_SYNC_OUT | FTGMAC030_INT_DELAY_REQ_OUT | \
++					 FTGMAC030_INT_PDELAY_REQ_OUT | FTGMAC030_INT_PDELAY_RESP_OUT)
++#define FTGMAC030_INT_RX_TMSP_VALID     (FTGMAC030_INT_SYNC_IN | FTGMAC030_INT_DELAY_REQ_IN | \
++					 FTGMAC030_INT_PDELAY_REQ_IN | FTGMAC030_INT_PDELAY_RESP_IN)
++
++/*
++ * Interrupt timer control register
++ */
++#define FTGMAC030_ITC_RXINT_CNT(x)	(((x) & 0xf) << 0)
++#define FTGMAC030_ITC_RXINT_THR(x)	(((x) & 0x7) << 4)
++#define FTGMAC030_ITC_RXINT_TIME_SEL	(1 << 7)
++#define FTGMAC030_ITC_TXINT_CNT(x)	(((x) & 0xf) << 8)
++#define FTGMAC030_ITC_TXINT_THR(x)	(((x) & 0x7) << 12)
++#define FTGMAC030_ITC_TXINT_TIME_SEL	(1 << 15)
++
++/*
++ * Automatic polling timer control register
++ */
++#define FTGMAC030_APTC_RXPOLL_CNT(x)	(((x) & 0xf) << 0)
++#define FTGMAC030_APTC_RXPOLL_TIME_SEL	(1 << 4)
++#define FTGMAC030_APTC_TXPOLL_CNT(x)	(((x) & 0xf) << 8)
++#define FTGMAC030_APTC_TXPOLL_TIME_SEL	(1 << 12)
++
++/*
++ * DMA burst length and arbitration control register
++ */
++#define FTGMAC030_DBLAC_RXFIFO_LTHR(x)	(((x) & 0x7) << 0)
++#define FTGMAC030_DBLAC_RXFIFO_HTHR(x)	(((x) & 0x7) << 3)
++#define FTGMAC030_DBLAC_RX_THR_EN	(1 << 6)
++#define FTGMAC030_DBLAC_RXBURST_SIZE(x)	(((x) & 0x3) << 8)
++#define FTGMAC030_DBLAC_TXBURST_SIZE(x)	(((x) & 0x3) << 10)
++#define FTGMAC030_DBLAC_RXDES_SIZE(x)	(((x) & 0xf) << 12)
++#define FTGMAC030_DBLAC_TXDES_SIZE(x)	(((x) & 0xf) << 16)
++#define FTGMAC030_DBLAC_IFG_CNT(x)	(((x) & 0x7) << 20)
++#define FTGMAC030_DBLAC_IFG_INC		(1 << 23)
++
++/*
++ * DMA FIFO status register
++ */
++#define FTGMAC030_DMAFIFOS_RXDMA1_SM(dmafifos)	((dmafifos) & 0xf)
++#define FTGMAC030_DMAFIFOS_RXDMA2_SM(dmafifos)	(((dmafifos) >> 4) & 0xf)
++#define FTGMAC030_DMAFIFOS_RXDMA3_SM(dmafifos)	(((dmafifos) >> 8) & 0x7)
++#define FTGMAC030_DMAFIFOS_TXDMA1_SM(dmafifos)	(((dmafifos) >> 12) & 0xf)
++#define FTGMAC030_DMAFIFOS_TXDMA2_SM(dmafifos)	(((dmafifos) >> 16) & 0x3)
++#define FTGMAC030_DMAFIFOS_TXDMA3_SM(dmafifos)	(((dmafifos) >> 18) & 0xf)
++#define FTGMAC030_DMAFIFOS_RXFIFO_EMPTY		(1 << 26)
++#define FTGMAC030_DMAFIFOS_TXFIFO_EMPTY		(1 << 27)
++#define FTGMAC030_DMAFIFOS_RXDMA_GRANT		(1 << 28)
++#define FTGMAC030_DMAFIFOS_TXDMA_GRANT		(1 << 29)
++#define FTGMAC030_DMAFIFOS_RXDMA_REQ		(1 << 30)
++#define FTGMAC030_DMAFIFOS_TXDMA_REQ		(1 << 31)
++
++/*
++ * Receive buffer size register
++ */
++#define FTGMAC030_RBSR_SIZE(x)		((x) & 0x3fff)
++
++/*
++ * MAC control register
++ */
++#define FTGMAC030_MACCR_TXDMA_EN	(1 << 0)
++#define FTGMAC030_MACCR_RXDMA_EN	(1 << 1)
++#define FTGMAC030_MACCR_TXMAC_EN	(1 << 2)
++#define FTGMAC030_MACCR_RXMAC_EN	(1 << 3)
++#define FTGMAC030_MACCR_RX_ALL		(1 << 8)
++#define FTGMAC030_MACCR_HT_MULTI_EN	(1 << 9)
++#define FTGMAC030_MACCR_RX_MULTIPKT	(1 << 10)
++#define FTGMAC030_MACCR_RX_BROADPKT	(1 << 11)
++#define FTGMAC030_MACCR_RX_RUNT		(1 << 12)
++#define FTGMAC030_MACCR_JUMBO_LF	(1 << 13)
++#define FTGMAC030_MACCR_ENRX_IN_HALFTX	(1 << 14)
++#define FTGMAC030_MACCR_DISCARD_CRCERR	(1 << 16)
++#define FTGMAC030_MACCR_CRC_APD		(1 << 17)
++#define FTGMAC030_MACCR_REMOVE_VLAN	(1 << 18)
++#define FTGMAC030_MACCR_PTP_EN		(1 << 20)
++#define FTGMAC030_MACCR_LOOP_EN		(1 << 21)
++#define FTGMAC030_MACCR_HPTXR_EN	(1 << 22)
++#define FTGMAC030_MACCR_GIGA_MODE	(2 << 24)
++#define FTGMAC030_MACCR_FAST_MODE	(1 << 24)
++#define FTGMAC030_MACCR_FULLDUP		(1 << 26)
++#define FTGMAC030_MACCR_SW_RST		(1 << 31)
++
++/*
++ * PHY control register
++ */
++#define FTGMAC030_PHYCR_MDC_CYCTHR_MASK         0x3f
++#define FTGMAC030_PHYCR_MDC_CYCTHR(x)           ((x) & 0x3f)
++#define FTGMAC030_PHYCR_OP(x)           	(((x) & 0x3) << 14)
++#define FTGMAC030_PHYCR_ST(x)           	(((x) & 0x3) << 12)
++#define FTGMAC030_PHYCR_PHYAD(x)                (((x) & 0x1f) << 16)
++#define FTGMAC030_PHYCR_REGAD(x)                (((x) & 0x1f) << 21)
++#define FTGMAC030_PHYCR_MIIRD                   (1 << 26)
++#define FTGMAC030_PHYCR_MIIWR                   (1 << 27)
++
++/*
++ * PHY data register
++ */
++#define FTGMAC030_PHYDATA_MIIWDATA(x)           ((x) & 0xffff)
++#define FTGMAC030_PHYDATA_MIIRDATA(phydata)     (((phydata) >> 16) & 0xffff)
++
++/*
++ * Feature Register (0x44)
++ */
++#define FTGMAC030_FEAR_TFIFO_RSIZE(x) ((x & 0x70) >> 4)
++#define FTGMAC030_FEAR_RFIFO_RSIZE(x) ((x & 0x7) >> 0)
++
++/*
++ * Transmit descriptor, aligned to 16 bytes
++ */
++struct ftgmac030_txdes {
++	unsigned int	txdes0;
++	unsigned int	txdes1;
++	unsigned int	txdes2;	/* not used by HW */
++	unsigned int	txdes3;	/* TXBUF_BADR */
++} __attribute__ ((aligned(16)));
++
++#define FTGMAC030_TXDES0_TXBUF_SIZE(x)	((x) & 0x3fff)
++#define FTGMAC030_TXDES0_EDOTR		(1 << 15)
++#define FTGMAC030_TXDES0_CRC_ERR	(1 << 19)
++#define FTGMAC030_TXDES0_LTS		(1 << 28)
++#define FTGMAC030_TXDES0_FTS		(1 << 29)
++#define FTGMAC030_TXDES0_TXDMA_OWN	(1 << 31)
++
++#define FTGMAC030_TXDES1_VLANTAG_CI(x)	((x) & 0xffff)
++#define FTGMAC030_TXDES1_INS_VLANTAG	(1 << 16)
++#define FTGMAC030_TXDES1_TCP_CHKSUM	(1 << 17)
++#define FTGMAC030_TXDES1_UDP_CHKSUM	(1 << 18)
++#define FTGMAC030_TXDES1_IP_CHKSUM	(1 << 19)
++#define FTGMAC030_TXDES1_IPV6_PKT       (1 << 21)
++#define FTGMAC030_TXDES1_LLC		(1 << 22)
++#define FTGMAC030_TXDES1_TX2FIC		(1 << 30)
++#define FTGMAC030_TXDES1_TXIC		(1 << 31)
++
++/*
++ * Receive descriptor, aligned to 16 bytes
++ */
++struct ftgmac030_rxdes {
++	unsigned int	rxdes0;
++	unsigned int	rxdes1;
++	unsigned int	rxdes2;	/* not used by HW */
++	unsigned int	rxdes3;	/* RXBUF_BADR */
++} __attribute__ ((aligned(16)));
++
++#define FTGMAC030_RXDES0_VDBC		0x3fff
++#define FTGMAC030_RXDES0_EDORR		(1 << 15)
++#define FTGMAC030_RXDES0_MULTICAST	(1 << 16)
++#define FTGMAC030_RXDES0_BROADCAST	(1 << 17)
++#define FTGMAC030_RXDES0_RX_ERR		(1 << 18)
++#define FTGMAC030_RXDES0_CRC_ERR	(1 << 19)
++#define FTGMAC030_RXDES0_FTL		(1 << 20)
++#define FTGMAC030_RXDES0_RUNT		(1 << 21)
++#define FTGMAC030_RXDES0_RX_ODD_NB	(1 << 22)
++#define FTGMAC030_RXDES0_FIFO_FULL	(1 << 23)
++#define FTGMAC030_RXDES0_PAUSE_OPCODE	(1 << 24)
++#define FTGMAC030_RXDES0_PAUSE_FRAME	(1 << 25)
++#define FTGMAC030_RXDES0_LRS		(1 << 28)
++#define FTGMAC030_RXDES0_FRS		(1 << 29)
++#define FTGMAC030_RXDES0_RXPKT_RDY	(1 << 31)
++
++#define FTGMAC030_RXDES1_IPV6		(1 << 19)
++#define FTGMAC030_RXDES1_VLANTAG_CI	0xffff
++#define FTGMAC030_RXDES1_PROT_MASK	(0x3 << 20)
++#define FTGMAC030_RXDES1_PROT_NONIP	(0x0 << 20)
++#define FTGMAC030_RXDES1_PROT_IP	(0x1 << 20)
++#define FTGMAC030_RXDES1_PROT_TCPIP	(0x2 << 20)
++#define FTGMAC030_RXDES1_PROT_UDPIP	(0x3 << 20)
++#define FTGMAC030_RXDES1_LLC		(1 << 22)
++#define FTGMAC030_RXDES1_DF		(1 << 23)
++#define FTGMAC030_RXDES1_VLANTAG_AVAIL	(1 << 24)
++#define FTGMAC030_RXDES1_TCP_CHKSUM_ERR	(1 << 25)
++#define FTGMAC030_RXDES1_UDP_CHKSUM_ERR	(1 << 26)
++#define FTGMAC030_RXDES1_IP_CHKSUM_ERR	(1 << 27)
++
++/******************************************************************************
++ * private data
++ *****************************************************************************/
++struct ftgmac030_descs {
++	struct ftgmac030_rxdes rxdes[RX_QUEUE_ENTRIES];
++	struct ftgmac030_txdes txdes[TX_QUEUE_ENTRIES];
++};
++
++struct ftgmac030 {
++	struct resource *res;
++	void __iomem *base;
++	int irq;
++
++	struct ftgmac030_descs *descs;
++	dma_addr_t descs_dma_addr;
++
++	unsigned int rx_pointer;
++	unsigned int tx_clean_pointer;
++	unsigned int tx_pointer;
++	unsigned int tx_pending;
++
++	spinlock_t tx_lock;
++
++	struct net_device *netdev;
++	struct device *dev;
++	struct napi_struct napi;
++
++	struct mii_bus *mii_bus;
++	int phy_irq[PHY_MAX_ADDR];
++	struct phy_device *phydev;
++	int old_speed;
++	int old_duplex;
++
++#ifdef CONFIG_FTGMAC030_PTP
++	struct hwtstamp_config hwtstamp_config;
++	struct delayed_work systim_overflow_work;
++	struct sk_buff *tx_hwtstamp_skb;
++	struct work_struct tx_hwtstamp_work;
++	spinlock_t systim_lock;	/* protects SYSTIML/H regsters */
++	struct ptp_clock *ptp_clock;
++	struct ptp_clock_info ptp_clock_info;
++#endif
++
++};
++
++void wait_status(int millisecond);
++int mac_scu_init(int irq);
++void mac_scu_close(int irq);
++void set_mac_clock(int irq);
++void set_MDC_CLK(struct ftgmac030 *priv);
++
++#ifdef CONFIG_FTGMAC030_PTP
++
++#define FTGMAC030_SYSTIM_OVERFLOW_PERIOD	(HZ * 60 * 60)
++
++extern void ftgmac030_ptp_init(struct ftgmac030 *adapter);
++extern u32 REG_PTP_TM_SEC;
++extern u32 REG_PTP_TM_NSEC;
++extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info);
++extern int ptp_clock_unregister(struct ptp_clock *ptp);
++#endif
++
++#endif /* __FTGMAC030_H */
+diff --git a/drivers/net/ethernet/faraday/ftgmac030_platform.c b/drivers/net/ethernet/faraday/ftgmac030_platform.c
+new file mode 100644
+index 00000000..8a450074
+--- /dev/null
++++ b/drivers/net/ethernet/faraday/ftgmac030_platform.c
+@@ -0,0 +1,210 @@
++/*
++ * Faraday FTGMAC030 Ethernet
++ *
++ * (C) Copyright 2009 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/version.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/mii.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/phy.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include "ftgmac030.h"
++#include <mach/ftpmu010.h>
++#include <mach/fmem.h>
++#include <linux/gpio.h>
++
++static int mac_fd = 0, mac_fd_1 = 0;
++
++#ifdef CONFIG_FTGMAC030_DRIVER_0
++static pmuReg_t pmu_reg[] = {
++#ifndef CONFIG_FPGA
++    //{reg_off, bits_mask, lock_bits, init_val, init_mask},
++    {0x54, (0x1 << 2), (0x1 << 2), 0, (0x1 << 2)},	//reset off
++    {0x60, (0x1 << 21), (0x1 << 21), 0, (0x1 << 21)},	//gating clock on
++    {0x6C, (0x1 << 19), (0x1 << 19), 0, (0x1 << 19)},	//gating clock on
++    {0x70, (0x1 << 11), (0x1 << 11), 0, (0x1 << 11)},	//gating clock on
++    {0x188, (0x3F << 0), (0x3F << 0), (0x1 << 0), (0x3F << 0)},	//cntp pvalue
++    {0x188, (0x3F << 8), (0x3F << 8), (0x4 << 8), (0x3F << 8)},//PHY cntp pvalue
++#endif
++};
++
++static pmuRegInfo_t pmu_reg_info = {
++    DRV_NAME,
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_PLL1,
++    &pmu_reg[0]
++};
++#endif
++
++#ifdef CONFIG_FTGMAC030_DRIVER_1
++static pmuReg_t pmu_reg_1[] = {
++#ifndef CONFIG_FPGA
++    //{reg_off, bits_mask, lock_bits, init_val, init_mask},
++    {0x54, (0x1 << 3), (0x1 << 3), 0, (0x1 << 3)},	//reset off
++    {0x60, (0x1 << 22), (0x1 << 22), 0, (0x1 << 22)},	//gating clock on
++    {0x6C, (0x1 << 20), (0x1 << 20), 0, (0x1 << 20)},	//gating clock on
++    {0x70, (0x1 << 12), (0x1 << 12), 0, (0x1 << 12)},	//gating clock on
++    {0x188, (0x3F << 16), (0x3F << 16), (0x1 << 16), (0x3F << 16)},	//cntp pvalue
++    {0x188, (0x3F << 24), (0x3F << 24), (0x4 << 24), (0x3F << 24)},//PHY cntp pvalue
++#endif
++};
++static pmuRegInfo_t pmu_reg_info_1 = {
++    DRV_1_NAME,
++    ARRAY_SIZE(pmu_reg_1),
++    ATTR_TYPE_PLL1,
++    &pmu_reg_1[0]
++};
++#endif
++
++void wait_status(int millisecond)
++{
++    if (in_interrupt() || in_atomic()){
++        mdelay(millisecond);
++    }else{           
++        set_current_state(TASK_INTERRUPTIBLE);
++        schedule_timeout((HZ / 1000) * millisecond);
++    }
++}
++
++
++void set_mac_clock(int irq)
++{
++    int tmp_fd;
++    
++    if(irq == MAC_FTGMAC030_0_IRQ)
++	    tmp_fd = mac_fd;
++    else
++	    tmp_fd = mac_fd_1;
++
++#ifndef CONFIG_FPGA
++#ifdef CONFIG_PLATFORM_GM8220
++    if(irq == MAC_FTGMAC100_0_IRQ){
++        //set phy X_GMII0_CLK_IN
++        ftpmu010_write_reg(tmp_fd, 0x28, 0, (0x1 << 29));
++        //set MAC p-value
++        ftpmu010_write_reg(tmp_fd, 0x70, 0, 0x1);
++    }
++    
++    if(irq == MAC_FTGMAC100_1_IRQ){
++        //set phy X_GMII1_CLK_IN
++        ftpmu010_write_reg(tmp_fd, 0x28, 0, (0x1 << 28));
++        //set pin-mux
++        ftpmu010_write_reg(tmp_fd, 0x50, 0, (0x1 << 14));        
++        //set MAC p-value
++        ftpmu010_write_reg(tmp_fd, 0x70, 0, (0x1 << 5));    
++    }
++#endif
++#endif
++}
++
++void set_MDC_CLK(struct ftgmac030 *priv)
++{
++#ifndef CONFIG_FPGA
++#ifndef CONFIG_PLATFORM_GM8210  /* 8210 can use default value *///???????????????????????
++    int tmp;
++    
++    tmp = ioread32(priv->base + FTGMAC030_OFFSET_PHYCR);
++    tmp &= ~FTGMAC030_PHYCR_MDC_CYCTHR_MASK;
++    tmp |= FTGMAC030_PHYCR_MDC_CYCTHR(0xF0);
++    iowrite32(tmp, priv->base + FTGMAC030_OFFSET_PHYCR);
++#endif
++#endif
++}
++
++int mac_scu_init(int irq)
++{
++    if(irq == MAC_FTGMAC030_0_IRQ){
++    	mac_fd = ftpmu010_register_reg(&pmu_reg_info);
++     	if (mac_fd < 0) {
++            printk(KERN_ERR "MAC: %s register reg fail \n", __FUNCTION__);
++    	    return -1;
++    	}
++#ifndef CONFIG_FPGA
++#if defined(CONFIG_PLATFORM_GM8220) || defined(CONFIG_PLATFORM_GM8288)
++        ftpmu010_write_reg(mac_fd, 0xB4, 0, (0x1 << 11)); 
++#endif
++#endif
++    }
++
++#ifndef CONFIG_FPGA
++#ifdef CONFIG_PLATFORM_GM8220
++    if(irq == MAC_FTGMAC030_1_IRQ){
++    	mac_fd_1 = ftpmu010_register_reg(&pmu_reg_info_1);    
++     	if (mac_fd_1 < 0) {
++        	printk(KERN_ERR "MAC: %s register reg fail \n", __FUNCTION__);
++    	    return -1;
++    	}     	
++        ftpmu010_write_reg(mac_fd_1, 0xB4, 0, (0x1 << 13));
++    }
++#endif
++#endif  //CONFIG_FPGA
++    return 0; 
++}
++
++void mac_scu_close(int irq)
++{
++    //IP Clock off 
++    if(irq == MAC_FTGMAC030_0_IRQ){
++#ifndef CONFIG_FPGA
++#if defined(CONFIG_PLATFORM_GM8220) || defined(CONFIG_PLATFORM_GM8288)
++    	ftpmu010_write_reg(mac_fd, 0xB4, (0x1 << 14), (0x1 << 14)); 
++#endif
++#endif
++    	ftpmu010_deregister_reg(mac_fd);
++    }
++    else{
++#ifndef CONFIG_FPGA
++#if defined(CONFIG_PLATFORM_GM8220) || defined(CONFIG_PLATFORM_GM8288)
++    	ftpmu010_write_reg(mac_fd_1, 0xB4, (0x1 << 13), (0x1 << 13)); 
++#endif
++#endif
++    	ftpmu010_deregister_reg(mac_fd_1);
++    }
++}
++
++void mac_reset(void)
++{
++#ifndef CONFIG_FPGA
++    printk(KERN_NOTICE "HW reset\n");
++    ftpmu010_write_reg(mac_fd, 0xA0, 0, (0x1 << 18));
++    mdelay(1);
++    ftpmu010_write_reg(mac_fd, 0xA0, (0x1 << 18), (0x1 << 18));
++#endif
++} 
++
++/*  1-RMII or MII mode; 0-RGMII or GMII mode */
++int interface_type(void)
++{
++#ifndef CONFIG_FPGA
++#ifdef CONFIG_PLATFORM_GM8220
++    if((ftpmu010_read_reg(0xD8) & 0x7) == 0x5)
++        return 0;
++#endif
++#endif
++	return 1;
++}
+\ No newline at end of file
+diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
+index 47f85c33..45b1d577 100644
+--- a/drivers/net/ethernet/faraday/ftgmac100.c
++++ b/drivers/net/ethernet/faraday/ftgmac100.c
+@@ -21,6 +21,7 @@
+ 
+ #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+ 
++#include <linux/crc32.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/etherdevice.h>
+ #include <linux/ethtool.h>
+@@ -31,69 +32,157 @@
+ #include <linux/netdevice.h>
+ #include <linux/phy.h>
+ #include <linux/platform_device.h>
++#include <linux/vmalloc.h>
+ #include <net/ip.h>
+-
++#include <linux/gpio.h>
++#include <linux/timer.h>
++#include <asm/setup.h>
++#include <linux/proc_fs.h>
++#include <mach/gm_jiffies.h>
+ #include "ftgmac100.h"
+ 
+-#define DRV_NAME	"ftgmac100"
+-#define DRV_VERSION	"0.7"
++static int first_time = 0, MDIO_first_time = 1;
++static char show_tx_pkg = 0, show_rx_pkg = 0, show_phy = 0, show_rx_dbg = 0;
++static struct proc_dir_entry *ftgmac_proc = NULL, *ftgmac_tx_pkg_debug = NULL;
++static struct proc_dir_entry *ftgmac_rx_pkg_debug = NULL, *ftgmac_phy_debug = NULL, *ftgmac_rx_debug = NULL, *ftgmac_reg_debug = NULL;
++static char *command_line = NULL;
++
++/* ****************************************************************************
++ * array contains all platform devices
++ * ****************************************************************************/ 
++
++static u64 ftgmac100_dmamask = DMA_BIT_MASK(32);
++#if defined(CONFIG_FTGMAC100_DRIVER_0_MASTER) || defined(CONFIG_FTGMAC100_DRIVER_0_SLAVE)
++/*GMAC 0*/
++static struct resource ftgmac100_0_resource[] = {
++	{
++         .start  = MAC_FTGMAC100_0_PA_BASE,
++         .end        = MAC_FTGMAC100_0_PA_LIMIT,
++         .flags  = IORESOURCE_MEM,
++	},
++	{
++         .start  = MAC_FTGMAC100_0_IRQ,
++         .end        = MAC_FTGMAC100_0_IRQ,
++         .flags  = IORESOURCE_IRQ,
++	},
++};
+ 
+-#define RX_QUEUE_ENTRIES	256	/* must be power of 2 */
+-#define TX_QUEUE_ENTRIES	512	/* must be power of 2 */
++static void ftgmac100_0_release(struct device *dev)
++{
++    return;
++}
+ 
+-#define MAX_PKT_SIZE		1518
+-#define RX_BUF_SIZE		PAGE_SIZE	/* must be smaller than 0x3fff */
++static struct platform_device ftgmac100_0_device = {
++	.name	= DRV_NAME,
++	.id		= 0,
++	.num_resources	= ARRAY_SIZE(ftgmac100_0_resource),
++	.resource	= ftgmac100_0_resource,
++        .dev = {
++        	.dma_mask = &ftgmac100_dmamask,
++        	.coherent_dma_mask = DMA_BIT_MASK(32),
++        	.release = ftgmac100_0_release,
++        }, 	
++};
++#endif
++
++#if defined(CONFIG_FTGMAC100_DRIVER_1_MASTER) || defined(CONFIG_FTGMAC100_DRIVER_1_SLAVE)
++/*GMAC 1*/
++static struct resource ftgmac100_1_resource[] = {
++	{
++         .start  = MAC_FTGMAC100_1_PA_BASE,
++         .end        = MAC_FTGMAC100_1_PA_LIMIT,
++         .flags  = IORESOURCE_MEM,
++	},
++	{
++         .start  = MAC_FTGMAC100_1_IRQ,
++         .end        = MAC_FTGMAC100_1_IRQ,
++         .flags  = IORESOURCE_IRQ,
++	},
++};
++
++static void ftgmac100_1_release(struct device *dev)
++{
++    return;
++}
++
++static struct platform_device ftgmac100_1_device = {
++	.name	= DRV_1_NAME,
++	.id		= 1,
++	.num_resources	= ARRAY_SIZE(ftgmac100_1_resource),
++	.resource	= ftgmac100_1_resource,
++        .dev = {
++        	.dma_mask = &ftgmac100_dmamask,
++        	.coherent_dma_mask = DMA_BIT_MASK(32),
++        	.release = ftgmac100_1_release,
++        }, 	
++};
++#endif 
+ 
+ /******************************************************************************
+  * private data
+  *****************************************************************************/
+-struct ftgmac100_descs {
+-	struct ftgmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
+-	struct ftgmac100_txdes txdes[TX_QUEUE_ENTRIES];
+-};
+ 
+-struct ftgmac100 {
+-	struct resource *res;
+-	void __iomem *base;
+-	int irq;
++struct ftgmac100_rx_reg_offset {
++	unsigned int offset_rxpd;
++	unsigned int offset_rxr_badr;
++};
+ 
+-	struct ftgmac100_descs *descs;
+-	dma_addr_t descs_dma_addr;
++const struct ftgmac100_rx_reg_offset ftgmac100_rx_reg_offset[MAX_RX_QUEUES] = {
++	{FTGMAC100_OFFSET_RXPD, FTGMAC100_OFFSET_RXR_BADR}
++};
+ 
++struct ftgmac100_rx_ring {
++	unsigned int rx_num_entries;
++	u16 rx_queue_index;
++	dma_addr_t rx_dma_addr;
++	struct ftgmac100_rxdes *rxdes;
+ 	unsigned int rx_pointer;
++	unsigned int rx_offset_rxpd;
++	unsigned int rx_offset_rxr_badr;
++	struct net_device *netdev;
++	struct device *dev;
++};
++
++struct ftgmac100_tx_reg_offset {
++	unsigned int offset_txpd;
++	unsigned int offset_txr_badr;
++};
++
++const struct ftgmac100_tx_reg_offset ftgmac100_tx_reg_offset[MAX_TX_QUEUES] = {
++	{FTGMAC100_OFFSET_NPTXPD, FTGMAC100_OFFSET_NPTXR_BADR},
++	{FTGMAC100_OFFSET_HPTXPD, FTGMAC100_OFFSET_HPTXR_BADR}
++};
++
++struct ftgmac100_tx_ring {
++	unsigned int tx_num_entries;
++	u16 tx_queue_index;
++	dma_addr_t tx_dma_addr;
++	struct ftgmac100_txdes *txdes;
+ 	unsigned int tx_clean_pointer;
+ 	unsigned int tx_pointer;
+ 	unsigned int tx_pending;
+ 
+-	spinlock_t tx_lock;
+-
++	unsigned int tx_offset_txpd;
++	unsigned int tx_offset_txr_badr;
+ 	struct net_device *netdev;
+ 	struct device *dev;
+-	struct napi_struct napi;
+-
+-	struct mii_bus *mii_bus;
+-	int phy_irq[PHY_MAX_ADDR];
+-	struct phy_device *phydev;
+-	int old_speed;
+ };
+ 
+-static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
++static int ftgmac100_alloc_rx_page(struct ftgmac100_rx_ring *rx_ring,
+ 				   struct ftgmac100_rxdes *rxdes, gfp_t gfp);
+-
+ /******************************************************************************
+  * internal functions (hardware register access)
+  *****************************************************************************/
+ #define INT_MASK_ALL_ENABLED	(FTGMAC100_INT_RPKT_LOST	| \
+-				 FTGMAC100_INT_XPKT_ETH		| \
+-				 FTGMAC100_INT_XPKT_LOST	| \
+ 				 FTGMAC100_INT_AHB_ERR		| \
+-				 FTGMAC100_INT_PHYSTS_CHG	| \
+ 				 FTGMAC100_INT_RPKT_BUF		| \
+ 				 FTGMAC100_INT_NO_RXBUF)
+ 
+-static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr)
++#define INT_MASK_TX (FTGMAC100_INT_XPKT_ETH | FTGMAC100_INT_XPKT_LOST)
++
++static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, struct ftgmac100_rx_ring *rx_ring)
+ {
+-	iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR);
++	iowrite32(rx_ring->rx_dma_addr, priv->base + rx_ring->rx_offset_rxr_badr);
+ }
+ 
+ static void ftgmac100_set_rx_buffer_size(struct ftgmac100 *priv,
+@@ -103,23 +192,28 @@ static void ftgmac100_set_rx_buffer_size(struct ftgmac100 *priv,
+ 	iowrite32(size, priv->base + FTGMAC100_OFFSET_RBSR);
+ }
+ 
+-static void ftgmac100_set_normal_prio_tx_ring_base(struct ftgmac100 *priv,
+-						   dma_addr_t addr)
++static void ftgmac100_set_tx_ring_base(struct ftgmac100 *priv, struct ftgmac100_tx_ring *tx_ring)
+ {
+-	iowrite32(addr, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
++	iowrite32(tx_ring->tx_dma_addr, priv->base + tx_ring->tx_offset_txr_badr);
+ }
+ 
+-static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv)
++static void ftgmac100_txdma_start_polling(struct ftgmac100 *priv, struct ftgmac100_tx_ring *tx_ring)
+ {
+-	iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
++	iowrite32(1, priv->base + tx_ring->tx_offset_txpd);
+ }
+ 
++
+ static int ftgmac100_reset_hw(struct ftgmac100 *priv)
+ {
++#ifdef CONFIG_PLATFORM_GM8210    
+ 	struct net_device *netdev = priv->netdev;
+ 	int i;
++#endif
+ 
++    MDIO_first_time = 1;
++#ifdef CONFIG_PLATFORM_GM8210
+ 	/* NOTE: reset clears all registers */
++	printk("reset MAC IP\n");
+ 	iowrite32(FTGMAC100_MACCR_SW_RST, priv->base + FTGMAC100_OFFSET_MACCR);
+ 	for (i = 0; i < 5; i++) {
+ 		unsigned int maccr;
+@@ -128,11 +222,15 @@ static int ftgmac100_reset_hw(struct ftgmac100 *priv)
+ 		if (!(maccr & FTGMAC100_MACCR_SW_RST))
+ 			return 0;
+ 
+-		udelay(1000);
++		wait_status(1);
+ 	}
+ 
+ 	netdev_err(netdev, "software reset failed\n");
+ 	return -EIO;
++#else
++    mac_reset();
++    return 0;
++#endif	
+ }
+ 
+ static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
+@@ -146,18 +244,35 @@ static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
+ 
+ static void ftgmac100_init_hw(struct ftgmac100 *priv)
+ {
+-	/* setup ring buffer base registers */
+-	ftgmac100_set_rx_ring_base(priv,
+-				   priv->descs_dma_addr +
+-				   offsetof(struct ftgmac100_descs, rxdes));
+-	ftgmac100_set_normal_prio_tx_ring_base(priv,
+-					       priv->descs_dma_addr +
+-					       offsetof(struct ftgmac100_descs, txdes));
+-
++	int i;
++	
++	if(priv->rx_rings != NULL) {
++		/* setup ring buffer base registers */
++		for (i = 0; i < priv->rx_num_queues; i++) {
++			ftgmac100_set_rx_ring_base(priv, &priv->rx_rings[i]);
++		}
++		for (i = 0; i < priv->tx_num_queues; i++) {
++			ftgmac100_set_tx_ring_base(priv, &priv->tx_rings[i]);
++		}
++	}
+ 	ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE);
+ 
+-	iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + FTGMAC100_OFFSET_APTC);
+-
++	iowrite32(FTGMAC100_APTC_RXPOLL_CNT(0xF), priv->base + FTGMAC100_OFFSET_APTC);
++	set_MDC_CLK(priv);
++#if 1
++    {
++	unsigned int value;        
++  // enable flow control
++	value = ioread32(priv->base + FTGMAC100_OFFSET_FCR);			
++	iowrite32(value | 0x1, priv->base + FTGMAC100_OFFSET_FCR);
++
++  // enable back pressure register
++	value = ioread32(priv->base + FTGMAC100_OFFSET_BPR);			
++	iowrite32(value | 0x1, priv->base + FTGMAC100_OFFSET_BPR);
++    }
++#endif		
++	//iowrite32(0xFF, priv->base + FTGMAC100_OFFSET_ITC);
++	
+ 	ftgmac100_set_mac(priv, priv->netdev->dev_addr);
+ }
+ 
+@@ -165,12 +280,16 @@ static void ftgmac100_init_hw(struct ftgmac100 *priv)
+ 				 FTGMAC100_MACCR_RXDMA_EN	| \
+ 				 FTGMAC100_MACCR_TXMAC_EN	| \
+ 				 FTGMAC100_MACCR_RXMAC_EN	| \
+-				 FTGMAC100_MACCR_FULLDUP	| \
++				 FTGMAC100_MACCR_HPTXR_EN	| \
+ 				 FTGMAC100_MACCR_CRC_APD	| \
+ 				 FTGMAC100_MACCR_RX_RUNT	| \
+-				 FTGMAC100_MACCR_RX_BROADPKT)
++				 FTGMAC100_MACCR_RX_BROADPKT | \
++				 FTGMAC100_MACCR_JUMBO_LF)
+ 
+-static void ftgmac100_start_hw(struct ftgmac100 *priv, int speed)
++static int ftgmac100_set_tfifo_size(struct ftgmac100 *priv, int size_sel);
++static int ftgmac100_set_rfifo_size(struct ftgmac100 *priv, int size_sel);
++
++static void ftgmac100_start_hw(struct ftgmac100 *priv, int speed, int duplex)
+ {
+ 	int maccr = MACCR_ENABLE_ALL;
+ 
+@@ -188,14 +307,18 @@ static void ftgmac100_start_hw(struct ftgmac100 *priv, int speed)
+ 		break;
+ 	}
+ 
++	if(duplex)
++		maccr |= FTGMAC100_MACCR_FULLDUP;
++
+ 	iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
++	priv->tx_fifo_sel = ftgmac100_set_tfifo_size(priv, priv->tx_fifo_sel);
++	priv->rx_fifo_sel = ftgmac100_set_rfifo_size(priv, priv->rx_fifo_sel);
+ }
+ 
+ static void ftgmac100_stop_hw(struct ftgmac100 *priv)
+ {
+ 	iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR);
+ }
+-
+ /******************************************************************************
+  * internal functions (receive descriptor)
+  *****************************************************************************/
+@@ -225,9 +348,14 @@ static bool ftgmac100_rxdes_rx_error(struct ftgmac100_rxdes *rxdes)
+ 	return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RX_ERR);
+ }
+ 
++static bool ftgmac100_rxdes_fifo_error(struct ftgmac100_rxdes *rxdes)
++{
++    return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_FIFO_FULL);
++}
++
+ static bool ftgmac100_rxdes_crc_error(struct ftgmac100_rxdes *rxdes)
+ {
+-	return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR);
++    return rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_CRC_ERR);
+ }
+ 
+ static bool ftgmac100_rxdes_frame_too_long(struct ftgmac100_rxdes *rxdes)
+@@ -304,143 +432,156 @@ static bool ftgmac100_rxdes_ipcs_err(struct ftgmac100_rxdes *rxdes)
+  */
+ static void ftgmac100_rxdes_set_page(struct ftgmac100_rxdes *rxdes, struct page *page)
+ {
+-	rxdes->rxdes2 = (unsigned int)page;
++	struct ftgmac100_page *p = (struct ftgmac100_page *)rxdes->rxdes2;
++	//p->page_va = page_address(p->page);
++	p->page = page;
+ }
+ 
+ static struct page *ftgmac100_rxdes_get_page(struct ftgmac100_rxdes *rxdes)
+ {
+-	return (struct page *)rxdes->rxdes2;
++	struct ftgmac100_page *p = (struct ftgmac100_page *)rxdes->rxdes2;
++	return p->page;
+ }
+ 
+ /******************************************************************************
+- * internal functions (receive)
++ * internal functions (transmit & receive)
+  *****************************************************************************/
+-static int ftgmac100_next_rx_pointer(int pointer)
++static int ftgmac100_next_pointer(int pointer, int num_entries)
+ {
+-	return (pointer + 1) & (RX_QUEUE_ENTRIES - 1);
++	return (pointer + 1) & (num_entries - 1);
+ }
+ 
+-static void ftgmac100_rx_pointer_advance(struct ftgmac100 *priv)
++/******************************************************************************
++ * internal functions (receive)
++ *****************************************************************************/
++static void ftgmac100_rx_pointer_advance(struct ftgmac100_rx_ring *rx_ring)
+ {
+-	priv->rx_pointer = ftgmac100_next_rx_pointer(priv->rx_pointer);
++	rx_ring->rx_pointer = ftgmac100_next_pointer(rx_ring->rx_pointer, rx_ring->rx_num_entries);
+ }
+ 
+-static struct ftgmac100_rxdes *ftgmac100_current_rxdes(struct ftgmac100 *priv)
++static struct ftgmac100_rxdes *ftgmac100_current_rxdes(struct ftgmac100_rx_ring *rx_ring)
+ {
+-	return &priv->descs->rxdes[priv->rx_pointer];
++	return &rx_ring->rxdes[rx_ring->rx_pointer];
+ }
+ 
+ static struct ftgmac100_rxdes *
+-ftgmac100_rx_locate_first_segment(struct ftgmac100 *priv)
++ftgmac100_rx_locate_first_segment(struct ftgmac100_rx_ring *rx_ring)
+ {
+-	struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
++	struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(rx_ring);
+ 
+ 	while (ftgmac100_rxdes_packet_ready(rxdes)) {
+ 		if (ftgmac100_rxdes_first_segment(rxdes))
+ 			return rxdes;
+ 
+ 		ftgmac100_rxdes_set_dma_own(rxdes);
+-		ftgmac100_rx_pointer_advance(priv);
+-		rxdes = ftgmac100_current_rxdes(priv);
++		ftgmac100_rx_pointer_advance(rx_ring);
++		rxdes = ftgmac100_current_rxdes(rx_ring);
+ 	}
+ 
+ 	return NULL;
+ }
+ 
+-static bool ftgmac100_rx_packet_error(struct ftgmac100 *priv,
++static bool ftgmac100_rx_packet_error(struct ftgmac100_rx_ring *rx_ring,
+ 				      struct ftgmac100_rxdes *rxdes)
+ {
+-	struct net_device *netdev = priv->netdev;
++	struct net_device *netdev = rx_ring->netdev;
+ 	bool error = false;
+ 
+-	if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) {
+-		if (net_ratelimit())
+-			netdev_info(netdev, "rx err\n");
++	if (unlikely(ftgmac100_rxdes_fifo_error(rxdes))) {
++		if (show_rx_dbg)
++			netdev_info(netdev, "MAC rx fifo full, lose\n");
+ 
+-		netdev->stats.rx_errors++;
+-		error = true;
+-	}
+-
+-	if (unlikely(ftgmac100_rxdes_crc_error(rxdes))) {
+-		if (net_ratelimit())
+-			netdev_info(netdev, "rx crc err\n");
+-
+-		netdev->stats.rx_crc_errors++;
+-		error = true;
+-	} else if (unlikely(ftgmac100_rxdes_ipcs_err(rxdes))) {
+-		if (net_ratelimit())
+-			netdev_info(netdev, "rx IP checksum err\n");
+-
+-		error = true;
+-	}
+-
+-	if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) {
+-		if (net_ratelimit())
+-			netdev_info(netdev, "rx frame too long\n");
+-
+-		netdev->stats.rx_length_errors++;
+-		error = true;
+-	} else if (unlikely(ftgmac100_rxdes_runt(rxdes))) {
+-		if (net_ratelimit())
+-			netdev_info(netdev, "rx runt\n");
+-
+-		netdev->stats.rx_length_errors++;
+-		error = true;
+-	} else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) {
+-		if (net_ratelimit())
+-			netdev_info(netdev, "rx odd nibble\n");
+-
+-		netdev->stats.rx_length_errors++;
+ 		error = true;
++	} else {
++    	if (unlikely(ftgmac100_rxdes_rx_error(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx err\n");
++    
++    		error = true;
++    	} else if (unlikely(ftgmac100_rxdes_crc_error(rxdes))) {
++    	    if (show_rx_dbg)
++    			netdev_info(netdev, "rx crc err\n");
++    
++    		netdev->stats.rx_crc_errors++;
++    		error = true;
++    	} else if (unlikely(ftgmac100_rxdes_ipcs_err(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx IP checksum err\n");
++            
++            netdev->stats.rx_frame_errors++;
++    		error = true;
++    	} else if (unlikely(ftgmac100_rxdes_frame_too_long(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx frame too long\n");
++    
++    		netdev->stats.rx_length_errors++;
++    		error = true;
++    	} else if (unlikely(ftgmac100_rxdes_runt(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx runt\n");
++    
++    		netdev->stats.rx_length_errors++;
++    		error = true;
++    	} else if (unlikely(ftgmac100_rxdes_odd_nibble(rxdes))) {
++    		if (show_rx_dbg)
++    			netdev_info(netdev, "rx odd nibble\n");
++    
++    		netdev->stats.rx_length_errors++;
++    		error = true;
++    	}	    
+ 	}
+ 
++    if(error)
++        netdev->stats.rx_errors++;
++    
+ 	return error;
+ }
+ 
+-static void ftgmac100_rx_drop_packet(struct ftgmac100 *priv)
++static void ftgmac100_rx_drop_packet(struct ftgmac100_rx_ring *rx_ring)
+ {
+-	struct net_device *netdev = priv->netdev;
+-	struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(priv);
++	struct net_device *netdev = rx_ring->netdev;
++	struct ftgmac100_rxdes *rxdes = ftgmac100_current_rxdes(rx_ring);
+ 	bool done = false;
+ 
+-	if (net_ratelimit())
+-		netdev_dbg(netdev, "drop packet %p\n", rxdes);
++	if (show_rx_dbg)
++		netdev_err(netdev, "drop packet %p\n", rxdes);
+ 
+ 	do {
+ 		if (ftgmac100_rxdes_last_segment(rxdes))
+ 			done = true;
+ 
+ 		ftgmac100_rxdes_set_dma_own(rxdes);
+-		ftgmac100_rx_pointer_advance(priv);
+-		rxdes = ftgmac100_current_rxdes(priv);
++		ftgmac100_rx_pointer_advance(rx_ring);
++		rxdes = ftgmac100_current_rxdes(rx_ring);
+ 	} while (!done && ftgmac100_rxdes_packet_ready(rxdes));
+-
+-	netdev->stats.rx_dropped++;
+ }
+ 
+-static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
++static bool ftgmac100_process_rx_jumbo_ring(struct ftgmac100_rx_ring *rx_ring, struct napi_struct *napi)
+ {
+-	struct net_device *netdev = priv->netdev;
++	struct net_device *netdev = rx_ring->netdev;
+ 	struct ftgmac100_rxdes *rxdes;
+ 	struct sk_buff *skb;
+ 	bool done = false;
++	int i;
+ 
+-	rxdes = ftgmac100_rx_locate_first_segment(priv);
++	rxdes = ftgmac100_rx_locate_first_segment(rx_ring);
+ 	if (!rxdes)
+ 		return false;
+ 
+-	if (unlikely(ftgmac100_rx_packet_error(priv, rxdes))) {
+-		ftgmac100_rx_drop_packet(priv);
++	if (unlikely(ftgmac100_rx_packet_error(rx_ring, rxdes))) {
++		ftgmac100_rx_drop_packet(rx_ring);
++		netdev->stats.rx_dropped++;
+ 		return true;
+ 	}
+ 
+ 	/* start processing */
+ 	skb = netdev_alloc_skb_ip_align(netdev, 128);
+ 	if (unlikely(!skb)) {
+-		if (net_ratelimit())
+-			netdev_err(netdev, "rx skb alloc failed\n");
++		netdev_err(netdev, "rx skb alloc failed\n");
++
++		ftgmac100_rx_drop_packet(rx_ring);
++		netdev->stats.rx_dropped++;
+ 
+-		ftgmac100_rx_drop_packet(priv);
+ 		return true;
+ 	}
+ 
+@@ -461,39 +602,57 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
+ 		struct page *page = ftgmac100_rxdes_get_page(rxdes);
+ 		unsigned int size;
+ 
+-		dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
++		dma_unmap_page(rx_ring->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
+ 
+ 		size = ftgmac100_rxdes_data_length(rxdes);
+ 		skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 0, size);
+ 
+ 		skb->len += size;
+ 		skb->data_len += size;
+-		skb->truesize += PAGE_SIZE;
++		skb->truesize += RX_BUF_SIZE;
+ 
+ 		if (ftgmac100_rxdes_last_segment(rxdes))
+ 			done = true;
+ 
+-		ftgmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC);
++		ftgmac100_alloc_rx_page(rx_ring, rxdes, GFP_ATOMIC);
+ 
+-		ftgmac100_rx_pointer_advance(priv);
+-		rxdes = ftgmac100_current_rxdes(priv);
++		ftgmac100_rx_pointer_advance(rx_ring);
++		rxdes = ftgmac100_current_rxdes(rx_ring);
+ 	} while (!done);
+ 
+ 	if (skb->len <= 64)
+-		skb->truesize -= PAGE_SIZE;
++		skb->truesize -= RX_BUF_SIZE;
+ 	__pskb_pull_tail(skb, min(skb->len, 64U));
+ 	skb->protocol = eth_type_trans(skb, netdev);
+ 
+ 	netdev->stats.rx_packets++;
+ 	netdev->stats.rx_bytes += skb->len;
+ 
++	if(show_rx_pkg) {
++	    printk("<rx pkg=");
++	    for(i = 0; i < 10; i++)
++	    	printk("0x%02x ", *(skb->mac_header + i));
++	    for(i = 0; i < 10; i++)
++	        printk("0x%02x ", *(skb->data + i));
++        printk(">\n");
++    }
++    
+ 	/* push packet to protocol stack */
+-	napi_gro_receive(&priv->napi, skb);
+-
+-	(*processed)++;
++	napi_gro_receive(napi, skb);
+ 	return true;
+ }
+ 
++static bool ftgmac100_rx_packet(struct ftgmac100 *priv)
++{
++	int i;
++	bool ret = false;
++	for (i = 0; i < priv->rx_num_queues; i++) {
++		if (priv->process_rx_ring(&priv->rx_rings[i], &priv->napi))
++			ret = true;
++	}
++	return ret;
++}
++
+ /******************************************************************************
+  * internal functions (transmit descriptor)
+  *****************************************************************************/
+@@ -511,6 +670,11 @@ static bool ftgmac100_txdes_owned_by_dma(struct ftgmac100_txdes *txdes)
+ 	return txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_TXDMA_OWN);
+ }
+ 
++static bool ftgmac100_txdes_first_segment(struct ftgmac100_txdes *txdes)
++{
++	return txdes->txdes0 & cpu_to_le32(FTGMAC100_TXDES0_FTS);
++}
++
+ static void ftgmac100_txdes_set_dma_own(struct ftgmac100_txdes *txdes)
+ {
+ 	/*
+@@ -562,6 +726,11 @@ static void ftgmac100_txdes_set_ipcs(struct ftgmac100_txdes *txdes)
+ 	txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_IP_CHKSUM);
+ }
+ 
++static void ftgmac100_txdes_set_used(struct ftgmac100_txdes *txdes)
++{
++	txdes->txdes1 |= cpu_to_le32(FTGMAC100_TXDES1_USED);
++}
++
+ static void ftgmac100_txdes_set_dma_addr(struct ftgmac100_txdes *txdes,
+ 					 dma_addr_t addr)
+ {
+@@ -591,142 +760,313 @@ static struct sk_buff *ftgmac100_txdes_get_skb(struct ftgmac100_txdes *txdes)
+ /******************************************************************************
+  * internal functions (transmit)
+  *****************************************************************************/
+-static int ftgmac100_next_tx_pointer(int pointer)
+-{
+-	return (pointer + 1) & (TX_QUEUE_ENTRIES - 1);
+-}
+-
+-static void ftgmac100_tx_pointer_advance(struct ftgmac100 *priv)
++static void ftgmac100_tx_clean_pointer_advance(struct ftgmac100_tx_ring *tx_ring)
+ {
+-	priv->tx_pointer = ftgmac100_next_tx_pointer(priv->tx_pointer);
++	tx_ring->tx_clean_pointer = ftgmac100_next_pointer(tx_ring->tx_clean_pointer, tx_ring->tx_num_entries);
+ }
+ 
+-static void ftgmac100_tx_clean_pointer_advance(struct ftgmac100 *priv)
++static int ftgmac100_current_txdes_idx(struct ftgmac100_tx_ring *tx_ring)
+ {
+-	priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv->tx_clean_pointer);
++	return tx_ring->tx_pointer;
+ }
+ 
+-static struct ftgmac100_txdes *ftgmac100_current_txdes(struct ftgmac100 *priv)
++static struct ftgmac100_txdes *ftgmac100_idx_txdes(struct ftgmac100_tx_ring *tx_ring, int idx)
+ {
+-	return &priv->descs->txdes[priv->tx_pointer];
++	if (idx >= tx_ring->tx_num_entries)
++		return NULL;
++	return &tx_ring->txdes[idx];
+ }
+ 
+ static struct ftgmac100_txdes *
+-ftgmac100_current_clean_txdes(struct ftgmac100 *priv)
++ftgmac100_current_clean_txdes(struct ftgmac100_tx_ring *tx_ring)
+ {
+-	return &priv->descs->txdes[priv->tx_clean_pointer];
++	return &tx_ring->txdes[tx_ring->tx_clean_pointer];
+ }
+ 
+-static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
++static bool ftgmac100_clean_tx_ring(struct ftgmac100 *priv, struct ftgmac100_tx_ring *tx_ring, int *nr_frag)
+ {
+-	struct net_device *netdev = priv->netdev;
++	struct net_device *netdev = tx_ring->netdev;
+ 	struct ftgmac100_txdes *txdes;
+ 	struct sk_buff *skb;
+ 	dma_addr_t map;
+ 
+-	if (priv->tx_pending == 0)
+-		return false;
++    spin_lock(&priv->mac_lock);
++	/* spinlock protect */
++	if (tx_ring->tx_pending == 0)
++		goto out;
+ 
+-	txdes = ftgmac100_current_clean_txdes(priv);
++	txdes = ftgmac100_current_clean_txdes(tx_ring);
+ 
+ 	if (ftgmac100_txdes_owned_by_dma(txdes))
+-		return false;
++		goto out;
++
++    spin_unlock(&priv->mac_lock);
+ 
+ 	skb = ftgmac100_txdes_get_skb(txdes);
++
++	/* unmap the first txdes (single buffer) */
+ 	map = ftgmac100_txdes_get_dma_addr(txdes);
++	if (ftgmac100_txdes_first_segment(txdes)) {
++		dma_unmap_single(tx_ring->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
++		(*nr_frag) = 0;
++	}
++	else {
++		const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[*nr_frag];
++		dma_unmap_page(tx_ring->dev, map, skb_frag_size(frag), DMA_TO_DEVICE);
++		(*nr_frag)++;
++	}
+ 
+ 	netdev->stats.tx_packets++;
+ 	netdev->stats.tx_bytes += skb->len;
+-
+-	dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
+-
+ 	dev_kfree_skb(skb);
+ 
++	ftgmac100_tx_clean_pointer_advance(tx_ring);
+ 	ftgmac100_txdes_reset(txdes);
+ 
+-	ftgmac100_tx_clean_pointer_advance(priv);
+-
+-	spin_lock(&priv->tx_lock);
+-	priv->tx_pending--;
+-	spin_unlock(&priv->tx_lock);
+-	netif_wake_queue(netdev);
++	spin_lock(&priv->mac_lock);
++	tx_ring->tx_pending--;
++	spin_unlock(&priv->mac_lock);
+ 
+ 	return true;
++out:
++	spin_unlock(&priv->mac_lock);
++	return false;
+ }
+ 
+ static void ftgmac100_tx_complete(struct ftgmac100 *priv)
+ {
+-	while (ftgmac100_tx_complete_packet(priv))
+-		;
++	int i, nr_frag = 0;
++	for (i = 0; i < priv->tx_num_queues; i++) {
++		while(ftgmac100_clean_tx_ring(priv, &priv->tx_rings[i], &nr_frag))
++			;
++	}
+ }
+ 
+-static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb,
+-			  dma_addr_t map)
++/*
++ * In order to prevent the critical section of these tx descriptors,
++ * we need to reserve these tx descriptors in advance.
++ * return value is the index of the first tx descriptor.
++ */
++static int ftgmac100_reserve_txdeses(struct ftgmac100 *priv, struct ftgmac100_tx_ring *tx_ring, int num)
++{
++	int cur_idx = ftgmac100_current_txdes_idx(tx_ring);
++
++	spin_lock(&priv->mac_lock);
++
++	if ((TX_QUEUE_ENTRIES - tx_ring->tx_pending) < num)
++		goto tx_full;
++
++	tx_ring->tx_pointer += num;
++	if (tx_ring->tx_pointer >= TX_QUEUE_ENTRIES)
++		tx_ring->tx_pointer -= TX_QUEUE_ENTRIES;
++
++	//tx_ring->tx_pending += num;//tx_ring->tx_pending ++;
++
++	spin_unlock(&priv->mac_lock);
++
++	return cur_idx;
++
++tx_full:
++	spin_unlock(&priv->mac_lock);
++	return -1;
++}
++
++static int ftgmac100_xmit(struct ftgmac100 *priv, struct sk_buff *skb)
+ {
+ 	struct net_device *netdev = priv->netdev;
+-	struct ftgmac100_txdes *txdes;
+-	unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
++	struct ftgmac100_tx_ring *tx_ring = &priv->tx_rings[skb->queue_mapping];
++	struct ftgmac100_txdes *txdes = NULL, *first_txdes = NULL;
++	int txdes_idx;
++	int i;
++	unsigned int num_txdeses = 1;
++	const struct skb_frag_struct *frag;
++	dma_addr_t map;
++	unsigned int total_len = 0, len;
++
++	num_txdeses += skb_shinfo(skb)->nr_frags;
++
++	/* the first descriptor must be set at last */
++	txdes_idx = ftgmac100_reserve_txdeses(priv, tx_ring, num_txdeses);
+ 
+-	txdes = ftgmac100_current_txdes(priv);
+-	ftgmac100_tx_pointer_advance(priv);
++	if (unlikely(txdes_idx < 0)) {
++		netif_stop_queue(netdev);
++		if (show_rx_dbg)
++			printk("MAC tx queue full, wait to digest\n");
++		
++		return NETDEV_TX_BUSY;
++	}
++
++#if 0//debug
++	if (tx_ring->tx_pending > 480) {
++		printk(">>> tx pending %d <<<\n", tx_ring->tx_pending);
++	}
++#endif	
++	if ((TX_QUEUE_ENTRIES - tx_ring->tx_pending) < TX_QUEUE_THRESHOLD)
++		iowrite32(INT_MASK_TX, priv->base + FTGMAC100_OFFSET_IER);
++
++	first_txdes = ftgmac100_idx_txdes(tx_ring, txdes_idx);
++	txdes_idx = ftgmac100_next_pointer(txdes_idx, tx_ring->tx_num_entries);
++
++	if (num_txdeses > 1) {
++		txdes = ftgmac100_idx_txdes(tx_ring, txdes_idx);
++		txdes_idx = ftgmac100_next_pointer(txdes_idx, tx_ring->tx_num_entries);
++
++		for (i = 1; i < (num_txdeses - 1); i++) {
++			frag = &skb_shinfo(skb)->frags[i - 1];
++			len = skb_frag_size(frag);
++			total_len += len;
++			map = skb_frag_dma_map(priv->dev, frag, 0, len, DMA_TO_DEVICE);
++
++			if (unlikely(dma_mapping_error(priv->dev, map)))
++				goto dma_err;
++			/* setup TX descriptor */
++			ftgmac100_txdes_set_skb(txdes, skb);
++			ftgmac100_txdes_set_dma_addr(txdes, map);
++			ftgmac100_txdes_set_buffer_size(txdes, len);
++
++			ftgmac100_txdes_set_dma_own(txdes);
++			ftgmac100_txdes_set_used(txdes);
++			txdes = ftgmac100_idx_txdes(tx_ring, txdes_idx);
++			txdes_idx = ftgmac100_next_pointer(txdes_idx, tx_ring->tx_num_entries);
++		}
++
++		/* setup the last descriptor */
++		frag = &skb_shinfo(skb)->frags[i - 1];
++		len = skb_frag_size(frag);
++		
++		map = skb_frag_dma_map(priv->dev, frag, 0, len, DMA_TO_DEVICE);
+ 
+-	/* setup TX descriptor */
+-	ftgmac100_txdes_set_skb(txdes, skb);
+-	ftgmac100_txdes_set_dma_addr(txdes, map);
+-	ftgmac100_txdes_set_buffer_size(txdes, len);
++		if (unlikely(dma_mapping_error(priv->dev, map)))
++			goto dma_err;
++
++		ftgmac100_txdes_set_skb(txdes, skb);
++		ftgmac100_txdes_set_dma_addr(txdes, map);
++		
++		if((total_len + len + skb_headlen(skb)) < ETH_ZLEN)
++		    len = ETH_ZLEN - skb_headlen(skb) - total_len;
++
++        total_len += len;
++
++		ftgmac100_txdes_set_buffer_size(txdes, len);
++		ftgmac100_txdes_set_last_segment(txdes);
++
++		ftgmac100_txdes_set_dma_own(txdes);
++		ftgmac100_txdes_set_used(txdes);
++	}
++
++	/* setup the first descriptor */
++	len = skb_headlen(skb);
++	total_len += len;
++	map = dma_map_single(priv->dev, skb->data, len, DMA_TO_DEVICE);
++
++	if(show_tx_pkg) {
++	    printk("<tx pkg=");
++	    for(i = 0; i < len; i++)
++	        printk("0x%02x ", *(skb->data + i));
++        printk(">\n");
++    }
++  
++	if (unlikely(dma_mapping_error(priv->dev, map)))
++		goto dma_err;
++
++	ftgmac100_txdes_set_skb(first_txdes, skb);
++	ftgmac100_txdes_set_dma_addr(first_txdes, map);
++
++	if (1 == num_txdeses) {
++		len = (total_len < ETH_ZLEN) ? ETH_ZLEN : len;
++		ftgmac100_txdes_set_buffer_size(first_txdes, len);
++	}
++	else
++		ftgmac100_txdes_set_buffer_size(first_txdes, len);
++
++	ftgmac100_txdes_set_first_segment(first_txdes);
++
++	if (1 == num_txdeses)
++		ftgmac100_txdes_set_last_segment(first_txdes);
++
++	ftgmac100_txdes_set_txint(first_txdes);
+ 
+-	ftgmac100_txdes_set_first_segment(txdes);
+-	ftgmac100_txdes_set_last_segment(txdes);
+-	ftgmac100_txdes_set_txint(txdes);
+ 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ 		__be16 protocol = skb->protocol;
+ 
+ 		if (protocol == cpu_to_be16(ETH_P_IP)) {
+ 			u8 ip_proto = ip_hdr(skb)->protocol;
+ 
+-			ftgmac100_txdes_set_ipcs(txdes);
++			ftgmac100_txdes_set_ipcs(first_txdes);
+ 			if (ip_proto == IPPROTO_TCP)
+-				ftgmac100_txdes_set_tcpcs(txdes);
++				ftgmac100_txdes_set_tcpcs(first_txdes);
+ 			else if (ip_proto == IPPROTO_UDP)
+-				ftgmac100_txdes_set_udpcs(txdes);
++				ftgmac100_txdes_set_udpcs(first_txdes);
+ 		}
+ 	}
+ 
+-	spin_lock(&priv->tx_lock);
+-	priv->tx_pending++;
+-	if (priv->tx_pending == TX_QUEUE_ENTRIES)
++	/* spinlock protect */
++    spin_lock(&priv->mac_lock);
++	ftgmac100_txdes_set_dma_own(first_txdes);
++	ftgmac100_txdes_set_used(first_txdes);
++	tx_ring->tx_pending ++;
++
++	if (unlikely(tx_ring->tx_pending == TX_QUEUE_ENTRIES)) {
+ 		netif_stop_queue(netdev);
++		if (show_rx_dbg)
++			printk("MAC tx queue full, wait to digest!\n");
++	}
++	spin_unlock(&priv->mac_lock);
+ 
+-	/* start transmit */
+-	ftgmac100_txdes_set_dma_own(txdes);
+-	spin_unlock(&priv->tx_lock);
++	ftgmac100_txdma_start_polling(priv, tx_ring);
++	return NETDEV_TX_OK;
+ 
+-	ftgmac100_txdma_normal_prio_start_polling(priv);
++dma_err:
++	netdev_err(netdev, "map socket buffer failed\n");
+ 
++	netdev->stats.tx_dropped++;
++	dev_kfree_skb(skb);
+ 	return NETDEV_TX_OK;
+ }
+ 
+ /******************************************************************************
+  * internal functions (buffer)
+  *****************************************************************************/
+-static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
++static int ftgmac100_alloc_tx_entries(struct ftgmac100_tx_ring *tx_ring, 
++					unsigned int num_entries, 
++					const struct ftgmac100_tx_reg_offset *reg_offset)
++{
++	struct net_device *netdev = tx_ring->netdev;
++
++	tx_ring->tx_num_entries = num_entries;
++	tx_ring->txdes = dma_alloc_coherent(tx_ring->dev, 
++										tx_ring->tx_num_entries * sizeof(struct ftgmac100_txdes), 
++										&tx_ring->tx_dma_addr, GFP_ATOMIC);
++	if (!tx_ring->txdes) {
++		netdev_err(netdev, "failed to allocate tx descriptors\n");
++		return -ENOMEM;
++	}
++	tx_ring->tx_clean_pointer = 0;
++	tx_ring->tx_pointer = 0;
++	tx_ring->tx_pending = 0;
++
++	tx_ring->tx_offset_txpd = reg_offset->offset_txpd;
++	tx_ring->tx_offset_txr_badr = reg_offset->offset_txr_badr;
++	ftgmac100_txdes_set_end_of_ring(&tx_ring->txdes[tx_ring->tx_num_entries - 1]);
++	return 0;
++}
++
++static int ftgmac100_alloc_rx_page(struct ftgmac100_rx_ring *rx_ring,
+ 				   struct ftgmac100_rxdes *rxdes, gfp_t gfp)
+ {
+-	struct net_device *netdev = priv->netdev;
++	struct net_device *netdev = rx_ring->netdev;
+ 	struct page *page;
+ 	dma_addr_t map;
+ 
+ 	page = alloc_page(gfp);
+ 	if (!page) {
+-		if (net_ratelimit())
+-			netdev_err(netdev, "failed to allocate rx page\n");
++		netdev_err(netdev, "failed to allocate rx page\n");
+ 		return -ENOMEM;
+ 	}
+ 
+-	map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
+-	if (unlikely(dma_mapping_error(priv->dev, map))) {
+-		if (net_ratelimit())
+-			netdev_err(netdev, "failed to map rx page\n");
++	map = dma_map_page(rx_ring->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE);
++	if (unlikely(dma_mapping_error(rx_ring->dev, map))) {
++		netdev_err(netdev, "failed to map rx page\n");
+ 		__free_page(page);
+ 		return -ENOMEM;
+ 	}
+@@ -737,69 +1077,142 @@ static int ftgmac100_alloc_rx_page(struct ftgmac100 *priv,
+ 	return 0;
+ }
+ 
+-static void ftgmac100_free_buffers(struct ftgmac100 *priv)
++static int ftgmac100_alloc_rx_entries(struct ftgmac100_rx_ring *rx_ring,
++				unsigned int num_entries,
++				const struct ftgmac100_rx_reg_offset *reg_offset)
+ {
+ 	int i;
++	struct net_device *netdev = rx_ring->netdev;
+ 
+-	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
+-		struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+-		struct page *page = ftgmac100_rxdes_get_page(rxdes);
+-		dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
++	rx_ring->rx_num_entries = num_entries;
++	rx_ring->rxdes = dma_alloc_coherent(rx_ring->dev, 
++										rx_ring->rx_num_entries * sizeof(struct ftgmac100_rxdes), 
++										&rx_ring->rx_dma_addr, GFP_ATOMIC);
+ 
+-		if (!page)
+-			continue;
++	if (!rx_ring->rxdes) {
++		netdev_err(netdev, "failed to allocate rx descriptors\n");
++		return -ENOMEM;
++	}
+ 
+-		dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
+-		__free_page(page);
++	for (i = 0; i < rx_ring->rx_num_entries; i++) {
++		struct ftgmac100_rxdes *rxdes = &rx_ring->rxdes[i];
++		rxdes->rxdes2 = (unsigned int)vzalloc(sizeof(struct ftgmac100_page));
++		if (ftgmac100_alloc_rx_page(rx_ring, rxdes, GFP_ATOMIC | GFP_DMA)) {
++		    netdev_err(netdev, "failed to allocate rx page\n");
++			return -ENOMEM;
++		}
++    }
++	rx_ring->rx_pointer = 0;
++	rx_ring->rx_offset_rxpd = reg_offset->offset_rxpd;
++	rx_ring->rx_offset_rxr_badr = reg_offset->offset_rxr_badr;
++	ftgmac100_rxdes_set_end_of_ring(&rx_ring->rxdes[rx_ring->rx_num_entries - 1]);
++	return 0;
++}
++
++static void ftgmac100_free_rxdes(struct ftgmac100_rx_ring *rx_ring)
++{
++	int i;
++	if (rx_ring->rxdes) {
++		for (i = 0; i < rx_ring->rx_num_entries; i++) {
++			struct ftgmac100_rxdes *rxdes = &rx_ring->rxdes[i];
++			struct page *page = ftgmac100_rxdes_get_page(rxdes);
++			dma_addr_t map = ftgmac100_rxdes_get_dma_addr(rxdes);
++
++			if (!page)
++				continue;
++
++			dma_unmap_page(rx_ring->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
++			__free_page(page);
++			vfree((void *)rxdes->rxdes2);
++		}
++		dma_free_coherent(rx_ring->dev, rx_ring->rx_num_entries * sizeof(struct ftgmac100_rxdes),
++					rx_ring->rxdes, rx_ring->rx_dma_addr);
+ 	}
++}
+ 
+-	for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
+-		struct ftgmac100_txdes *txdes = &priv->descs->txdes[i];
+-		struct sk_buff *skb = ftgmac100_txdes_get_skb(txdes);
+-		dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes);
++static void ftgmac100_free_txdes(struct ftgmac100 *priv, struct ftgmac100_tx_ring *tx_ring)
++{
++	int i;
++	if (tx_ring->txdes) {
++		/* free txdes on by one */
++    	for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
++    		struct ftgmac100_txdes *txdes = &tx_ring->txdes[i];
++    		struct sk_buff *skb = ftgmac100_txdes_get_skb(txdes);
++    		dma_addr_t map = ftgmac100_txdes_get_dma_addr(txdes);
++    
++    		if (!skb)
++    			continue;
++    
++    		dma_unmap_single(tx_ring->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
++    		kfree_skb(skb);
++    	}
++		dma_free_coherent(tx_ring->dev, tx_ring->tx_num_entries * sizeof(struct ftgmac100_txdes),
++					tx_ring->txdes, tx_ring->tx_dma_addr);
++	}
++}
+ 
+-		if (!skb)
+-			continue;
++static void ftgmac100_free_buffers(struct ftgmac100 *priv)
++{
++	int i;
+ 
+-		dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE);
+-		dev_kfree_skb(skb);
++	if (priv->rx_rings) {
++		for (i = 0; i < priv->rx_num_queues; i++) {
++			ftgmac100_free_rxdes(&priv->rx_rings[i]);
++		}
++		vfree(priv->rx_rings);
+ 	}
+ 
+-	dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs),
+-			  priv->descs, priv->descs_dma_addr);
++	if (priv->tx_rings) {
++		for (i = 0; i< priv->tx_num_queues; i++) {
++			ftgmac100_free_txdes(priv, &priv->tx_rings[i]);
++		}
++		vfree(priv->tx_rings);
++	}
+ }
+ 
+ static int ftgmac100_alloc_buffers(struct ftgmac100 *priv)
+ {
+ 	int i;
+ 
+-	priv->descs = dma_alloc_coherent(priv->dev,
+-					 sizeof(struct ftgmac100_descs),
+-					 &priv->descs_dma_addr, GFP_KERNEL);
+-	if (!priv->descs)
+-		return -ENOMEM;
+-
+-	memset(priv->descs, 0, sizeof(struct ftgmac100_descs));
++	priv->rx_rings = vzalloc(priv->rx_num_queues * sizeof(struct ftgmac100_rx_ring));
++	if (!priv->rx_rings){
++	    printk(KERN_ERR "GMAC alloc rx rings fail\n");
++		goto err;
++	}
++	priv->tx_rings = vzalloc(priv->tx_num_queues * sizeof(struct ftgmac100_tx_ring));
++	if (!priv->tx_rings){
++	    printk(KERN_ERR "GMAC alloc tx rings fail\n");
++		goto err;
++	}
+ 
+ 	/* initialize RX ring */
+-	ftgmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
+-
+-	for (i = 0; i < RX_QUEUE_ENTRIES; i++) {
+-		struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i];
+-
+-		if (ftgmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL))
++	for (i = 0; i < priv->rx_num_queues; i++) {
++		priv->rx_rings[i].netdev = priv->netdev;
++		priv->rx_rings[i].dev = priv->dev;
++		priv->rx_rings[i].rx_queue_index = i;
++		if (ftgmac100_alloc_rx_entries(&priv->rx_rings[i], 
++										RX_QUEUE_ENTRIES, 
++										&ftgmac100_rx_reg_offset[i]))
+ 			goto err;
+ 	}
+ 
+ 	/* initialize TX ring */
+-	ftgmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]);
++	for (i = 0; i < priv->tx_num_queues; i++) {
++		priv->tx_rings[i].netdev = priv->netdev;
++		priv->tx_rings[i].dev = priv->dev;
++		priv->tx_rings[i].tx_queue_index = i;
++		if (ftgmac100_alloc_tx_entries(&priv->tx_rings[i], 
++										TX_QUEUE_ENTRIES, 
++										&ftgmac100_tx_reg_offset[i]))
++			goto err;
++	}
+ 	return 0;
+ 
+ err:
+ 	ftgmac100_free_buffers(priv);
+ 	return -ENOMEM;
+ }
+-
++    
+ /******************************************************************************
+  * internal functions (mdio)
+  *****************************************************************************/
+@@ -807,27 +1220,71 @@ static void ftgmac100_adjust_link(struct net_device *netdev)
+ {
+ 	struct ftgmac100 *priv = netdev_priv(netdev);
+ 	struct phy_device *phydev = priv->phydev;
+-	int ier;
++	int err;
++	unsigned int maht0, maht1;
++	unsigned int maccr = 0x0, rx_mode = 0x0;
+ 
+-	if (phydev->speed == priv->old_speed)
++#ifndef CONFIG_PLATFORM_GM8210
++	if (phydev->speed == 1000) {
++	    if(interface_type())
++		    return;
++	}
++#endif	
++	if (phydev->speed == priv->old_speed && phydev->duplex == priv->old_duplex)
+ 		return;
+ 
+-	priv->old_speed = phydev->speed;
++	if (phydev->speed == 0)
++		    return;
+ 
+-	ier = ioread32(priv->base + FTGMAC100_OFFSET_IER);
+-
+-	/* disable all interrupts */
+-	iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
+-
+-	netif_stop_queue(netdev);
+-	ftgmac100_stop_hw(priv);
++	printk("phy speed is %d, %s duplex\n", phydev->speed, phydev->duplex ? "full" : "half");
++	/* some PHY must reset when link change */
++	if(first_time)
++		set_mac_clock(priv->irq);
++	first_time = 1;
++	
++	priv->old_speed = phydev->speed;
++	priv->old_duplex = phydev->duplex;
++
++	/* keep rx mode */
++	rx_mode = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
++	rx_mode &= (FTGMAC100_MACCR_RX_BROADPKT | FTGMAC100_MACCR_RX_MULTIPKT | FTGMAC100_MACCR_HT_MULTI_EN | FTGMAC100_MACCR_RX_ALL);
++
++	maht0 = ioread32(priv->base + FTGMAC100_OFFSET_MAHT0);
++	maht1 = ioread32(priv->base + FTGMAC100_OFFSET_MAHT1);
++#if 1
++    netif_stop_queue(netdev);
++    
++    iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
++    
++    ftgmac100_stop_hw(priv);
++    
++    ftgmac100_reset_hw(priv);
++    ftgmac100_free_buffers(priv);
++    
++    err = ftgmac100_alloc_buffers(priv);
++    if (err)
++    	return;
++    
++    ftgmac100_init_hw(priv);
++    ftgmac100_start_hw(priv, phydev->speed, phydev->duplex);
++    
++    netif_start_queue(netdev);
++#endif
++#ifdef CONFIG_FTGMAC100_STORM
++	priv->broadcast_num = 0;
++	priv->begin_jiffies = 0;
++#endif
++	/* restore multicast settings */
++	maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
++	maccr |= rx_mode;
++	iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
+ 
+-	netif_start_queue(netdev);
+-	ftgmac100_init_hw(priv);
+-	ftgmac100_start_hw(priv, phydev->speed);
++    iowrite32(maht0, priv->base + FTGMAC100_OFFSET_MAHT0);
++    iowrite32(maht1, priv->base + FTGMAC100_OFFSET_MAHT1);
+ 
+-	/* re-enable interrupts */
+-	iowrite32(ier, priv->base + FTGMAC100_OFFSET_IER);
++	/* enable all interrupts */
++	iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTGMAC100_OFFSET_IER);
++	
+ }
+ 
+ static int ftgmac100_mii_probe(struct ftgmac100 *priv)
+@@ -865,10 +1322,26 @@ static int ftgmac100_mii_probe(struct ftgmac100 *priv)
+ 	return 0;
+ }
+ 
++/******************************************************************************
++ * internal functions (hash table)
++ ******************************************************************************/
++static unsigned int ftgmac100_get_ht_index(unsigned char *mac_addr)
++{
++	unsigned int crc32 = ether_crc(ETH_ALEN, mac_addr);
++	crc32 = ~crc32;
++	crc32 = bitrev8(crc32 & 0xff) |
++			(bitrev8((crc32 >> 8) & 0xff) << 8) |
++			(bitrev8((crc32 >> 16) & 0xff) << 16) |
++			(bitrev8((crc32 >> 24) & 0xff) << 24);
++
++	/* return MSB 6 bits */
++	return ((unsigned char)(crc32 >> 26));
++}
++
+ /******************************************************************************
+  * struct mii_bus functions
+  *****************************************************************************/
+-static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
++static int ftgmac100_dummy_read(struct mii_bus *bus, int phy_addr, int regnum)
+ {
+ 	struct net_device *netdev = bus->priv;
+ 	struct ftgmac100 *priv = netdev_priv(netdev);
+@@ -886,7 +1359,7 @@ static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+ 
+ 	iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
+ 
+-	for (i = 0; i < 10; i++) {
++	for (i = 0; i < 100; i++) {
+ 		phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
+ 
+ 		if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
+@@ -896,7 +1369,51 @@ static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+ 			return FTGMAC100_PHYDATA_MIIRDATA(data);
+ 		}
+ 
+-		udelay(100);
++		wait_status(1);
++	}
++
++	netdev_err(netdev, "mdio read timed out\n");
++	return -EIO;
++}
++
++static int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
++{
++	struct net_device *netdev = bus->priv;
++	struct ftgmac100 *priv = netdev_priv(netdev);
++	unsigned int phycr;
++	int i, data;
++
++	if(MDIO_first_time) {	/* for 8287 and 8139 */    
++	    data = ftgmac100_dummy_read(bus, phy_addr, regnum);
++	    MDIO_first_time = 0;
++	}
++	    
++	phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
++
++	/* preserve MDC cycle threshold */
++	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
++
++	phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
++		 FTGMAC100_PHYCR_REGAD(regnum) |
++		 FTGMAC100_PHYCR_MIIRD;
++
++	iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
++
++	for (i = 0; i < 100; i++) {
++		phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
++
++		if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
++
++			data = ioread32(priv->base + FTGMAC100_OFFSET_PHYDATA);
++			data = FTGMAC100_PHYDATA_MIIRDATA(data);
++			
++			if(show_phy)
++			    printk("<r:adr=%d,reg=%d,data=0x%x>", phy_addr, regnum, data);
++			    
++			return data;
++		}
++
++		wait_status(1);
+ 	}
+ 
+ 	netdev_err(netdev, "mdio read timed out\n");
+@@ -912,6 +1429,9 @@ static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
+ 	int data;
+ 	int i;
+ 
++    if(show_phy)
++        printk("<w:adr=%d,reg=%d,data=0x%x>", phy_addr, regnum, value);
++        
+ 	phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
+ 
+ 	/* preserve MDC cycle threshold */
+@@ -926,13 +1446,13 @@ static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
+ 	iowrite32(data, priv->base + FTGMAC100_OFFSET_PHYDATA);
+ 	iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
+ 
+-	for (i = 0; i < 10; i++) {
++	for (i = 0; i < 100; i++) {
+ 		phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
+ 
+ 		if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0)
+ 			return 0;
+ 
+-		udelay(100);
++		wait_status(1);
+ 	}
+ 
+ 	netdev_err(netdev, "mdio write timed out\n");
+@@ -971,30 +1491,141 @@ static int ftgmac100_set_settings(struct net_device *netdev,
+ 	return phy_ethtool_sset(priv->phydev, cmd);
+ }
+ 
++static void ftgmac100_get_ethtool_stats(struct net_device *netdev,
++		struct ethtool_stats *stats, u64 *data)
++{
++	int i = 0;
++
++    for (i = 0; i < 8; i++)
++        data[i] = ((unsigned long *)&netdev->stats)[i];
++
++    data[i++] = netdev->stats.rx_length_errors;
++    data[i++] = netdev->stats.rx_crc_errors;
++    data[i++] = netdev->stats.rx_frame_errors;
++    data[i++] = netdev->stats.rx_fifo_errors;//justin 0xC8
++}
++
++static const struct {
++	const char name[ETH_GSTRING_LEN];
++} sundance_stats[] = {
++	{ "rx_packets" },
++	{ "tx_packets" },
++	{ "rx_bytes" },
++	{ "tx_bytes" },
++	{ "rx_errors" },
++	{ "tx_errors" },
++	{ "rx_dropped" },
++	{ "tx_dropped" },
++	
++	{ "rx_length_errors" },
++	{ "rx_crc_errors" },
++	{ "rx_frame_errors" },
++	{ "rx_fifo_errors" },	
++};
++
++static void get_strings(struct net_device *dev, u32 stringset,
++		u8 *data)
++{
++	if (stringset == ETH_SS_STATS)
++		memcpy(data, sundance_stats, sizeof(sundance_stats));
++}
++
++static int get_sset_count(struct net_device *dev, int sset)
++{
++	switch (sset) {
++	case ETH_SS_STATS:
++		return ARRAY_SIZE(sundance_stats);
++	default:
++		return -EOPNOTSUPP;
++	}
++}
++
+ static const struct ethtool_ops ftgmac100_ethtool_ops = {
+ 	.set_settings		= ftgmac100_set_settings,
+ 	.get_settings		= ftgmac100_get_settings,
+ 	.get_drvinfo		= ftgmac100_get_drvinfo,
+ 	.get_link		= ethtool_op_get_link,
++	.get_ethtool_stats = ftgmac100_get_ethtool_stats,
++	.get_strings = get_strings,
++	.get_sset_count = get_sset_count,
+ };
+ 
+ /******************************************************************************
+  * interrupt handler
+  *****************************************************************************/
++static int ftgmac100_poll(struct napi_struct *napi, int budget);
+ static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
+ {
+ 	struct net_device *netdev = dev_id;
+ 	struct ftgmac100 *priv = netdev_priv(netdev);
+ 
++	/* Disable interrupts for polling */
++	iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
++
+ 	if (likely(netif_running(netdev))) {
+-		/* Disable interrupts for polling */
+-		iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
+ 		napi_schedule(&priv->napi);
+ 	}
+ 
+ 	return IRQ_HANDLED;
+ }
+ 
++#ifdef CONFIG_FTGMAC100_STORM
++static void calc_counter(struct ftgmac100 *priv, int mode)
++{
++	struct net_device *netdev = priv->netdev;
++	unsigned int data, counter;
++
++	priv->end_jiffies = get_gm_jiffies();
++	if(((priv->end_jiffies - priv->begin_jiffies) < (priv->delay_time - 50)) && (mode)) {
++		//printk("<t=%d,%ld>", priv->delay_time, priv->end_jiffies - priv->begin_jiffies);
++		return;
++	}
++
++	data = ioread32(priv->base + FTGMAC100_OFFSET_RX_BC);
++
++	if(data < priv->broadcast_num)
++		counter = 0xFFFFFFFF - priv->broadcast_num + data;
++	else
++		counter = data - priv->broadcast_num;
++
++    priv->broadcast_num = data;
++
++    //printk("<b=%d,t=%ld>", counter, priv->end_jiffies - priv->begin_jiffies);
++    priv->begin_jiffies = priv->end_jiffies;
++
++    if(counter > RX_BROADCAST_THRESHOLD) {
++    	priv->enable_rx = false;
++    	priv->delay_time = RX_DELAY_TIME;
++    	iowrite32(ioread32(priv->base + FTGMAC100_OFFSET_MACCR) & ~(FTGMAC100_MACCR_RX_BROADPKT | FTGMAC100_MACCR_RX_MULTIPKT | FTGMAC100_MACCR_HT_MULTI_EN), priv->base + FTGMAC100_OFFSET_MACCR);
++	} else {
++		priv->enable_rx = true;
++		priv->delay_time = RX_DETECT_TIME;
++
++		data = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
++		if(data) {
++			if (netdev->flags & IFF_ALLMULTI)
++				data |= FTGMAC100_MACCR_RX_MULTIPKT;
++
++			if (netdev->flags & IFF_BROADCAST)
++				data |= FTGMAC100_MACCR_RX_BROADPKT;
++
++			if (netdev->flags & IFF_MULTICAST)
++				data |= FTGMAC100_MACCR_HT_MULTI_EN;
++
++			iowrite32(data, priv->base + FTGMAC100_OFFSET_MACCR);
++		}
++	}
++}
++
++static void ftgmac100_timer(unsigned long d)
++{
++	struct ftgmac100 *priv = (struct ftgmac100 *)d;
++
++    mod_timer(&priv->timer, jiffies + msecs_to_jiffies(priv->delay_time));
++    calc_counter(priv, 0);
++}
++#endif	/* #ifdef CONFIG_FTGMAC100_STORM */
++
+ /******************************************************************************
+  * struct napi_struct functions
+  *****************************************************************************/
+@@ -1006,6 +1637,10 @@ static int ftgmac100_poll(struct napi_struct *napi, int budget)
+ 	bool completed = true;
+ 	int rx = 0;
+ 
++#ifdef CONFIG_FTGMAC100_STORM
++	calc_counter(priv, 1);
++#endif	/* #ifdef CONFIG_FTGMAC100_STORM */
++
+ 	status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
+ 	iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
+ 
+@@ -1020,7 +1655,9 @@ static int ftgmac100_poll(struct napi_struct *napi, int budget)
+ 		bool retry;
+ 
+ 		do {
+-			retry = ftgmac100_rx_packet(priv, &rx);
++			retry = ftgmac100_rx_packet(priv);
++			if (retry)
++				rx++;
+ 		} while (retry && rx < budget);
+ 
+ 		if (retry && rx == budget)
+@@ -1039,29 +1676,19 @@ static int ftgmac100_poll(struct napi_struct *napi, int budget)
+ 		ftgmac100_tx_complete(priv);
+ 	}
+ 
+-	if (status & (FTGMAC100_INT_NO_RXBUF | FTGMAC100_INT_RPKT_LOST |
+-		      FTGMAC100_INT_AHB_ERR | FTGMAC100_INT_PHYSTS_CHG)) {
+-		if (net_ratelimit())
+-			netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status,
+-				    status & FTGMAC100_INT_NO_RXBUF ? "NO_RXBUF " : "",
+-				    status & FTGMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "",
+-				    status & FTGMAC100_INT_AHB_ERR ? "AHB_ERR " : "",
+-				    status & FTGMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : "");
+-
+-		if (status & FTGMAC100_INT_NO_RXBUF) {
+-			/* RX buffer unavailable */
+-			netdev->stats.rx_over_errors++;
+-		}
+-
+-		if (status & FTGMAC100_INT_RPKT_LOST) {
+-			/* received packet lost due to RX FIFO full */
+-			netdev->stats.rx_fifo_errors++;
+-		}
++	if (status & FTGMAC100_INT_AHB_ERR)
++    	netdev_info(netdev, "AHB bus err\n");			
++	
++	if (status & FTGMAC100_INT_RPKT_LOST) {
++		/* received packet lost due to RX FIFO full */
++		netdev->stats.rx_fifo_errors++;
++		netdev->stats.rx_errors++;
++    	if (show_rx_dbg)
++    		netdev_info(netdev, "MAC INT rx fifo full, lose\n");			
+ 	}
+ 
+ 	if (completed) {
+ 		napi_complete(napi);
+-
+ 		/* enable all interrupts */
+ 		iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTGMAC100_OFFSET_IER);
+ 	}
+@@ -1082,27 +1709,34 @@ static int ftgmac100_open(struct net_device *netdev)
+ 		netdev_err(netdev, "failed to allocate buffers\n");
+ 		goto err_alloc;
+ 	}
+-
++	priv->process_rx_ring = ftgmac100_process_rx_jumbo_ring;
++
++#ifdef CONFIG_FTGMAC100_STORM
++	priv->broadcast_num = 0;
++	priv->begin_jiffies = 0;
++	priv->enable_rx = true;
++
++	init_timer(&priv->timer);
++	priv->timer.data     = (unsigned long)priv;
++	priv->timer.function = ftgmac100_timer;
++	priv->timer.expires  = jiffies + msecs_to_jiffies(RX_DETECT_TIME);
++	add_timer(&priv->timer);
++	priv->delay_time = RX_DETECT_TIME;
++#endif
+ 	err = request_irq(priv->irq, ftgmac100_interrupt, 0, netdev->name, netdev);
+ 	if (err) {
+ 		netdev_err(netdev, "failed to request irq %d\n", priv->irq);
+ 		goto err_irq;
+ 	}
+ 
+-	priv->rx_pointer = 0;
+-	priv->tx_clean_pointer = 0;
+-	priv->tx_pointer = 0;
+-	priv->tx_pending = 0;
+-
+ 	err = ftgmac100_reset_hw(priv);
+ 	if (err)
+ 		goto err_hw;
+ 
+ 	ftgmac100_init_hw(priv);
+-	ftgmac100_start_hw(priv, 10);
++	ftgmac100_start_hw(priv, priv->old_speed, priv->old_duplex);
+ 
+ 	phy_start(priv->phydev);
+-
+ 	napi_enable(&priv->napi);
+ 	netif_start_queue(netdev);
+ 
+@@ -1122,14 +1756,20 @@ static int ftgmac100_stop(struct net_device *netdev)
+ {
+ 	struct ftgmac100 *priv = netdev_priv(netdev);
+ 
++#ifdef CONFIG_FTGMAC100_STORM
++	del_timer_sync(&priv->timer);
++#endif
++
+ 	/* disable all interrupts */
+ 	iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
+ 
+ 	netif_stop_queue(netdev);
+ 	napi_disable(&priv->napi);
++	
+ 	phy_stop(priv->phydev);
+ 
+ 	ftgmac100_stop_hw(priv);
++	ftgmac100_reset_hw(priv);
+ 	free_irq(priv->irq, netdev);
+ 	ftgmac100_free_buffers(priv);
+ 
+@@ -1140,29 +1780,73 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
+ 				     struct net_device *netdev)
+ {
+ 	struct ftgmac100 *priv = netdev_priv(netdev);
+-	dma_addr_t map;
+ 
+-	if (unlikely(skb->len > MAX_PKT_SIZE)) {
+-		if (net_ratelimit())
+-			netdev_dbg(netdev, "tx packet too big\n");
++	if (unlikely(skb->len > (netdev->mtu + 18))) {
+ 
+ 		netdev->stats.tx_dropped++;
+ 		dev_kfree_skb(skb);
+ 		return NETDEV_TX_OK;
+ 	}
+ 
+-	map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+-	if (unlikely(dma_mapping_error(priv->dev, map))) {
+-		/* drop packet */
+-		if (net_ratelimit())
+-			netdev_err(netdev, "map socket buffer failed\n");
++	return ftgmac100_xmit(priv, skb);
++}
+ 
+-		netdev->stats.tx_dropped++;
+-		dev_kfree_skb(skb);
+-		return NETDEV_TX_OK;
++
++static void ftgmac100_set_rx_mode(struct net_device *netdev)
++{
++	struct ftgmac100 *priv = netdev_priv(netdev);
++	unsigned int maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
++
++	if (show_rx_dbg)
++		printk("set rx mode = 0x%x\n", netdev->flags);
++
++	/* clear filter flags */
++	maccr &= ~(FTGMAC100_MACCR_RX_BROADPKT | FTGMAC100_MACCR_RX_MULTIPKT | FTGMAC100_MACCR_HT_MULTI_EN | FTGMAC100_MACCR_RX_ALL);
++	if (netdev->flags & IFF_PROMISC) {
++		maccr |= FTGMAC100_MACCR_RX_ALL;
++	}
++
++	if (netdev->flags & IFF_ALLMULTI) {
++		maccr |= FTGMAC100_MACCR_RX_MULTIPKT;
+ 	}
+ 
+-	return ftgmac100_xmit(priv, skb, map);
++	if (netdev->flags & IFF_BROADCAST) {
++		maccr |= FTGMAC100_MACCR_RX_BROADPKT;
++	}
++
++	if (netdev->flags & IFF_MULTICAST) {
++		unsigned int maht0 = 0x0;
++		unsigned int maht1 = 0x0;
++		struct netdev_hw_addr *ha;
++
++		maccr |= FTGMAC100_MACCR_HT_MULTI_EN;
++		/* clear hash table*/
++		iowrite32(maht0, priv->base + FTGMAC100_OFFSET_MAHT0);
++		iowrite32(maht1, priv->base + FTGMAC100_OFFSET_MAHT1);
++		/* set hash table */
++		netdev_for_each_mc_addr(ha, netdev) {
++			unsigned char ht_index = ftgmac100_get_ht_index(ha->addr);
++			if (ht_index < 32)
++				maht0 |= (1 << ht_index);
++			else
++				maht1 |= (1 << (ht_index - 32));
++		}
++		iowrite32(maht0, priv->base + FTGMAC100_OFFSET_MAHT0);
++		iowrite32(maht1, priv->base + FTGMAC100_OFFSET_MAHT1);
++	}
++	iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
++}
++
++static int ftgmac100_mac_addr(struct net_device *netdev, void *p)
++{
++	struct ftgmac100 *priv = netdev_priv(netdev);
++	int ret;
++	ret = eth_mac_addr(netdev, p);
++	if (unlikely(ret))
++		return ret;
++
++	ftgmac100_set_mac(priv, p);
++	return ret;
+ }
+ 
+ /* optional */
+@@ -1173,13 +1857,105 @@ static int ftgmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int
+ 	return phy_mii_ioctl(priv->phydev, ifr, cmd);
+ }
+ 
++
++/*
++ * tx fifo size and rx fifo size selection (only 3 bits):
++ * 0x0: 2K
++ * 0x1: 4K
++ * 0x2: 8K
++ * 0x3: 16K
++ * 0x4: 32K
++ * else: reserved
++ */
++static int ftgmac100_set_tfifo_size(struct ftgmac100 *priv, int size_sel)
++{
++	int max_sel = FTGMAC100_FEAR_TFIFO_RSIZE(ioread32(priv->base + FTGMAC100_OFFSET_FEAR));
++	int tpafcr = ioread32(priv->base + FTGMAC100_OFFSET_TPAFCR);;
++
++	tpafcr &= ~FTGMAC100_TPAFCR_TFIFO_SIZE(0x7);
++
++	tpafcr |= FTGMAC100_TPAFCR_TFIFO_SIZE(max_sel);
++	iowrite32(tpafcr, priv->base + FTGMAC100_OFFSET_TPAFCR);
++	return max_sel;
++}
++
++static int ftgmac100_set_rfifo_size(struct ftgmac100 *priv, int size_sel)
++{
++	int max_sel = FTGMAC100_FEAR_RFIFO_RSIZE(ioread32(priv->base + FTGMAC100_OFFSET_FEAR));
++	int tpafcr = ioread32(priv->base + FTGMAC100_OFFSET_TPAFCR);;
++
++	tpafcr &= ~FTGMAC100_TPAFCR_RFIFO_SIZE(0x7);
++
++	tpafcr |= FTGMAC100_TPAFCR_RFIFO_SIZE(max_sel);
++	iowrite32(tpafcr, priv->base + FTGMAC100_OFFSET_TPAFCR);
++	return max_sel;
++}
++
++static int ftgmac100_fifo_size_to_sel(int fifo_size)
++{
++	if (fifo_size <= (SZ_2K - SZ_32))
++		return 0;
++	else if (fifo_size <= (SZ_4K -SZ_32))
++		return 1;
++	else if (fifo_size <= (SZ_8K -SZ_32))
++		return 2;
++	else if (fifo_size <= (SZ_16K -SZ_32))
++		return 3;
++	else if (fifo_size <= (SZ_32K -SZ_32))
++		return 4;
++	else
++		return 5;
++}
++
++static unsigned int ftgmac100_fifo_size_sel_to_size(int sel)
++{
++	switch (sel) {
++	case 0:
++		return (SZ_2K - SZ_32);
++	case 1:
++		return (SZ_4K - SZ_32);
++	case 2:
++		return (SZ_8K -SZ_32);
++	case 3:
++		return (SZ_16K -SZ_32);
++	case 4:
++		return (SZ_32K -SZ_32);
++	default:
++		return 0;
++	}
++}
++
++static int ftgmac100_change_mtu(struct net_device *netdev, int new_mtu)
++{
++	unsigned int tx_size, rx_size, tx_sel, rx_sel, max_size;
++	struct ftgmac100 *priv = netdev_priv(netdev);
++	int sel = ftgmac100_fifo_size_to_sel(new_mtu);
++
++	tx_sel = ftgmac100_set_tfifo_size(priv, sel);
++	rx_sel = ftgmac100_set_rfifo_size(priv, sel);
++
++	priv->tx_fifo_sel = tx_sel;
++	priv->rx_fifo_sel = rx_sel;
++
++	tx_size = ftgmac100_fifo_size_sel_to_size(tx_sel);
++	rx_size = ftgmac100_fifo_size_sel_to_size(rx_sel);
++
++	max_size = (tx_size > rx_size) ? tx_size : rx_size;
++
++	netdev->mtu = (new_mtu < max_size) ? new_mtu : (max_size < MAX_PKT_SIZE) ? max_size : MAX_PKT_SIZE;
++
++	return 0;
++}
++
+ static const struct net_device_ops ftgmac100_netdev_ops = {
+ 	.ndo_open		= ftgmac100_open,
+ 	.ndo_stop		= ftgmac100_stop,
+ 	.ndo_start_xmit		= ftgmac100_hard_start_xmit,
+-	.ndo_set_mac_address	= eth_mac_addr,
++	.ndo_set_rx_mode	= ftgmac100_set_rx_mode,
++	.ndo_set_mac_address	= ftgmac100_mac_addr,
+ 	.ndo_validate_addr	= eth_validate_addr,
+ 	.ndo_do_ioctl		= ftgmac100_do_ioctl,
++	.ndo_change_mtu		= ftgmac100_change_mtu,
+ };
+ 
+ /******************************************************************************
+@@ -1193,7 +1969,11 @@ static int ftgmac100_probe(struct platform_device *pdev)
+ 	struct ftgmac100 *priv;
+ 	int err;
+ 	int i;
+-
++	int tx_num_queues = 1, rx_num_queues = 1;
++	char *ptr = NULL, *ptr_end;
++	u8 addr[6];
++	char ethaddr[18];
++	
+ 	if (!pdev)
+ 		return -ENODEV;
+ 
+@@ -1205,8 +1985,13 @@ static int ftgmac100_probe(struct platform_device *pdev)
+ 	if (irq < 0)
+ 		return irq;
+ 
++	if (num_online_cpus() > 1) {
++		tx_num_queues = TX_NUM_QUEUES;
++		rx_num_queues = RX_NUM_QUEUES;
++	}
++
+ 	/* setup net_device */
+-	netdev = alloc_etherdev(sizeof(*priv));
++	netdev = alloc_etherdev_mqs(sizeof(*priv), tx_num_queues, rx_num_queues);
+ 	if (!netdev) {
+ 		err = -ENOMEM;
+ 		goto err_alloc_etherdev;
+@@ -1216,17 +2001,17 @@ static int ftgmac100_probe(struct platform_device *pdev)
+ 
+ 	SET_ETHTOOL_OPS(netdev, &ftgmac100_ethtool_ops);
+ 	netdev->netdev_ops = &ftgmac100_netdev_ops;
+-	netdev->features = NETIF_F_IP_CSUM | NETIF_F_GRO;
++	netdev->features = NETIF_F_IP_CSUM | NETIF_F_GRO | NETIF_F_GSO;
+ 
+ 	platform_set_drvdata(pdev, netdev);
+ 
+ 	/* setup private data */
+ 	priv = netdev_priv(netdev);
++	priv->tx_num_queues = tx_num_queues;
++	priv->rx_num_queues = rx_num_queues;
+ 	priv->netdev = netdev;
+ 	priv->dev = &pdev->dev;
+ 
+-	spin_lock_init(&priv->tx_lock);
+-
+ 	/* initialize NAPI */
+ 	netif_napi_add(netdev, &priv->napi, ftgmac100_poll, 64);
+ 
+@@ -1248,15 +2033,26 @@ static int ftgmac100_probe(struct platform_device *pdev)
+ 
+ 	priv->irq = irq;
+ 
++	if(mac_scu_init(priv->irq) < 0){
++		err = -EIO;
++		goto err_alloc_mdiobus;
++	}
++	
+ 	/* initialize mdio bus */
++	set_mac_clock(priv->irq);
+ 	priv->mii_bus = mdiobus_alloc();
+ 	if (!priv->mii_bus) {
+ 		err = -EIO;
+ 		goto err_alloc_mdiobus;
+ 	}
+ 
+-	priv->mii_bus->name = "ftgmac100_mdio";
+-	snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "ftgmac100_mii");
++	if(irq == MAC_FTGMAC100_0_IRQ){
++		priv->mii_bus->name = "ftgmac100-0-mdio";
++		snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, DRV_NAME);
++	}else{
++		priv->mii_bus->name = "ftgmac100-1-mdio";
++		snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, DRV_1_NAME);	
++	}
+ 
+ 	priv->mii_bus->priv = netdev;
+ 	priv->mii_bus->read = ftgmac100_mdiobus_read;
+@@ -1286,14 +2082,54 @@ static int ftgmac100_probe(struct platform_device *pdev)
+ 		goto err_register_netdev;
+ 	}
+ 
+-	netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base);
++	//netdev_info(netdev, "%d tx queue used (max: %d)", priv->tx_num_queues, MAX_TX_QUEUES);
++	//netdev_info(netdev, "%d rx queue used (max: %d)", priv->rx_num_queues, MAX_RX_QUEUES);
++	//netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base);
+ 
+ 	if (!is_valid_ether_addr(netdev->dev_addr)) {
+-		random_ether_addr(netdev->dev_addr);
+-		netdev_info(netdev, "generated random MAC address %pM\n",
+-			    netdev->dev_addr);
++        ethaddr[17] = '\0';	    
++	    	if(irq == MAC_FTGMAC100_0_IRQ){	        
++            ptr = strstr(command_line, "ethaddr=");
++            if (ptr)
++                memcpy(ethaddr, ptr + 8, 17 * sizeof(char));
++        }
++        else{
++            ptr = strstr(command_line, "eth1addr=");
++            if (ptr)
++                memcpy(ethaddr, ptr + 9, 17 * sizeof(char));
++        }
++    
++        if (ptr) {
++            printk(KERN_NOTICE "ethaddr parsed from commandline: %s\n", ethaddr);
++            ptr_end = ethaddr;
++            
++            for (i = 0; i <= 5; i++) {
++                addr[i] = simple_strtol(ptr_end, &ptr_end, 16) |
++                          simple_strtol(ptr_end, &ptr_end, 16) << 4;
++                          ptr_end++; /* skip ":" in  ethaddr */
++                          
++            }
++            memcpy(netdev->dev_addr, addr, sizeof(addr));
++            
++        } else {	    	    
++    		random_ether_addr(netdev->dev_addr);
++    		//netdev_info(netdev, "generated random MAC address %pM\n", netdev->dev_addr);
++	    }
++    }
++
++	priv->tx_fifo_sel = 0x0;
++	priv->rx_fifo_sel = 0x0;
++	spin_lock_init(&priv->mac_lock);	
++
++	ftgmac_reg_debug->data = netdev;
++/*
++	err = ftgmac100_alloc_buffers(priv);
++	if (err) {
++		netdev_err(netdev, "failed to allocate buffers\n");
++		goto err_alloc_etherdev;
+ 	}
+-
++	priv->process_rx_ring = ftgmac100_process_rx_jumbo_ring;
++*/
+ 	return 0;
+ 
+ err_register_netdev:
+@@ -1328,6 +2164,8 @@ static int __exit ftgmac100_remove(struct platform_device *pdev)
+ 	mdiobus_unregister(priv->mii_bus);
+ 	mdiobus_free(priv->mii_bus);
+ 
++	mac_scu_close(priv->irq);
++	
+ 	iounmap(priv->base);
+ 	release_resource(priv->res);
+ 
+@@ -1337,6 +2175,7 @@ static int __exit ftgmac100_remove(struct platform_device *pdev)
+ 	return 0;
+ }
+ 
++#if defined(CONFIG_FTGMAC100_DRIVER_0_MASTER) || defined(CONFIG_FTGMAC100_DRIVER_0_SLAVE)
+ static struct platform_driver ftgmac100_driver = {
+ 	.probe		= ftgmac100_probe,
+ 	.remove		= __exit_p(ftgmac100_remove),
+@@ -1345,19 +2184,200 @@ static struct platform_driver ftgmac100_driver = {
+ 		.owner	= THIS_MODULE,
+ 	},
+ };
++#endif
++#if defined(CONFIG_FTGMAC100_DRIVER_1_MASTER) || defined(CONFIG_FTGMAC100_DRIVER_1_SLAVE)
++static struct platform_driver ftgmac100_1_driver = {
++	.probe		= ftgmac100_probe,
++	.remove		= __exit_p(ftgmac100_remove),
++	.driver		= {
++		.name	= DRV_1_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++#endif
++
++static int ftgmac_proc_tx_write(struct file *file, const char *buffer, unsigned long count,
++                                void *data)
++{
++    show_tx_pkg = *buffer - 48;
++    //printk("buf=%d,%d\n", *buffer, show_tx_pkg);
++    return count;
++}
++
++static int ftgmac_proc_rx_write(struct file *file, const char *buffer, unsigned long count,
++                                void *data)
++{
++    show_rx_pkg = *buffer - 48;
++    return count;
++}
++
++static int ftgmac_proc_phy_write(struct file *file, const char *buffer, unsigned long count,
++                                void *data)
++{
++    show_phy = *buffer - 48;
++    return count;
++}
+ 
++static int ftgmac_proc_rx_dbg_write(struct file *file, const char *buffer, unsigned long count,
++                                void *data)
++{
++    show_rx_dbg = *buffer - 48;
++    //printk("buf=%d,%d\n", *buffer, show_rx_dbg);
++    return count;
++}
++
++static int ftgmac_proc_reg_dbg_read(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++    struct net_device *netdev = data;
++    struct ftgmac100 *priv = netdev_priv(netdev);
++    unsigned int i, len = 0;
++
++	len += sprintf(page + len, "GMAC version %s, queue number tx = %d, rx = %d\n", DRV_VERSION, TX_QUEUE_ENTRIES, RX_QUEUE_ENTRIES);
++	for(i = 0; i < 15; i++) {
++    	len += sprintf(page + len, "reg%2x: %8x %8x %8x %8x\n", i * 16, ioread32(priv->base + i * 16 + 0), 
++    			ioread32(priv->base + i * 16 + 4), ioread32(priv->base + i * 16 + 8), ioread32(priv->base + i * 16 + 12));
++	}
++    return len;
++}
++
++int register_mac0 = 0, register_mac1 = 0;
+ /******************************************************************************
+  * initialization / finalization
+  *****************************************************************************/
+ static int __init ftgmac100_init(void)
+ {
+-	pr_info("Loading version " DRV_VERSION " ...\n");
+-	return platform_driver_register(&ftgmac100_driver);
++    int result = -ENODEV;
++  
++    command_line = kmalloc(COMMAND_LINE_SIZE, GFP_ATOMIC);
++    memcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
++
++	printk("GMAC version %s, queue number tx = %d, rx = %d\n", DRV_VERSION, TX_QUEUE_ENTRIES, RX_QUEUE_ENTRIES);
++
++    ftgmac_proc = create_proc_entry("ftgmac", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
++    if (ftgmac_proc == NULL) {
++        printk("Error to create driver ftgmac proc\n");
++        goto exit_init;
++    }
++    
++    ftgmac_tx_pkg_debug = create_proc_entry("show_tx", S_IRUGO, ftgmac_proc);
++    if (ftgmac_tx_pkg_debug == NULL)
++        panic("Fail to create proc ftgmac tx pkg!\n");
++
++    ftgmac_tx_pkg_debug->write_proc = ftgmac_proc_tx_write;
++
++    ftgmac_rx_pkg_debug = create_proc_entry("show_rx", S_IRUGO, ftgmac_proc);
++    if (ftgmac_rx_pkg_debug == NULL)
++        panic("Fail to create proc ftgmac rx pkg!\n");
++
++    ftgmac_rx_pkg_debug->write_proc = ftgmac_proc_rx_write;
++
++    ftgmac_phy_debug = create_proc_entry("show_phy", S_IRUGO, ftgmac_proc);
++    if (ftgmac_phy_debug == NULL)
++        panic("Fail to create proc ftgmac phy!\n");
++
++    ftgmac_phy_debug->write_proc = ftgmac_proc_phy_write;
++
++    ftgmac_rx_debug = create_proc_entry("show_rx_dbg", S_IRUGO, ftgmac_proc);
++    if (ftgmac_rx_debug == NULL)
++        panic("Fail to create proc ftgmac rx dbg!\n");
++
++    ftgmac_rx_debug->write_proc = ftgmac_proc_rx_dbg_write;
++
++    ftgmac_reg_debug = create_proc_entry("reg_dbg", S_IRUGO, ftgmac_proc);
++    if (ftgmac_reg_debug == NULL)
++        panic("Fail to create proc ftgmac reg dbg!\n");
++
++    ftgmac_reg_debug->read_proc = ftgmac_proc_reg_dbg_read;
++
++#ifdef Generate_PHY_Clock
++    if ((result = gpio_request(GPIO_pin, "gpio1")) != 0) {
++        printk("gpio request fail\n");
++        return result;
++    }
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8210
++#ifdef CONFIG_FTGMAC100_DRIVER_0_MASTER
++    if(!CPU_detect())
++        register_mac0 = 1;
++#endif
++#ifdef CONFIG_FTGMAC100_DRIVER_0_SLAVE
++    if(CPU_detect())
++        register_mac0 = 1;
++#endif
++#ifdef CONFIG_FTGMAC100_DRIVER_1_MASTER
++    if(!CPU_detect())
++        register_mac1 = 1;
++#endif
++#ifdef CONFIG_FTGMAC100_DRIVER_1_SLAVE
++    if(CPU_detect())
++        register_mac1 = 1;
++#endif
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8287) || defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++    register_mac0 = 1;
++#endif
++
++	if(register_mac0){
++	    platform_device_register(&ftgmac100_0_device);
++	    
++    	result = platform_driver_register(&ftgmac100_driver);
++    	if (result < 0) {
++    	    platform_device_unregister(&ftgmac100_0_device);
++	        goto exit_init;
++	    }
++	}
++#if defined(CONFIG_FTGMAC100_DRIVER_1_MASTER) || defined(CONFIG_FTGMAC100_DRIVER_1_SLAVE)	
++	if(register_mac1){
++	    platform_device_register(&ftgmac100_1_device);
++	    
++    	result = platform_driver_register(&ftgmac100_1_driver);
++    	if (result < 0) {
++    	    platform_device_unregister(&ftgmac100_1_device);
++	        goto exit_init;
++	    }
++	}
++#endif
++
++exit_init:		    	
++	return result;
+ }
+ 
+ static void __exit ftgmac100_exit(void)
+ {
+-	platform_driver_unregister(&ftgmac100_driver);
++    if (ftgmac_tx_pkg_debug != NULL)
++        remove_proc_entry(ftgmac_tx_pkg_debug->name, ftgmac_proc);
++
++    if (ftgmac_rx_pkg_debug != NULL)
++        remove_proc_entry(ftgmac_rx_pkg_debug->name, ftgmac_proc);
++
++    if (ftgmac_phy_debug != NULL)
++        remove_proc_entry(ftgmac_phy_debug->name, ftgmac_proc);
++
++    if (ftgmac_rx_debug != NULL)
++        remove_proc_entry(ftgmac_rx_debug->name, ftgmac_proc);
++
++    if (ftgmac_reg_debug != NULL)
++        remove_proc_entry(ftgmac_reg_debug->name, ftgmac_proc);                
++
++    if (ftgmac_proc != NULL)
++        remove_proc_entry(ftgmac_proc->name, NULL);
++        
++#ifdef Generate_PHY_Clock
++	gpio_free(GPIO_pin);
++#endif
++
++    if(register_mac0) {
++    	platform_driver_unregister(&ftgmac100_driver);
++    	platform_device_unregister(&ftgmac100_0_device);
++    }
++#if defined(CONFIG_FTGMAC100_DRIVER_1_MASTER) || defined(CONFIG_FTGMAC100_DRIVER_1_SLAVE)
++    if(register_mac1) {
++    	platform_driver_unregister(&ftgmac100_1_driver);
++    	platform_device_unregister(&ftgmac100_1_device);
++    }
++#endif    
+ }
+ 
+ module_init(ftgmac100_init);
+diff --git a/drivers/net/ethernet/faraday/ftgmac100.h b/drivers/net/ethernet/faraday/ftgmac100.h
+index 13408d44..9e73a07e 100644
+--- a/drivers/net/ethernet/faraday/ftgmac100.h
++++ b/drivers/net/ethernet/faraday/ftgmac100.h
+@@ -22,6 +22,8 @@
+ #ifndef __FTGMAC100_H
+ #define __FTGMAC100_H
+ 
++#define CONFIG_FTGMAC100_STORM
++
+ #define FTGMAC100_OFFSET_ISR		0x00
+ #define FTGMAC100_OFFSET_IER		0x04
+ #define FTGMAC100_OFFSET_MAC_MADR	0x08
+@@ -138,6 +140,22 @@
+  */
+ #define FTGMAC100_RBSR_SIZE(x)		((x) & 0x3fff)
+ 
++/*
++ * Feature Register (0x44)
++ */
++#define FTGMAC100_FEAR_TFIFO_RSIZE(x) ((x & 0x38) >> 3)
++#define FTGMAC100_FEAR_RFIFO_RSIZE(x) ((x & 0x7) >> 0)
++
++/*
++ * Transmit Priority Arbitration and FIFO Control register (0x48)
++ */
++#define FTGMAC100_TPAFCR_TFIFO_SIZE(x)  ((x & 0x7) << 27)
++#define FTGMAC100_TPAFCR_RFIFO_SIZE(x)  ((x & 0x7) << 24)
++#define FTGMAC100_TPAFCR_EARLY_TXTHR(x) ((x & 0xff) << 16)
++#define FTGMAC100_TPAFCR_EARLY_RXTHR(x) ((x & 0xff) << 8)
++#define FTGMAC100_TPAFCR_HPKT_THR(x)    ((x & 0xf) << 4)
++#define FTGMAC100_TPAFCR_NPKT_THR(x)    ((x & 0xf) << 0)
++
+ /*
+  * MAC control register
+  */
+@@ -165,8 +183,13 @@
+ /*
+  * PHY control register
+  */
++#ifdef CONFIG_PLATFORM_GM8210
+ #define FTGMAC100_PHYCR_MDC_CYCTHR_MASK	0x3f
+ #define FTGMAC100_PHYCR_MDC_CYCTHR(x)	((x) & 0x3f)
++#else  
++#define FTGMAC100_PHYCR_MDC_CYCTHR_MASK	0xff        
++#define FTGMAC100_PHYCR_MDC_CYCTHR(x)	((x) & 0xff)
++#endif
+ #define FTGMAC100_PHYCR_PHYAD(x)	(((x) & 0x1f) << 16)
+ #define FTGMAC100_PHYCR_REGAD(x)	(((x) & 0x1f) << 21)
+ #define FTGMAC100_PHYCR_MIIRD		(1 << 26)
+@@ -204,6 +227,40 @@ struct ftgmac100_txdes {
+ #define FTGMAC100_TXDES1_TX2FIC		(1 << 30)
+ #define FTGMAC100_TXDES1_TXIC		(1 << 31)
+ 
++/* user define */
++#ifdef CONFIG_FTMAC_TINY
++#define RX_QUEUE_ENTRIES	128	    /* must be power of 2 */
++#define TX_QUEUE_ENTRIES	128	    /* must be power of 2 */
++#else
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++#define RX_QUEUE_ENTRIES	128	    /* must be power of 2 */
++#define TX_QUEUE_ENTRIES	256	    /* must be power of 2 */
++#else
++#define RX_QUEUE_ENTRIES	512	    /* must be power of 2 */
++#define TX_QUEUE_ENTRIES	1024	/* must be power of 2 */
++#endif
++#endif
++
++#ifdef CONFIG_FTGMAC100_STORM
++#define RX_BROADCAST_THRESHOLD	800
++#define RX_DETECT_TIME	200
++#define RX_DELAY_TIME	1000
++#endif
++
++#define TX_QUEUE_THRESHOLD  (TX_QUEUE_ENTRIES / 4)
++
++#define MAX_PKT_SIZE		9216
++#define RX_BUF_SIZE		PAGE_SIZE	/* must be smaller than 0x3fff */
++
++#define RX_NUM_QUEUES	1
++#define TX_NUM_QUEUES	1
++
++#define MAX_RX_QUEUES   1
++#define MAX_TX_QUEUES	2
++
++/* software used bits */
++#define FTGMAC100_TXDES1_USED (1 << 20)
++
+ /*
+  * Receive descriptor, aligned to 16 bytes
+  */
+@@ -214,6 +271,45 @@ struct ftgmac100_rxdes {
+ 	unsigned int	rxdes3;	/* RXBUF_BADR */
+ } __attribute__ ((aligned(16)));
+ 
++struct ftgmac100_page {
++	struct page *page;
++	void *page_va;
++};
++
++struct ftgmac100 {
++	struct resource *res;
++	void __iomem *base;
++	int irq;
++
++	struct ftgmac100_rx_ring *rx_rings;
++	struct ftgmac100_tx_ring *tx_rings;
++
++	struct net_device *netdev;
++	struct device *dev;
++	struct napi_struct napi;
++
++	struct mii_bus *mii_bus;
++	int phy_irq[PHY_MAX_ADDR];
++	struct phy_device *phydev;
++	int old_speed;
++	int old_duplex;
++	int tx_fifo_sel;
++	int rx_fifo_sel;
++	int tx_num_queues;
++	int rx_num_queues;
++	int link_flag;
++	spinlock_t mac_lock;
++	bool (*process_rx_ring)(struct ftgmac100_rx_ring *, struct napi_struct *);
++#ifdef CONFIG_FTGMAC100_STORM
++	struct timer_list   timer;
++	unsigned int broadcast_num;
++	unsigned int delay_time;
++	unsigned long begin_jiffies;
++	unsigned long end_jiffies;
++	bool enable_rx;
++#endif
++};
++
+ #define FTGMAC100_RXDES0_VDBC		0x3fff
+ #define FTGMAC100_RXDES0_EDORR		(1 << 15)
+ #define FTGMAC100_RXDES0_MULTICAST	(1 << 16)
+@@ -243,4 +339,29 @@ struct ftgmac100_rxdes {
+ #define FTGMAC100_RXDES1_UDP_CHKSUM_ERR	(1 << 26)
+ #define FTGMAC100_RXDES1_IP_CHKSUM_ERR	(1 << 27)
+ 
++#define DRV_NAME	"ftgmac100-0"
++#define DRV_1_NAME	"ftgmac100-1"
++#define DRV_VERSION	"2.2"
++
++void wait_status(int millisecond);
++int mac_scu_init(int irq);
++void mac_scu_close(int irq);
++void set_mac_clock(int irq);
++void set_MDC_CLK(struct ftgmac100 *priv);
++int CPU_detect(void);
++void mac_reset(void);      
++int interface_type(void); 
++ 
++#ifdef CONFIG_PLATFORM_GM8181
++#define Generate_PHY_Clock  	1
++#define GPIO_pin  		0      
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8210
++#ifndef CONFIG_GM8210_FPGA
++//#define Generate_PHY_Clock  	1   //reset phy at u-boot or burn-in code
++#endif
++#define GPIO_pin  		        0     
++#endif
++
+ #endif /* __FTGMAC100_H */
+diff --git a/drivers/net/ethernet/faraday/ftgmac100_platform.c b/drivers/net/ethernet/faraday/ftgmac100_platform.c
+new file mode 100644
+index 00000000..81484ccd
+--- /dev/null
++++ b/drivers/net/ethernet/faraday/ftgmac100_platform.c
+@@ -0,0 +1,276 @@
++/*
++ * Faraday FTGMAC100 Ethernet
++ *
++ * (C) Copyright 2009 Faraday Technology
++ * Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * 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 <linux/version.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/mii.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/phy.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include "ftgmac100.h"
++#include <mach/ftpmu010.h>
++#include <mach/fmem.h>
++#include <linux/gpio.h>
++
++static int mac_fd = 0, mac_fd_1 = 0;
++
++#if defined(CONFIG_FTGMAC100_DRIVER_0_MASTER) || defined(CONFIG_FTGMAC100_DRIVER_0_SLAVE)
++#ifdef CONFIG_PLATFORM_GM8210
++static pmuReg_t pmu_reg[] = {
++    {0x28, (0x1 << 29), (0x1 << 29), 0, (0x1 << 29)},	//phy clock select
++    {0x4C, (0x1 << 26), (0x1 << 26), (0x1 << 26), (0x1 << 26)},	//GTX_CLK polarity
++    {0x70, 0x1F, 0x1F, 0, 0x1F},											//phy clock pvalue
++    {0x7C, (0x1 << 2), (0x1 << 2), 0, (0x1 << 2)},		//rx clock phase
++    {0xA0, (0x1 << 18), (0x1 << 18), (0x1 << 18), (0x1 << 18)},	//reset	    
++    {0xB4, (0x1 << 14), (0x1 << 14), 0, (0x1 << 14)}, //clock off   
++};
++
++static pmuRegInfo_t pmu_reg_info = {
++    DRV_NAME,
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_PLL1,
++    &pmu_reg[0]
++};
++#endif
++#ifdef CONFIG_PLATFORM_GM8287
++static pmuReg_t pmu_reg[] = {
++    {0x28, (0x1 << 29), (0x1 << 29), 0, (0x1 << 29)},
++    {0x40, (0xF << 12), (0xF << 12), (0x3 << 12), (0xF << 12)},
++    {0x4C, (0x1 << 26), (0x1 << 26), 0, (0x1 << 26)},
++    //{0x50, (0xF << 10), (0xF << 10), 0, (0xF << 10)},// u-boot will set RGMII or RMII
++    //{0x70, 0x1F, 0x1F, 0x5, 0x1F},// u-boot will set this function with UART
++    {0x7C, (0x1 << 2), (0x1 << 2), 0, (0x1 << 2)},
++    {0xA0, (0x1 << 18), (0x1 << 18), (0x1 << 18), (0x1 << 18)},
++    {0xB4, (0x1 << 14), (0x1 << 14), 0, (0x1 << 14)},    
++};
++
++static pmuRegInfo_t pmu_reg_info = {
++    DRV_NAME,
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_PLL1,
++    &pmu_reg[0]
++};
++#endif
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++static pmuReg_t pmu_reg[] = {
++    {0x28, (0x1 << 4), (0x1 << 4), 0, (0x1 << 4)},
++    //{0x5C, (0xFFFFFFFF << 0), (0xFFFFFFFF << 0), 0x22222222, (0xFFFFFFFF << 0)},// u-boot will set RGMII or RMII
++    //{0x60, (0xFFFFFFFF << 0), (0xFFFFFFFF << 0), 0x11112022, (0xFFFFFFFF << 0)},// u-boot will set RGMII or RMII
++#ifdef CONFIG_FPGA
++    {0x70, (0xFF << 4), (0xFF << 4), 0, (0xFF << 4)},
++    {0x7C, (0x7 << 3), (0x7 << 3), 0x20, (0x7 << 3)}, //RGMII
++#else
++    //{0x70, (0xFF << 4), (0xFF << 4), 0, (0xFF << 4)},// u-boot will set this function with UART
++    //{0x7C, (0x7 << 3), (0x7 << 3), 0, (0x7 << 3)},  // u-boot will set RGMII or RMII
++#endif
++    {0xA0, (0x1 << 18), (0x1 << 18), (0x1 << 18), (0x1 << 18)},
++    {0xAC, (0x1 << 5), (0x1 << 5), 0, (0x1 << 5)}, 
++    {0xB4, (0x1 << 11), (0x1 << 11), 0, (0x1 << 11)},  
++};
++
++static pmuRegInfo_t pmu_reg_info = {
++    DRV_NAME,
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_PLL1,
++    &pmu_reg[0]
++};
++#endif
++#endif
++
++#if defined(CONFIG_FTGMAC100_DRIVER_1_MASTER) || defined(CONFIG_FTGMAC100_DRIVER_1_SLAVE) 
++static pmuReg_t pmu_reg_1[] = {
++    //{reg_off, bits_mask, lock_bits, init_val, init_mask},
++    {0x28, (0x1 << 28), (0x1 << 28), 0, 0},
++    {0x4C, (0x1 << 27), (0x1 << 27), 0, 0},
++    {0x50, (0x1 << 14), (0x1 << 14), 0, 0},
++    {0x70, (0x1F << 5), (0x1F << 5), 0, 0},
++    {0x7C, (0x1 << 3), (0x1 << 3), 0, 0},
++    {0xA0, (0x1 << 19), (0x1 << 19), 0, 0},
++    {0xB4, (0x1 << 13), (0x1 << 13), 0, 0},  
++};
++static pmuRegInfo_t pmu_reg_info_1 = {
++    DRV_1_NAME,
++    ARRAY_SIZE(pmu_reg_1),
++    ATTR_TYPE_PLL1,
++    &pmu_reg_1[0]
++};
++#endif
++
++void wait_status(int millisecond)
++{
++    if (in_interrupt() || in_atomic()){
++        mdelay(millisecond);
++    }else{           
++        set_current_state(TASK_INTERRUPTIBLE);
++        schedule_timeout((HZ / 1000) * millisecond);
++    }
++} 
++
++int CPU_detect(void)
++{
++#ifdef CONFIG_PLATFORM_GM8210	
++	fmem_pci_id_t pci_id;
++	fmem_cpu_id_t cpu_id;
++	fmem_get_identifier(&pci_id, &cpu_id);
++	if(cpu_id == FMEM_CPU_FA626)
++		return 1;
++#endif
++	return 0;			
++} 
++
++void set_mac_clock(int irq)
++{
++    int tmp_fd;
++    
++    if(irq == MAC_FTGMAC100_0_IRQ)
++	    tmp_fd = mac_fd;
++    else
++	    tmp_fd = mac_fd_1;
++
++#ifdef CONFIG_PLATFORM_GM8210
++    if(!CPU_detect()){
++    	if(irq == MAC_FTGMAC100_0_IRQ){
++		    //set phy X_GMII0_CLK_IN
++		    ftpmu010_write_reg(tmp_fd, 0x28, 0, (0x1 << 29));
++		    //set MAC p-value
++		    ftpmu010_write_reg(tmp_fd, 0x70, 0, 0x1);
++    	}
++  	}
++
++    if(CPU_detect()){
++	    if(irq == MAC_FTGMAC100_1_IRQ){
++		    //set phy X_GMII1_CLK_IN
++		    ftpmu010_write_reg(tmp_fd, 0x28, 0, (0x1 << 28));
++		    //set pin-mux
++		    ftpmu010_write_reg(tmp_fd, 0x50, 0, (0x1 << 14));        
++		    //set MAC p-value
++		    ftpmu010_write_reg(tmp_fd, 0x70, 0, (0x1 << 5));    
++	    }
++  	}
++#endif
++
++#ifdef Generate_PHY_Clock              //Generate clock for GMAC
++
++    wait_status(10);
++    printk("Set PHY clock\n");
++    gpio_direction_output(GPIO_pin, 1);
++#ifdef CONFIG_ICPLUS_PHY
++    wait_status(3000);
++#else
++    wait_status(10);
++#endif    
++    printk("Set PHY clock finish\n");
++#endif
++
++}
++
++void set_MDC_CLK(struct ftgmac100 *priv)
++{
++#ifndef CONFIG_PLATFORM_GM8210  /* 8210 can use default value */
++    int tmp;
++    
++    tmp = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
++    tmp &= ~FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
++    tmp |= FTGMAC100_PHYCR_MDC_CYCTHR(0xF0);
++    iowrite32(tmp, priv->base + FTGMAC100_OFFSET_PHYCR);
++#endif
++}
++
++int mac_scu_init(int irq)
++{
++    if(!CPU_detect()){
++	    if(irq == MAC_FTGMAC100_0_IRQ){
++	    	mac_fd = ftpmu010_register_reg(&pmu_reg_info);
++	     	if (mac_fd < 0) {
++	   	        printk("MAC: %s register reg fail \n", __FUNCTION__);
++	 		    return -1;
++	    	}
++#if defined(CONFIG_PLATFORM_GM8210) || defined(CONFIG_PLATFORM_GM8287)
++    		ftpmu010_write_reg(mac_fd, 0xB4, 0, (0x1 << 14)); 
++#endif
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++    		ftpmu010_write_reg(mac_fd, 0xB4, 0, (0x1 << 11)); 
++#endif
++    	}
++  	} 	
++
++#ifdef CONFIG_PLATFORM_GM8210
++    if(CPU_detect()){
++    	if(irq == MAC_FTGMAC100_1_IRQ){
++	    	mac_fd_1 = ftpmu010_register_reg(&pmu_reg_info_1);    
++	     	if (mac_fd_1 < 0) {
++	   	    printk("MAC: %s register reg fail \n", __FUNCTION__);
++	 		    return -1;
++	    	}     	
++	        ftpmu010_write_reg(mac_fd_1, 0xB4, 0, (0x1 << 13));
++    	}
++  	}  
++#endif     
++    return 0; 
++}
++
++void mac_scu_close(int irq)
++{
++    //IP Clock off 
++    if(irq == MAC_FTGMAC100_0_IRQ){
++#if defined(CONFIG_PLATFORM_GM8210) || defined(CONFIG_PLATFORM_GM8287)
++    	ftpmu010_write_reg(mac_fd, 0xB4, (0x1 << 14), (0x1 << 14)); 
++#endif
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++    	ftpmu010_write_reg(mac_fd, 0xB4, (0x1 << 11), (0x1 << 11)); 
++#endif 
++    	ftpmu010_deregister_reg(mac_fd);
++    }
++    else{
++    	ftpmu010_write_reg(mac_fd_1, 0xB4, (0x1 << 13), (0x1 << 13)); 
++    	ftpmu010_deregister_reg(mac_fd_1);
++    }
++}
++
++void mac_reset(void)
++{    
++    ftpmu010_write_reg(mac_fd, 0xA0, 0, (0x1 << 18));
++    //mdelay(1);
++    printk("HW reset\n");
++    ftpmu010_write_reg(mac_fd, 0xA0, (0x1 << 18), (0x1 << 18));
++} 
++
++/*  1-RMII or MII mode; 0-RGMII or GMII mode */
++int interface_type(void)
++{
++#ifdef CONFIG_PLATFORM_GM8287
++    if((ftpmu010_read_reg(0xD8) & 0x7) == 0x5)
++        return 0;
++#endif
++#ifdef CONFIG_PLATFORM_GM8139
++    if(ftpmu010_read_reg(0x7C) & (1 << 5))
++        return 0;
++#endif        
++	return 1;
++}
+\ No newline at end of file
+diff --git a/drivers/net/ethernet/faraday/ftmac110.c b/drivers/net/ethernet/faraday/ftmac110.c
+new file mode 100644
+index 00000000..f164bc06
+--- /dev/null
++++ b/drivers/net/ethernet/faraday/ftmac110.c
+@@ -0,0 +1,1190 @@
++/*
++ *
++ * Copyright (C) 2011 Dante Su <dantesu@faraday-tech.com>
++ *
++ * 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 <linux/version.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/mii.h>
++#include <linux/phy.h>
++#include <linux/init.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++
++#include <linux/crc32.h>
++#include <linux/inet_lro.h>
++#include <linux/if_ether.h>
++#include <linux/if_vlan.h>
++#include <linux/if_link.h>
++#include <linux/ethtool.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++#include <linux/tcp.h>
++#include <net/ip6_checksum.h>
++
++#include <asm/io.h>
++#include <mach/ftpmu010.h>
++#include "ftmac110.h"
++
++#define CFG_XDESC_NUM
++#define CFG_TXDESC_NUM           CONFIG_FTMAC110_NDESC_TX
++#define CFG_RXDESC_NUM           CONFIG_FTMAC110_NDESC_RX
++#define CFG_XBUF_SIZE            1536
++
++#define CFG_NAPI_WEIGHT          CONFIG_FTMAC110_NDESC_RX
++#define CFG_LRO_MAX_AGGR         CFG_NAPI_WEIGHT
++#define CFG_LRO_MAX_DESC         (CFG_LRO_MAX_AGGR >> 1)
++
++#define DRV_NAME                 "ftmac110"     //name must match with platform.c
++#define DRV_VERSION              "1.0rc2"
++#define DRV_RELDATE              "May 24, 2011"
++
++#ifndef EMAC_REG32
++#define EMAC_REG32(priv, off)    *(volatile uint32_t *)((priv)->iobase + (off))
++#endif
++
++static int mac_fd = 0;
++
++typedef struct ftmac110_priv {
++    struct net_device_stats stats;
++    spinlock_t lock;
++#ifdef CONFIG_FTMAC110_PHYMON
++    struct timer_list timer;
++#endif
++#ifdef CONFIG_FTMAC110_NAPI
++    struct napi_struct napi;
++# ifdef CONFIG_FTMAC110_NAPI_LRO
++    struct net_lro_mgr lro_mgr;
++    struct net_lro_desc lro_desc[CFG_LRO_MAX_DESC];
++# endif
++#endif                          /* #ifdef CONFIG_FTMAC110_NAPI */
++    struct net_device *netdev;
++    struct device *dev;
++
++    uint32_t irq;
++    uint32_t irqmask;
++    uint32_t iobase;
++    uint32_t maccr;
++
++    void *desc_pool;
++
++    ftmac110_rxdesc_t *rx_descs;
++    dma_addr_t rx_descs_dma;
++    uint32_t rx_insert;
++    uint32_t rx_remove;
++    uint32_t rx_free;
++
++    ftmac110_txdesc_t *tx_descs;
++    dma_addr_t tx_descs_dma;
++    uint32_t tx_insert;
++    uint32_t tx_remove;
++    uint32_t tx_free;
++
++    struct mii_if_info mii_if;
++
++    struct {
++        uint32_t oui:24;
++        uint32_t model:6;
++        uint32_t rsvd:30;
++        uint32_t rev:4;
++    } phyid;
++
++} ftmac110_priv_t;
++
++static void wait_status(int millisecond)
++{
++        if (in_interrupt() || in_atomic()){
++            mdelay(millisecond);
++        }else{           
++            set_current_state(TASK_INTERRUPTIBLE);
++            schedule_timeout((HZ / 1000) * millisecond);
++        }
++} 
++
++/* 
++ * Local driver functions
++ */
++static int mdio_read(struct net_device *dev, int phy_id, int phy_reg)
++{
++    ftmac110_priv_t *priv = netdev_priv(dev);
++    uint32_t tmp, i;
++
++    tmp = MIIREG_READ | (phy_id << MIIREG_PHYADDR_SHIFT)
++        | (phy_reg << MIIREG_PHYREG_SHIFT)
++        | 0x30000000;
++
++    EMAC_REG32(priv, PHYCR_REG) = tmp;
++
++    for (i = 0; i < 100; i++) {
++        tmp = EMAC_REG32(priv, PHYCR_REG);
++        if ((tmp & MIIREG_READ) == 0) 
++           return (int)(tmp & 0xFFFF);  
++        
++        wait_status(10);
++    }
++
++    printk("mdio read timed out\n");
++    return -EIO;
++}
++
++static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
++{
++    ftmac110_priv_t *priv = netdev_priv(dev);
++    uint32_t tmp, i;
++
++    tmp = MIIREG_WRITE | (phy_id << MIIREG_PHYADDR_SHIFT)
++        | (phy_reg << MIIREG_PHYREG_SHIFT)
++        | 0x30000000;
++
++    EMAC_REG32(priv, PHYDATA_REG) = val;
++    EMAC_REG32(priv, PHYCR_REG) = tmp;
++
++    for (i = 0; i < 100; i++) {
++        tmp = EMAC_REG32(priv, PHYCR_REG);
++        
++        if ((tmp & MIIREG_WRITE) == 0) 
++            return;   
++                 
++        wait_status(10);
++    }
++	
++    printk("mdio write timed out\n");   
++    return;    
++}
++
++#ifdef CONFIG_PLATFORM_GM8126
++/*
++ * GM8126
++ */
++#define GM_PHY
++
++static pmuReg_t pmu_reg_8126[] = {
++    {0x38, (0x1 << 8) | (0x1 << 10), (0x1 << 8) | (0x1 << 10), 0, 0},
++    {0x58, (0x1 << 31), (0x1 << 31), 0, 0},
++    {0x5C, (0xF << 28), (0xF << 28), 0, 0},
++    {0x60, (0xFF << 22), (0xFF << 22), 0, 0},
++    {0x64, 0xFFFFFFFF, 0, 0, 0},
++    {0x6c, (0x1 << 10) | (0x1 << 11) | (0x1 << 18), (0x1 << 10) | (0x1 << 11) | (0x1 << 18), 0x0,
++     0x0},
++    {0x74, (0x3F << 26), (0x3F << 26), 0, 0},
++    {0x84, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0},
++};
++
++static pmuRegInfo_t pmu_reg_info_8126 = {
++    "MAC_8126",
++    ARRAY_SIZE(pmu_reg_8126),
++    ATTR_TYPE_PLL1,
++    &pmu_reg_8126[0]
++};
++
++static int ftmac110_pmu8126_init(void)
++{
++    int div = 0, tmp;
++
++    mac_fd = ftpmu010_register_reg(&pmu_reg_info_8126);
++    if (mac_fd < 0) {
++        printk("MAC: %s fail \n", __FUNCTION__);
++        return -1;
++    }
++    //MHz change to hz
++    tmp = ftpmu010_get_attr(ATTR_TYPE_PMUVER);
++    tmp &= 0xF0;
++    switch (tmp) {
++    case 0x10:
++        div = ftpmu010_clock_divisor(mac_fd, 100000000, 1) - 1;
++        break;
++    case 0x20:
++#ifdef RMII
++        div = ftpmu010_clock_divisor(mac_fd, 50000000, 1) - 1;  //RMII 50MHz
++#else
++        div = ftpmu010_clock_divisor(mac_fd, 25000000, 1) - 1;  //MII 25MHz
++#endif
++        break;
++    default:
++        printk("chip ID not match, use default div = %d\n", div);
++        break;
++    }
++    if (!div)
++        div = 1;
++    //printk("MAC clock div = %d, PLL1 clk = %d\n",div,ftpmu010_get_attr(ATTR_TYPE_PLL1));
++
++    //MAC PHY pin mux
++    ftpmu010_write_reg(mac_fd, 0x5C, (0x5 << 28), (0xF << 28));
++    ftpmu010_write_reg(mac_fd, 0x64, 0x55555555, 0xFFFFFFFF);
++
++#ifdef GM_PHY
++    /* MAC clock on(bit8) and PHY clock on(bit10) */
++    ftpmu010_write_reg(mac_fd, 0x38, 0, (0x1 << 8) | (0x1 << 10));
++    /* set MAC CLK div */
++    if (tmp == 0x10) {
++        printk("Not support test chip\n");
++    } else
++        ftpmu010_write_reg(mac_fd, 0x74, (div << 26), (0x3F << 26));
++
++    /* MII clock enable */
++#ifdef RMII
++    ftpmu010_write_reg(mac_fd, 0x6c, (0x1 << 10) | (0x1 << 18),
++                       (0x1 << 10) | (0x1 << 11) | (0x1 << 18) | (0x1 << 19));
++#else
++    ftpmu010_write_reg(mac_fd, 0x6c, (0x1 << 10) | (0x1 << 18),
++                       (0x1 << 10) | (0x1 << 11) | (0x1 << 18));
++#endif
++#else
++    /* MII pinmux */
++    ftpmu010_write_reg(mac_fd, 0x60, (0x55 << 22), (0xFF << 22));
++
++    /* MAC clock on(bit8) and PHY clock on(bit10) */
++    ftpmu010_write_reg(mac_fd, 0x38, (0x1 << 10), (0x1 << 8) | (0x1 << 10));
++    /* set MAC CLK div */
++    ftpmu010_write_reg(mac_fd, 0x74, (div << 26), (0x3F << 26));
++
++    /* MII always enable */
++    ftpmu010_write_reg(mac_fd, 0x58, (0x1 << 31), (0x1 << 31));
++    /* Select MII amd bypass internal PHY */
++#ifdef RMII
++    ftpmu010_write_reg(mac_fd, 0x6C, (0x1 << 10) | (0x1 << 11) | (0x1 << 18),
++                       (0x1 << 10) | (0x1 << 11) | (0x1 << 18) | (0x1 << 19));
++#else
++    ftpmu010_write_reg(mac_fd, 0x6C, (0x1 << 10) | (0x1 << 11) | (0x1 << 18),
++                       (0x1 << 10) | (0x1 << 11) | (0x1 << 18));
++#endif
++#endif
++    return 0;
++}
++#endif
++
++static uint32_t ftmac110_phyqry(ftmac110_priv_t * priv)
++{
++    uint32_t retry;
++    uint32_t maccr;
++    int adv, lpa, tmp, media;
++
++    maccr = Speed_100_bit | FULLDUP_bit;
++
++    // 1. check link status
++    for (retry = 3000000; retry; --retry) {
++        if (mii_link_ok(&priv->mii_if))
++            break;
++    }
++    if (!retry) {
++        netif_carrier_off(priv->netdev);
++        printk("ftmac110: link down\n");
++        goto exit;
++    }
++    netif_carrier_on(priv->netdev);
++
++    // 2. check A/N status
++    for (retry = 3000000; retry; --retry) {
++        tmp = mdio_read(priv->netdev, priv->mii_if.phy_id, MII_BMSR);
++        if (tmp & BMSR_ANEGCOMPLETE)
++            break;
++    }
++    if (!retry) {
++        printk("ftmac110: A/N failed\n");
++        goto exit;
++    }
++    adv = mdio_read(priv->netdev, priv->mii_if.phy_id, MII_ADVERTISE);
++    lpa = mdio_read(priv->netdev, priv->mii_if.phy_id, MII_LPA);
++    media = mii_nway_result(lpa & adv);
++
++    // 3. build MACCR with the PHY status
++    maccr = 0;
++
++    // 10/100Mbps Detection
++    if (media & ADVERTISE_100FULL)
++        maccr |= Speed_100_bit | FULLDUP_bit;
++    else if (media & ADVERTISE_100HALF)
++        maccr |= Speed_100_bit | ENRX_IN_HALFTX_bit;
++    else if (media & ADVERTISE_10FULL)
++        maccr |= FULLDUP_bit;
++    else if (media & ADVERTISE_10HALF)
++        maccr |= ENRX_IN_HALFTX_bit;
++
++    // 3-2. Vendor ID
++    /*
++       tmp = mdio_read(priv->netdev, priv->mii_if.phy_id, MII_PHYSID2);
++       priv->phyid.oui   = (mdio_read(priv->netdev, priv->mii_if.phy_id, MII_PHYSID1) << 6) | (tmp >> 10);
++       priv->phyid.model = (tmp >> 4) & 0x3F;
++       priv->phyid.rev   = (tmp & 0x0F);    
++       printk("ftmac110: PHY OUI=0x%06X, Model=0x%02X, Rev=0x%02X\n",
++       priv->phyid.oui, priv->phyid.model, priv->phyid.rev); 
++     */
++
++    printk("ftmac110: %d Mbps, %s\r\n",
++           (maccr & Speed_100_bit) ? 100 : 10, (maccr & FULLDUP_bit) ? "Full" : "half");
++
++    maccr |= CRC_APD_bit | RX_BROADPKT_bit | RX_RUNT_bit
++        | RCV_EN_bit | XMT_EN_bit | RDMA_EN_bit | XDMA_EN_bit;
++
++  exit:
++    return maccr;
++}
++
++#ifdef CONFIG_FTMAC110_PHYMON
++static void ftmac110_timer(unsigned long d)
++{
++    ftmac110_priv_t *priv = (ftmac110_priv_t *) d;
++
++    if (mii_link_ok(&priv->mii_if)) {
++        if (!netif_carrier_ok(priv->netdev)) {
++            printk("ftmac110: link up\n");
++            spin_lock(&priv->lock);
++            priv->maccr = ftmac110_phyqry(priv);
++            EMAC_REG32(priv, MACCR_REG) = priv->maccr;
++            spin_unlock(&priv->lock);
++        }
++    } else {
++        if (netif_carrier_ok(priv->netdev)) {
++            netif_carrier_off(priv->netdev);
++            printk("ftmac110: link down\n");
++        }
++    }
++
++    priv->timer.data = (unsigned long)priv;
++    priv->timer.function = ftmac110_timer;
++    priv->timer.expires = jiffies + msecs_to_jiffies(250);
++    add_timer(&priv->timer);
++}
++#endif /* #ifdef CONFIG_FTMAC110_PHYMON */
++
++static int ftmac110_rx_alloc(ftmac110_priv_t * priv)
++{
++    struct sk_buff *skb;
++    volatile ftmac110_rxdesc_t *rxd;
++
++    while (priv->rx_free < CFG_RXDESC_NUM) {
++        rxd = priv->rx_descs + priv->rx_insert;
++        if (rxd->owner == 1)    // owned by HW
++            break;
++
++        skb = netdev_alloc_skb(priv->netdev, CFG_XBUF_SIZE + NET_IP_ALIGN);
++        if (skb == NULL) {
++            printk("ftmac110: out of memory\n");
++            return -1;
++        }
++        skb_reserve(skb, NET_IP_ALIGN);
++
++        //printk("ftmac110: rxd[%d]: buf@0x%08X\n", priv->rx_insert, (uint32_t)skb->tail);
++        priv->rx_insert = (priv->rx_insert + 1) % CFG_RXDESC_NUM;
++        priv->rx_free++;
++
++        rxd->skb = skb;
++        rxd->buf = dma_map_single(priv->dev, skb->tail, CFG_XBUF_SIZE, DMA_FROM_DEVICE);
++        rxd->len = 0;
++        rxd->bufsz = CFG_XBUF_SIZE;
++        rxd->owner = 1;         // owned by HW
++    }
++
++    return 0;
++}
++
++static int ftmac110_set_mac_address(struct net_device *dev, void *p)
++{
++    struct ftmac110_priv *priv = netdev_priv(dev);
++    unsigned char *a = dev->dev_addr;
++    struct sockaddr *addr = p;
++
++    if (addr != NULL) {
++        if (!is_valid_ether_addr(addr->sa_data))
++            return -EADDRNOTAVAIL;
++        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
++    }
++    //spin_lock_irq(&priv->lock);
++
++    EMAC_REG32(priv, MAC_MADR_REG) = a[1] | (a[0] << 8);
++    EMAC_REG32(priv, MAC_LADR_REG) = a[5] | (a[4] << 8) | (a[3] << 16) | (a[2] << 24);
++
++    //spin_unlock_irq(&priv->lock);
++
++    return 0;
++}
++
++static int ftmac110_up(ftmac110_priv_t * priv)
++{
++    uint32_t maccr;
++
++    // 1. MAC reset
++    EMAC_REG32(priv, MACCR_REG) = SW_RST_bit;
++    do {
++        maccr = EMAC_REG32(priv, MACCR_REG);
++    } while (maccr & SW_RST_bit);
++
++    // 2. PHY status query & Fix up the MACCR value 
++    maccr = ftmac110_phyqry(priv);
++    priv->maccr = maccr;
++    priv->irqmask = XPKT_LOST_bit | NOTXBUF_bit | XPKT_FINISH_bit
++        | RPKT_LOST_bit | NORXBUF_bit | RPKT_FINISH_bit | PHYSTS_CHG_bit;
++
++    // 3. MAC address setup
++    ftmac110_set_mac_address(priv->netdev, NULL);
++
++    // 4. MAC registers setup
++    EMAC_REG32(priv, RXR_BADR_REG) = priv->rx_descs_dma;
++    EMAC_REG32(priv, TXR_BADR_REG) = priv->tx_descs_dma;
++    EMAC_REG32(priv, ITC_REG) = 0x0000FFFF;
++    EMAC_REG32(priv, APTC_REG) = 0x00000011;
++    EMAC_REG32(priv, DBLAC_REG) = 0x00000390;
++    EMAC_REG32(priv, ISR_REG) = 0x000003FF;
++    EMAC_REG32(priv, IMR_REG) = priv->irqmask;
++    EMAC_REG32(priv, MACCR_REG) = priv->maccr;
++
++    EMAC_REG32(priv, FCR_REG) |= 0x1;   //Flow Control
++    EMAC_REG32(priv, BPR_REG) |= 0x1;
++
++    return 0;
++}
++
++static int ftmac110_down(ftmac110_priv_t * priv)
++{
++    EMAC_REG32(priv, IMR_REG) = 0;
++    EMAC_REG32(priv, MACCR_REG) = 0;
++    return 0;
++}
++
++static int ftmac110_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++    ftmac110_priv_t *priv = netdev_priv(dev);
++    volatile ftmac110_txdesc_t *txd;
++    unsigned long flags;
++
++    if (skb == NULL)            /* NULL skb directly return */
++        return 0;
++
++    if (skb->len >= CFG_XBUF_SIZE) {    /* Packet too long, drop it */
++        dev_kfree_skb(skb);
++        return 0;
++    }
++
++    /* Critical Section */
++    spin_lock_irqsave(&priv->lock, flags);
++
++    /* TX resource check */
++    if (priv->tx_free == 0) {
++        netif_stop_queue(dev);
++        priv->stats.tx_dropped++;
++        EMAC_REG32(priv, TXPD_REG) = 0xffffffff;        // kick-off Tx DMA
++        spin_unlock_irqrestore(&priv->lock, flags);
++        //printk("ftmac110: out of txd\n");
++        return 1;
++    }
++
++    /* Statistic Counter */
++    priv->stats.tx_packets++;
++    priv->stats.tx_bytes += skb->len;
++
++    /* Set TX descriptor & Transmit it */
++    priv->tx_free--;
++    txd = priv->tx_descs + priv->tx_insert;
++    priv->tx_insert = (priv->tx_insert + 1) % CFG_TXDESC_NUM;
++
++    txd->skb = skb;
++    txd->len = skb->len < 64 ? 64 : skb->len;
++    txd->buf = dma_map_single(priv->dev, skb->data, skb->len, DMA_TO_DEVICE);
++    txd->lts = 1;
++    txd->fts = 1;
++    txd->owner = 1;
++
++    EMAC_REG32(priv, TXPD_REG) = 0xffffffff;    // kick-off Tx DMA
++
++    dev->trans_start = jiffies;
++    spin_unlock_irqrestore(&priv->lock, flags);
++
++    //printk("ftmac110: send..1\n");
++
++    return 0;
++}
++
++int phy_read_duplex(struct net_device *dev)
++{
++    int bmcr;
++    ftmac110_priv_t *priv = netdev_priv(dev);
++
++    bmcr = mdio_read(priv->netdev, priv->mii_if.phy_id, MII_BMCR);
++    if (bmcr & BMCR_FULLDPLX) {
++        return 1;               //Full
++    } else {
++        return 0;               //Half
++    }
++}
++
++int phy_read_speed(struct net_device *dev)
++{
++    int bmcr;
++    ftmac110_priv_t *priv = netdev_priv(dev);
++
++    bmcr = mdio_read(priv->netdev, priv->mii_if.phy_id, MII_BMCR);
++    if (bmcr & BMCR_SPEED100)
++        return 1;
++    else
++        return 0;
++}
++
++static void ftmac110_link_change(struct net_device *dev)
++{
++    unsigned int data;
++    ftmac110_priv_t *priv = netdev_priv(dev);
++
++    data = mdio_read(priv->netdev, priv->mii_if.phy_id, MII_BMSR);
++
++    if (data & BMSR_LSTATUS)
++        netif_carrier_on(dev);
++    else
++        netif_carrier_off(dev);
++
++    data = EMAC_REG32(priv, MACCR_REG);
++    if (phy_read_speed(dev)) {
++        EMAC_REG32(priv, MACCR_REG) = data | Speed_100_bit;
++        printk("Link Change: <SPEED100>\n");
++    } else {
++        EMAC_REG32(priv, MACCR_REG) = data & (~Speed_100_bit);
++        printk("Link Change: <SPEED10>\n");
++    }
++
++    if (phy_read_duplex(dev)) {
++        EMAC_REG32(priv, MACCR_REG) = data | FULLDUP_bit;
++        printk("Link Change: <FULL>\n");
++    } else {
++        EMAC_REG32(priv, MACCR_REG) = data & (~FULLDUP_bit);
++        printk("Link Change: <HALF>\n");
++    }
++
++#ifdef GM_PHY
++#if 0                           //for customer tune 10M mode PHY TX curren
++
++    val = mdio_read(dev, 1, 0x11) & 0xFFCF;
++    //mdio_write(dev, 1, 0x11, val | 0x10);//improve 10M mode PHY TX current 25uA
++    //mdio_write(dev, 1, 0x11, val | 0x20);//improve 10M mode PHY TX current 40uA
++    //mdio_write(dev, 1, 0x11, val | 0x30);//improve 10M mode PHY TX current 65uA
++    //mdio_write(dev, 1, 0x11, val);//default
++    //printk("PHY reg 0x11 = %#x\n",mdio_read(dev, 1, 0x11));
++#endif
++
++#if 0                           //for customer tune 100M mode PHY TX curren
++    //mdio_write(dev, 1, 0x12, 0x0E49);//improve 100M mode PHY TX current 6%
++    //mdio_write(dev, 1, 0x12, 0x0C49);//improve 100M mode PHY TX current 4%
++    //mdio_write(dev, 1, 0x12, 0x0A49);//improve 100M mode PHY TX current 2%
++    //mdio_write(dev, 1, 0x12, 0x0849);//default
++    //printk("PHY reg 0x12 = %#x\n",mdio_read(dev, 1, 0x12));
++#endif
++#endif
++}
++
++static irqreturn_t ftmac110_interrupt(int irq, void *dev_id)
++{
++    uint32_t stat;
++    unsigned long flags;
++    struct net_device *dev = dev_id;
++    ftmac110_priv_t *priv = netdev_priv(dev);
++
++    spin_lock_irqsave(&priv->lock, flags);
++
++    // fetch&clear interrupt status
++    stat = EMAC_REG32(priv, ISR_REG);
++    // disable interrupt
++    EMAC_REG32(priv, IMR_REG) = 0;
++
++    //printk("ftmac110: isr=0x%08X\n", stat);
++
++    // 1. rx drop
++    if (stat & NORXBUF_bit)
++        priv->stats.rx_dropped++;
++
++    // 3. tx done
++    if (stat & (XPKT_OK_bit | XPKT_LOST_bit | NOTXBUF_bit)) {
++        volatile ftmac110_txdesc_t *txd;
++        while (priv->tx_free < CFG_TXDESC_NUM) {
++            txd = priv->tx_descs + priv->tx_remove;
++            if (txd->owner)     // owned by HW
++                break;
++            if (txd->error)
++                priv->stats.tx_errors++;
++            dev_kfree_skb_irq(txd->skb);
++            txd->skb = NULL;
++            priv->tx_free++;
++            priv->tx_remove = (priv->tx_remove + 1) % CFG_TXDESC_NUM;
++        }
++    }
++    // 2. rx done
++    if (stat & (RPKT_FINISH_bit | RPKT_LOST_bit)) {
++#ifdef CONFIG_FTMAC110_NAPI
++        if (napi_schedule_prep(&priv->napi)) {
++            priv->irqmask &= ~(RPKT_LOST_bit | NORXBUF_bit | RPKT_FINISH_bit);
++            __napi_schedule(&priv->napi);
++        }
++#else
++        struct sk_buff *skb;
++        volatile ftmac110_rxdesc_t *rxd;
++        while (priv->rx_free > 0) {
++            rxd = priv->rx_descs + priv->rx_remove;
++            if (rxd->owner == 1)        // owned by HW
++                break;
++            skb = rxd->skb;
++            rxd->skb = NULL;
++            if (rxd->error) {
++                priv->stats.rx_errors++;
++                dev_kfree_skb_irq(skb);
++            } else {
++                skb->dev = dev;
++                skb_put(skb, rxd->len);
++                skb->protocol = eth_type_trans(skb, dev);
++                netif_rx(skb);  /* Send to upper layer */
++                priv->stats.rx_packets++;
++                priv->stats.rx_bytes += rxd->len;
++            }
++            priv->rx_free--;
++            priv->rx_remove = (priv->rx_remove + 1) % CFG_RXDESC_NUM;
++        }
++#endif
++    }
++    // 4. link change
++    if (stat & PHYSTS_CHG_bit)
++        ftmac110_link_change(dev);
++
++    if (priv->tx_free > 0)
++        netif_wake_queue(dev);
++
++    if (priv->rx_free < CFG_RXDESC_NUM)
++        ftmac110_rx_alloc(priv);
++
++    // enable interrupt
++    EMAC_REG32(priv, IMR_REG) = priv->irqmask;
++
++    spin_unlock_irqrestore(&priv->lock, flags);
++    return IRQ_HANDLED;
++}
++
++static inline int ftmac110_mcast_hash(int len, const uint8_t * data)
++{
++    return ether_crc(len, data) >> 26;
++}
++
++#if 0
++static void ftmac110_set_rx_mode(struct net_device *dev)
++{
++    uint32_t maccr;
++    unsigned long flags;
++    struct ftmac110_priv *priv = netdev_priv(dev);
++
++    spin_lock_irqsave(&priv->lock, flags);
++
++    maccr = priv->maccr & ~(RCV_ALL_bit | RX_MULTIPKT_bit | HT_MULTI_EN_bit);
++
++    if (dev->flags & IFF_PROMISC) {
++        maccr |= RCV_ALL_bit;
++    } else if (dev->flags & IFF_ALLMULTI) {
++        maccr |= RX_MULTIPKT_bit;
++    } else {
++        uint32_t ht[2] = { 0, 0 };
++        struct dev_mc_list *mclist;
++        int i;
++
++        for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
++            int hash = ftmac110_mcast_hash(ETH_ALEN, mclist->dmi_addr);
++            /*
++               printk("ftmac110: %02X:%02X:%02X:%02X:%02X:%02X=%d\n",
++               ha->addr[0], ha->addr[1], ha->addr[2],
++               ha->addr[3], ha->addr[4], ha->addr[5],
++               hash);
++             */
++            if (hash >= 32) {
++                ht[1] |= (1 << (hash - 32));
++            } else {
++                ht[0] |= (1 << (hash - 0));
++            }
++        }
++
++        if (ht[0] || ht[1]) {
++            maccr |= HT_MULTI_EN_bit;
++            EMAC_REG32(priv, MAHT0_REG) = ht[0];
++            EMAC_REG32(priv, MAHT1_REG) = ht[1];
++        }
++    }
++
++    priv->maccr = maccr;
++    EMAC_REG32(priv, MACCR_REG) = priv->maccr;
++
++    spin_unlock_irqrestore(&priv->lock, flags);
++
++    //printk("ftmac110: ftmac110_set_rx_mode...0x%08X\n", maccr);
++}
++#endif
++
++static int ftmac110_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++    struct ftmac110_priv *priv = netdev_priv(dev);
++    unsigned long flags;
++    int rc;
++
++    spin_lock_irqsave(&priv->lock, flags);
++    rc = generic_mii_ioctl(&priv->mii_if, if_mii(ifr), cmd, NULL);
++    spin_unlock_irqrestore(&priv->lock, flags);
++    return rc;
++}
++
++static struct net_device_stats *ftmac110_get_stats(struct net_device *dev)
++{
++    struct ftmac110_priv *priv = netdev_priv(dev);
++    return &priv->stats;
++}
++
++static int ftmac110_phy_reset(void)
++{
++#ifdef GM_PHY
++    //reset Faraday PHY, for N-Way
++    printk("reset Faraday Internal PHY.\n");
++    ftpmu010_write_reg(mac_fd, 0x84, 0, 0x1 | (0x3 << 4));
++    wait_status(1);
++    ftpmu010_write_reg(mac_fd, 0x84, 0x1, 0x1);
++#endif
++    return 0;
++}
++
++static int ftmac110_open(struct net_device *dev)
++{
++    struct ftmac110_priv *priv = netdev_priv(dev);
++    int i;
++    size_t sz;
++    void *va;
++    dma_addr_t pa;
++
++    spin_lock_irq(&priv->lock);
++
++    /* Request IRQ and Register interrupt handler */
++    if (request_irq(priv->irq, ftmac110_interrupt, IRQF_SHARED, dev->name, dev)) {
++        printk("ftmac110: failed to register irq\n");
++        return -1;
++    }
++
++    /* Allocate Descriptor memory (16 bytes aligned) */
++    sz = 16 + sizeof(ftmac110_txdesc_t) * CFG_TXDESC_NUM +
++        sizeof(ftmac110_rxdesc_t) * CFG_RXDESC_NUM;
++    va = dma_alloc_coherent(priv->dev, sz, &pa, GFP_KERNEL);
++    if (!va) {
++        printk("ftmac110: out of memory\n");
++        return -ENOMEM;
++    }
++    memset(va, 0, sz);
++    pa = (pa + 15) & 0xFFFFFFF0;
++    va = (void *)(((uint32_t) va + 15) & 0xFFFFFFF0);
++
++    priv->desc_pool = va;
++
++    // Init tx ring
++    priv->tx_descs = va;
++    priv->tx_descs_dma = pa;
++    for (i = 0; i < CFG_TXDESC_NUM; ++i) {
++        priv->tx_descs[i].len = 0;
++        priv->tx_descs[i].end = 0;
++        priv->tx_descs[i].owner = 0;    // owned by SW
++        //printk("ftmac110: txd[%d]@0x%08X\n", i, (uint32_t)&priv->tx_descs[i]);
++    }
++    priv->tx_descs[CFG_TXDESC_NUM - 1].end = 1;
++    priv->tx_insert = priv->tx_remove = 0;
++    priv->tx_free = CFG_TXDESC_NUM;
++
++    // Init rx ring
++    priv->rx_descs =
++        (ftmac110_rxdesc_t *) ((uint32_t) va + sizeof(ftmac110_txdesc_t) * CFG_TXDESC_NUM);
++    priv->rx_descs_dma = pa + sizeof(ftmac110_txdesc_t) * CFG_TXDESC_NUM;
++    for (i = 0; i < CFG_RXDESC_NUM; ++i) {
++        priv->rx_descs[i].end = 0;
++        priv->rx_descs[i].owner = 0;    // owned by SW
++        //printk("ftmac110: rxd[%d]@0x%08X\n", i, (uint32_t)&priv->rx_descs[i]);
++    }
++    priv->rx_descs[CFG_RXDESC_NUM - 1].end = 1;
++    priv->rx_insert = priv->rx_remove = 0;
++    priv->rx_free = 0;
++    ftmac110_rx_alloc(priv);
++
++    ftmac110_phy_reset();
++    // chip enable
++    ftmac110_up(priv);
++
++#ifdef CONFIG_FTMAC110_NAPI
++    napi_enable(&priv->napi);
++#endif
++    // netdev enable
++    netif_start_queue(dev);
++
++    spin_unlock_irq(&priv->lock);
++
++#ifdef CONFIG_FTMAC110_PHYMON
++    priv->timer.data = (unsigned long)priv;
++    priv->timer.function = ftmac110_timer;
++    priv->timer.expires = jiffies + msecs_to_jiffies(500);
++    add_timer(&priv->timer);
++#endif
++    return 0;
++}
++
++static int ftmac110_close(struct net_device *dev)
++{
++    struct ftmac110_priv *priv = netdev_priv(dev);
++
++#ifdef CONFIG_FTMAC110_PHYMON
++    del_timer_sync(&priv->timer);
++#endif
++
++    spin_lock_irq(&priv->lock);
++
++#ifdef CONFIG_FTMAC110_NAPI
++    napi_disable(&priv->napi);
++#endif
++
++    netif_stop_queue(dev);
++
++    ftmac110_down(priv);
++
++    free_irq(priv->irq, dev);
++
++    spin_unlock_irq(&priv->lock);
++    return 0;
++}
++
++#ifdef CONFIG_FTMAC110_NAPI
++
++# ifdef CONFIG_FTMAC110_NAPI_LRO
++static int
++ftmac110_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph, u64 * hdr_flags, void *priv)
++{
++    struct iphdr *iph;
++    unsigned int ipl;
++
++    skb_reset_network_header(skb);
++    iph = ip_hdr(skb);
++    ipl = ip_hdrlen(skb);
++
++    /* check if ipv4 & tcp */
++    if (iph->version != 4 || iph->protocol != IPPROTO_TCP)
++        return -1;
++
++    skb_set_transport_header(skb, ipl);
++
++    /* check if ip header and tcp header are complete */
++    if (ntohs(iph->tot_len) < ipl + tcp_hdrlen(skb))
++        return -1;
++
++    *iphdr = iph;
++    *tcph = tcp_hdr(skb);
++    *hdr_flags = LRO_IPV4 | LRO_TCP;
++
++    return 0;
++}
++# endif /* #ifdef CONFIG_FTMAC110_NAPI_LRO */
++
++static int ftmac110_rx_poll(struct napi_struct *napi, int budget)
++{
++    struct ftmac110_priv *priv = container_of(napi, struct ftmac110_priv, napi);
++    struct net_device *dev = priv->netdev;
++    int rx;
++
++    struct sk_buff *skb;
++    volatile ftmac110_rxdesc_t *rxd;
++
++    rx = 0;
++    while (priv->rx_free > 0) {
++        rxd = priv->rx_descs + priv->rx_remove;
++        if (rxd->owner == 1)    // owned by HW
++            break;
++        skb = rxd->skb;
++        rxd->skb = NULL;
++        if (rxd->error) {
++            priv->stats.rx_errors++;
++            dev_kfree_skb_irq(skb);
++        } else {
++            skb->dev = dev;
++            skb_put(skb, rxd->len);
++            skb->protocol = eth_type_trans(skb, dev);
++#ifdef CONFIG_FTMAC110_NAPI_LRO
++            lro_receive_skb(&priv->lro_mgr, skb, priv);
++#else
++            netif_receive_skb(skb);     /* Send to upper layer */
++#endif
++            priv->stats.rx_packets++;
++            priv->stats.rx_bytes += rxd->len;
++        }
++        priv->rx_free--;
++        priv->rx_remove = (priv->rx_remove + 1) % CFG_RXDESC_NUM;
++
++        if (++rx >= budget)
++            break;
++    }
++
++#ifdef CONFIG_FTMAC110_NAPI_LRO
++    lro_flush_all(&priv->lro_mgr);
++#endif
++
++    /* if we did not reach work limit, then we're done with
++     * this round of polling
++     */
++    if (rx < budget) {
++        unsigned long flags;
++
++        spin_lock_irqsave(&priv->lock, flags);
++        priv->irqmask |= (RPKT_LOST_bit | NORXBUF_bit | RPKT_FINISH_bit);
++        EMAC_REG32(priv, IMR_REG) = priv->irqmask;
++        __napi_complete(napi);
++        spin_unlock_irqrestore(&priv->lock, flags);
++    }
++
++    return 0;
++}
++
++#endif /* #ifdef CONFIG_FTMAC110_NAPI */
++
++/******************************************************************************
++ * ethtool stuff
++ *****************************************************************************/
++#if 0
++static int ftmac110_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++    struct ftmac110_priv *priv = netdev_priv(dev);
++    unsigned long flags;
++    int rc;
++
++    spin_lock_irqsave(&priv->lock, flags);
++    rc = mii_ethtool_gset(&priv->mii, cmd);
++    spin_unlock_irqrestore(&priv->lock, flags);
++
++    return rc;
++}
++
++static int ftmac110_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
++{
++    struct ftmac110_priv *priv = netdev_priv(dev);
++    unsigned long flags;
++    int rc;
++
++    spin_lock_irqsave(&priv->lock, flags);
++    rc = mii_ethtool_sset(&priv->mii, cmd);
++    spin_unlock_irqrestore(&priv->lock, flags);
++
++    return rc;
++}
++#endif
++static void ftmac110_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
++{
++    strcpy(info->driver, DRV_NAME);
++    strcpy(info->version, DRV_VERSION);
++}
++
++static int ftmac110_nway_reset(struct net_device *dev)
++{
++    struct ftmac110_priv *priv = netdev_priv(dev);
++    unsigned long flags;
++    int rc;
++
++    spin_lock_irqsave(&priv->lock, flags);
++    rc = mii_nway_restart(&priv->mii_if);
++    spin_unlock_irqrestore(&priv->lock, flags);
++    return rc;
++}
++
++static const struct ethtool_ops ftmac110_ethtool_ops = {
++    //.set_settings    = ftmac110_set_settings,
++    //.get_settings    = ftmac110_get_settings,
++    .get_drvinfo = ftmac110_get_drvinfo,
++    .get_link = ethtool_op_get_link,
++    .nway_reset = ftmac110_nway_reset,
++};
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static const struct net_device_ops ftmac110_netdev_ops = {
++    .ndo_open = ftmac110_open,
++    .ndo_stop = ftmac110_close,
++    .ndo_start_xmit = ftmac110_start_xmit,
++    //.ndo_set_rx_mode      = ftmac110_set_rx_mode,
++    .ndo_set_mac_address = ftmac110_set_mac_address,
++    .ndo_validate_addr = eth_validate_addr,
++    .ndo_do_ioctl = ftmac110_ioctl,
++    .ndo_get_stats = ftmac110_get_stats,
++};
++
++static int ftmac110_probe(struct platform_device *pdev)
++{
++    int irq, err;
++    void *iobase;
++    struct net_device *dev;
++    ftmac110_priv_t *priv;
++    struct resource *res;
++    static u64 dma_mask = DMA_BIT_MASK(32);
++
++    if (pdev == NULL)
++        return -ENODEV;
++
++    /* find IRQ */
++    res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++    if (!res)
++        return -ENODEV;
++    irq = res->start;
++
++    /* find IOBASE */
++    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++    if (!res)
++        return -ENODEV;
++    if (!request_mem_region(res->start, res->end - res->start + 1, "ftmac110")) {
++        printk("ftmac110: controller already in use\n");
++        return -EBUSY;
++    }
++    iobase = ioremap(res->start, res->end - res->start + 1);
++    if (iobase == NULL) {
++        printk("ftmac110: failed to map memory\n");
++        release_mem_region(res->start, res->end - res->start + 1);
++        return -EFAULT;
++    }
++
++    /* setup net_device */
++    dev = alloc_etherdev(sizeof(ftmac110_priv_t));
++    if (dev == NULL) {
++        printk("ftmac110: out of memory\n");
++        iounmap(iobase);
++        release_mem_region(res->start, res->end - res->start + 1);
++        return -ENOMEM;
++    }
++
++    SET_NETDEV_DEV(dev, &pdev->dev);
++    SET_ETHTOOL_OPS(dev, &ftmac110_ethtool_ops);
++    dev->netdev_ops = &ftmac110_netdev_ops;
++
++    platform_set_drvdata(pdev, dev);
++
++    /* setup private data */
++    priv = netdev_priv(dev);
++    priv->netdev = dev;
++    priv->dev = &(dev->dev);
++    priv->irq = irq;
++    priv->iobase = (uint32_t) iobase;
++#ifdef CONFIG_FTMAC110_NAPI
++    printk("Enable NAPI\n");
++    netif_napi_add(dev, &priv->napi, ftmac110_rx_poll, CFG_NAPI_WEIGHT);
++# ifdef CONFIG_FTMAC110_NAPI_LRO
++    printk("Enable NAPI_LRO\n");
++    dev->features |= NETIF_F_LRO;
++    priv->lro_mgr.max_aggr = CFG_LRO_MAX_AGGR;
++    priv->lro_mgr.max_desc = CFG_LRO_MAX_DESC;
++    priv->lro_mgr.lro_arr = priv->lro_desc;
++    priv->lro_mgr.get_skb_header = ftmac110_get_skb_header;
++    priv->lro_mgr.features = LRO_F_NAPI;
++    priv->lro_mgr.dev = priv->netdev;
++    priv->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
++    priv->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
++# endif
++#endif /* #ifdef CONFIG_FTMAC110_NAPI */
++    spin_lock_init(&priv->lock);
++
++    priv->mii_if.dev = dev;
++    priv->mii_if.mdio_read = mdio_read;
++    priv->mii_if.mdio_write = mdio_write;
++    priv->mii_if.phy_id = CONFIG_FTMAC110_PHYADDR;
++    priv->mii_if.phy_id_mask = 0x1f;
++    priv->mii_if.reg_num_mask = 0x1f;
++
++    dev->base_addr = (uint32_t) iobase;
++    dev->irq = irq;
++    dev->dev.dma_mask = &dma_mask;
++    dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
++
++    pdev->dev.dma_mask = &dma_mask;
++    pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
++
++    /* register network device */
++    err = register_netdev(dev);
++    if (err) {
++        printk("ftmac110: failed to register netdev\n");
++        iounmap(iobase);
++        release_mem_region(res->start, res->end - res->start + 1);
++        return err;
++    }
++
++    printk("ftmac110: irq=%d, iobase=0x%08X\n", priv->irq, priv->iobase);
++
++    if (is_zero_ether_addr(dev->dev_addr))
++        random_ether_addr(dev->dev_addr);
++    dev->dev_addr[0] = 0x00;
++    printk("ftmac110: mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
++           dev->dev_addr[0], dev->dev_addr[1],
++           dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
++
++#ifdef CONFIG_FTMAC110_PHYMON
++    init_timer(&priv->timer);
++#endif
++    return 0;
++}
++
++static int ftmac110_remove(struct platform_device *pdev)
++{
++    struct net_device *dev;
++    ftmac110_priv_t *priv;
++
++    dev = platform_get_drvdata(pdev);
++    priv = netdev_priv(dev);
++
++    unregister_netdev(dev);
++
++    iounmap((volatile void *)priv->iobase);
++
++    platform_set_drvdata(pdev, NULL);
++
++    free_netdev(dev);
++
++    return 0;
++}
++
++static struct platform_driver ftmac110_driver = {
++    .probe = ftmac110_probe,
++    .remove = ftmac110_remove,
++    .driver = {
++               .name = DRV_NAME,
++               .owner = THIS_MODULE,
++               },
++};
++
++static int __init ftmac110_init(void)
++{
++#ifdef CONFIG_PLATFORM_GM8126
++    int result = -ENODEV;
++
++    result = ftmac110_pmu8126_init();
++    if (result < 0) {
++        printk("GM8126 pmu init fail\n");
++        return result;
++    }
++#endif
++    return platform_driver_register(&ftmac110_driver);
++}
++
++static void __exit ftmac110_cleanup(void)
++{
++    ftpmu010_deregister_reg(mac_fd);
++    platform_driver_unregister(&ftmac110_driver);
++}
++
++module_init(ftmac110_init);
++module_exit(ftmac110_cleanup);
++
++MODULE_AUTHOR("Dante Su <dantesu@faraday-tech.com>");
++MODULE_DESCRIPTION("ftmac110 driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/net/ethernet/faraday/ftmac110.h b/drivers/net/ethernet/faraday/ftmac110.h
+new file mode 100644
+index 00000000..2f45ed17
+--- /dev/null
++++ b/drivers/net/ethernet/faraday/ftmac110.h
+@@ -0,0 +1,123 @@
++#ifndef FTMAC110_H
++#define FTMAC110_H
++
++// --------------------------------------------------------------------
++//        FTMAC110 MAC Registers
++// --------------------------------------------------------------------
++
++#define ISR_REG             0x00        // interrups status register
++#define IMR_REG             0x04        // interrupt maks register
++#define MAC_MADR_REG        0x08        // MAC address (Most significant)
++#define MAC_LADR_REG        0x0c        // MAC address (Least significant)
++#define MAHT0_REG           0x10        // Multicast Address Hash Table 0 register
++#define MAHT1_REG           0x14        // Multicast Address Hash Table 1 register
++#define TXPD_REG            0x18        // Transmit Poll Demand register
++#define RXPD_REG            0x1c        // Receive Poll Demand register
++#define TXR_BADR_REG        0x20        // Transmit Ring Base Address register
++#define RXR_BADR_REG        0x24        // Receive Ring Base Address register
++#define ITC_REG             0x28        // interrupt timer control register
++#define APTC_REG            0x2C        // Automatic Polling Timer control register
++#define DBLAC_REG           0x30        // DMA Burst Length and Arbitration control register
++
++#define MACCR_REG           0x88        // MAC control register
++#define MACSR_REG           0x8C        // MAC status register
++#define PHYCR_REG           0x90        // PHY control register
++#define PHYDATA_REG         0x94        // PHY Write Data register
++#define FCR_REG             0x98        // Flow Control register
++#define BPR_REG             0x9c        // back pressure register
++
++//Interrupt status register(ISR), Interrupt mask register(IMR) bit setting
++#define PHYSTS_CHG_bit		(1UL<<9)
++#define AHB_ERR_bit		(1UL<<8)
++#define RPKT_LOST_bit		(1UL<<7)
++#define RPKT_SAV_bit		(1UL<<6)
++#define XPKT_LOST_bit		(1UL<<5)
++#define XPKT_OK_bit		(1UL<<4)
++#define NOTXBUF_bit		(1UL<<3)
++#define XPKT_FINISH_bit		(1UL<<2)
++#define NORXBUF_bit		(1UL<<1)
++#define RPKT_FINISH_bit		(1UL<<0)
++
++/* MACC control bits */
++#define Speed_100_bit		(1UL<<18)
++#define RX_BROADPKT_bit		(1UL<<17)       // Receiving broadcast packet
++#define RX_MULTIPKT_bit		(1UL<<16)       // receiving multicast packet
++#define FULLDUP_bit		(1UL<<15)       // full duplex
++#define CRC_APD_bit		(1UL<<14)       // append crc to transmit packet
++#define RCV_ALL_bit		(1UL<<12)       // not check incoming packet's destination address
++#define RX_FTL_bit		(1UL<<11)       // Store incoming packet even its length is les than 64 byte
++#define RX_RUNT_bit		(1UL<<10)       // Store incoming packet even its length is les than 64 byte
++#define HT_MULTI_EN_bit		(1UL<<9)
++#define RCV_EN_bit		(1UL<<8)        // receiver enable
++#define ENRX_IN_HALFTX_bit	(1UL<<6)        // rx in half tx
++#define XMT_EN_bit		(1UL<<5)        // transmitter enable
++#define CRC_DIS_bit		(1UL<<4)
++#define LOOP_EN_bit		(1UL<<3)        // Internal loop-back
++#define SW_RST_bit		(1UL<<2)
++#define RDMA_EN_bit		(1UL<<1)        // enable DMA receiving channel
++#define XDMA_EN_bit		(1UL<<0)        // enable DMA transmitting channel
++
++// --------------------------------------------------------------------
++//        MII PHY Registers
++// --------------------------------------------------------------------
++
++//
++// Bits related to the MII interface
++//
++#define MIIREG_READ		(1 << 26)
++#define MIIREG_WRITE		(1 << 27)
++#define MIIREG_PHYREG_SHIFT	21
++#define MIIREG_PHYADDR_SHIFT	16
++
++// --------------------------------------------------------------------
++//        Receive Ring descriptor structure
++// --------------------------------------------------------------------
++typedef struct {
++    // RXDES0
++    uint32_t len:11;            // BIT:  0 - 10
++    uint32_t rsvd1:5;           // BIT: 11 - 15
++    uint32_t mcast:1;           // BIT: 16
++    uint32_t bcast:1;           // BIT: 17
++    uint32_t error:5;
++    uint32_t rsvd2:5;           // BIT: 23 - 27
++    uint32_t lrs:1;             // BIT: 28
++    uint32_t frs:1;             // BIT: 29
++    uint32_t rsvd3:1;           // BIT: 30
++    uint32_t owner:1;           // BIT: 31 - 1:Hardware, 0: Software
++
++    // RXDES1
++    uint32_t bufsz:11;          // BIT:  0 - 10
++    uint32_t rsvd4:20;          // BIT: 11 - 30
++    uint32_t end:1;             // BIT: 31
++
++    // RXDES2
++    uint32_t buf;
++
++    // RXDES3
++    void *skb;
++} ftmac110_rxdesc_t;
++
++typedef struct {
++    // TXDES0
++    uint32_t error:2;
++    uint32_t rsvd1:29;
++    uint32_t owner:1;           // BIT: 31 - 1:Hardware, 0: Software
++
++    // TXDES1
++    uint32_t len:11;            // BIT:  0 - 10
++    uint32_t rsvd2:16;
++    uint32_t lts:1;             // BIT: 27
++    uint32_t fts:1;             // BIT: 28
++    uint32_t tx2fic:1;          // BIT: 29
++    uint32_t txic:1;            // BIT: 30
++    uint32_t end:1;             // BIT: 31
++
++    // TXDES2
++    uint32_t buf;
++
++    // TXDES3
++    void *skb;
++
++} ftmac110_txdesc_t;
++
++#endif /* FTMAC_H */
+diff --git a/drivers/net/ethernet/faraday/ptp.c b/drivers/net/ethernet/faraday/ptp.c
+new file mode 100644
+index 00000000..427f8184
+--- /dev/null
++++ b/drivers/net/ethernet/faraday/ptp.c
+@@ -0,0 +1,328 @@
++/*******************************************************************************
++
++  Intel PRO/0300 Linux driver
++  Copyright(c) 1999 - 2013 Intel Corporation.
++  
++  Faraday FTGMAC030 PTP Linux driver
++  Copyright(c) 2014-2016 Faraday Technology
++
++  This program is free software; you can redistribute it and/or modify it
++  under the terms and conditions of the GNU General Public License,
++  version 2, as published by the Free Software Foundation.
++
++  This program is distributed in the hope it will be useful, but WITHOUT
++  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++  FITNESS FOR A PARTICULAR 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++  The full GNU General Public License is included in this distribution in
++  the file called "COPYING".
++
++  Contact Information:
++  Linux NICS <linux.nics@intel.com>
++  e0300-devel Mailing List <e0300-devel@lists.sourceforge.net>
++  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
++
++*******************************************************************************/
++
++/* PTP 1588 Hardware Clock (PHC)
++ * Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb)
++ * Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com>
++ */
++#include <linux/version.h>
++#include <linux/export.h>
++#include <linux/kernel.h>
++
++#include "ftgmac030.h"
++
++
++/**
++ * ftgmac030_phc_adjfreq - adjust the frequency of the hardware clock
++ * @ptp: ptp clock structure
++ * @delta: Desired frequency change in parts per billion
++ *
++ * Adjust the frequency of the PHC cycle counter by the indicated delta from
++ * the base frequency.
++ **/
++static int ftgmac030_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
++{
++	struct ftgmac030 *priv = container_of(ptp, struct ftgmac030,
++						     ptp_clock_info);
++	bool neg_adj = false;
++	u64 adjustment, fract;
++	u32 incns, i;
++	s32 incnns, adjnns;
++
++	if (delta < 0) {
++		neg_adj = true;
++		delta = -delta;
++	}
++
++	if (delta > ptp->max_adj)
++		return -EINVAL;
++
++	netdev_info(priv->netdev, "adjfreq: %s%d ppb\n", neg_adj?"-":"+", delta);
++
++	/* Get the increment value per period */
++	incns = ioread32(priv->base + FTGMAC030_REG_PTP_NS_PERIOD);
++	incnns = ioread32(priv->base + FTGMAC030_REG_PTP_NNS_PERIOD);
++	/*
++	 * If delta = 2 ppb(ns/s) means there is a different 2ns 
++	 * for each second. So we need to devide this 2ns evenly
++	 * into each period. Let's say phc_clock = 50 MHz.
++	 *
++	 * So, adjustment = 2ns / 50 MHz.
++	 * 
++	 * because 50 MHz = 1,000,000,000ns / 20ns.
++	 *
++	 * Then, we get:
++	 * 	adjustment = 2ns / (1,000,000,000ns / 20ns).
++	 *		   = (2ns * 20ns) / 1,000,000,000ns
++	 *
++	 * And finally we must adjust the incvalue to
++	 *
++	 *     incvalue = incvalue +(-) adjustment
++	 */
++	adjustment = incns;
++	adjustment *= delta;
++	adjustment = div_u64_rem(adjustment, 1000000000, (u32 *) &fract);
++	/*
++	 * fraction must be converted into binary format.
++	 * example:  0.5  -> 0x80000000
++	 *	     0.25 -> 0x40000000
++	 */
++	adjnns = 0;
++	if (fract) {
++		for (i=28; i>=0; i-=4) {
++			int tmp;
++
++			fract *= 16;
++			tmp = div_u64(fract, 1000000000);
++			adjnns = adjnns + (tmp << i);
++			tmp = div_u64_rem(fract, 1000000000, (u32 *) &fract);
++			if (!fract)
++				break;
++		}
++
++	}
++
++	if (neg_adj) {
++		if (incnns - adjnns < 0) { /* case 40.5 - 1.8 = 38.7 */
++			incns = incns - adjustment - 1;
++		} else { /* case 40.8 - 1.5 = 39.3 */
++			incns = incns - adjustment;
++		}
++		incnns = incnns - adjnns;
++	} else {
++		if ((u64)incnns + (u64)adjnns > 0xFFFFFFFFLL) { /* case 40.5 + 1.8 = 42.3 */
++			incns = incns + adjustment + 1;
++		} else { /* case 40.3 + 1.5 = 41.8 */
++			incns = incns + adjustment;
++		}
++		incnns = incnns + adjnns;
++
++	} 
++
++	netdev_info(priv->netdev, "adjfreq: ns_period %d nns_period 0x%08x\n", incns, incnns);
++	iowrite32(incns, priv->base + FTGMAC030_REG_PTP_NS_PERIOD);
++	iowrite32(incnns, priv->base + FTGMAC030_REG_PTP_NNS_PERIOD);
++	return 0;
++}
++
++/**
++ * ftgmac030_phc_adjtime - Shift the time of the hardware clock
++ * @ptp: ptp clock structure
++ * @delta: Desired change in nanoseconds
++ *
++ * Adjust the timer by resetting the timecounter structure.
++ **/
++static int ftgmac030_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
++{
++	struct ftgmac030 *priv = container_of(ptp, struct ftgmac030,
++						     ptp_clock_info);
++	unsigned long flags;
++	struct timespec ts;
++	s64 now;
++
++	spin_lock_irqsave(&priv->systim_lock, flags);
++
++	ts.tv_sec = ioread32(priv->base + FTGMAC030_REG_PTP_TM_SEC);
++	ts.tv_nsec = ioread32(priv->base + FTGMAC030_REG_PTP_TM_NSEC);
++
++	spin_unlock_irqrestore(&priv->systim_lock, flags);
++
++	now = timespec_to_ns(&ts);
++	now += delta;
++
++	ts = ns_to_timespec(now);
++	spin_lock_irqsave(&priv->systim_lock, flags);
++	iowrite32(ts.tv_sec, priv->base + FTGMAC030_REG_PTP_TM_SEC);
++	iowrite32(ts.tv_nsec, priv->base + FTGMAC030_REG_PTP_TM_NSEC);
++	spin_unlock_irqrestore(&priv->systim_lock, flags);
++
++	return 0;
++}
++
++/**
++ * ftgmac030_phc_gettime - Reads the current time from the hardware clock
++ * @ptp: ptp clock structure
++ * @ts: timespec structure to hold the current time value
++ *
++ * Read the timecounter and return the correct value in ns after converting
++ * it into a struct timespec.
++ **/
++static int ftgmac030_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
++{
++	struct ftgmac030 *priv = container_of(ptp, struct ftgmac030,
++						     ptp_clock_info);
++	unsigned long flags;
++
++	spin_lock_irqsave(&priv->systim_lock, flags);
++	ts->tv_sec = ioread32(priv->base + FTGMAC030_REG_PTP_TM_SEC);
++	ts->tv_nsec = ioread32(priv->base + FTGMAC030_REG_PTP_TM_NSEC);
++	spin_unlock_irqrestore(&priv->systim_lock, flags);
++
++	return 0;
++}
++
++/**
++ * ftgmac030_phc_settime - Set the current time on the hardware clock
++ * @ptp: ptp clock structure
++ * @ts: timespec containing the new time for the cycle counter
++ *
++ * Reset the timecounter to use a new base value instead of the kernel
++ * wall timer value.
++ **/
++static int ftgmac030_phc_settime(struct ptp_clock_info *ptp,
++			      const struct timespec *ts)
++{
++	struct ftgmac030 *priv = container_of(ptp, struct ftgmac030,
++						     ptp_clock_info);
++	unsigned long flags;
++
++	/* reset the timecounter */
++	spin_lock_irqsave(&priv->systim_lock, flags);
++	iowrite32(ts->tv_sec, priv->base + FTGMAC030_REG_PTP_TM_SEC);
++	iowrite32(ts->tv_nsec, priv->base + FTGMAC030_REG_PTP_TM_NSEC);
++	spin_unlock_irqrestore(&priv->systim_lock, flags);
++
++	return 0;
++}
++
++/**
++ * ftgmac030_phc_enable - enable or disable an ancillary feature
++ * @ptp: ptp clock structure
++ * @request: Desired resource to enable or disable
++ * @on: Caller passes one to enable or zero to disable
++ *
++ * Enable (or disable) ancillary features of the PHC subsystem.
++ * Currently, no ancillary features are supported.
++ **/
++static int ftgmac030_phc_enable(struct ptp_clock_info __always_unused *ptp,
++			     struct ptp_clock_request __always_unused *request,
++			     int __always_unused on)
++{
++	return -EOPNOTSUPP;
++}
++
++static void ftgmac030_systim_overflow_work(struct work_struct *work)
++{
++	struct ftgmac030 *priv = container_of(work, struct ftgmac030,
++						     systim_overflow_work.work);
++	struct timespec ts;
++
++	priv->ptp_clock_info.gettime(&priv->ptp_clock_info, &ts);
++
++	netdev_dbg(priv->netdev, "SYSTIM overflow check at %ld.%09lu\n", 
++		   ts.tv_sec, ts.tv_nsec);
++
++	schedule_delayed_work(&priv->systim_overflow_work,
++			      FTGMAC030_SYSTIM_OVERFLOW_PERIOD);
++}
++
++static const struct ptp_clock_info ftgmac030_ptp_clock_info = {
++	.owner		= THIS_MODULE,
++	.n_alarm	= 0,
++	.n_ext_ts	= 0,
++	.n_per_out	= 0,
++	.pps		= 0,
++	.adjfreq	= ftgmac030_phc_adjfreq,
++	.adjtime	= ftgmac030_phc_adjtime,
++	.gettime	= ftgmac030_phc_gettime,
++	.settime	= ftgmac030_phc_settime,
++	.enable		= ftgmac030_phc_enable,
++};
++
++/**
++ * ftgmac030_ptp_init - initialize PTP for devices which support it
++ * @adapter: board private structure
++ *
++ * This function performs the required steps for enabling PTP support.
++ * If PTP support has already been loaded it simply calls the cyclecounter
++ * init routine and exits.
++ **/
++void ftgmac030_ptp_init(struct ftgmac030 *adapter)
++{
++	u32 incns;
++
++	adapter->ptp_clock_info = ftgmac030_ptp_clock_info;
++
++	snprintf(adapter->ptp_clock_info.name,
++		 sizeof(adapter->ptp_clock_info.name), "%pm",
++		 adapter->netdev->perm_addr);
++
++	/* Get the increment value per period */
++	incns = ioread32(adapter->base + FTGMAC030_REG_PTP_NS_PERIOD);
++
++	/* Prevent from adjust the increment ns value per
++	 * period to less than 1.
++	 * If ptp_clock freq is 25 MHz, period is 40 ns,
++	 * then max adjustment is 39 ns.
++	 * Or in freq is 39 ns * 25MHz = 975 MHz
++	 */
++	adapter->ptp_clock_info.max_adj = (incns - 1) *
++					   div_u64(1000000000, incns);
++
++	INIT_DELAYED_WORK(&adapter->systim_overflow_work,
++			  ftgmac030_systim_overflow_work);
++
++	schedule_delayed_work(&adapter->systim_overflow_work,
++			      FTGMAC030_SYSTIM_OVERFLOW_PERIOD);
++
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0)
++	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info);
++#else
++	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
++						adapter->dev);
++#endif
++	if (IS_ERR(adapter->ptp_clock)) {
++		adapter->ptp_clock = NULL;
++		netdev_err(adapter->netdev, "ptp_clock_register failed\n");
++	} else {
++		netdev_info(adapter->netdev, "registered PHC clock\n");
++		netdev_info(adapter->netdev, "period %dns max_adj %d\n",
++					      incns,
++					      adapter->ptp_clock_info.max_adj);
++	}
++}
++
++/**
++ * ftgmac030_ptp_remove - disable PTP device and stop the overflow check
++ * @adapter: board private structure
++ *
++ * Stop the PTP support, and cancel the delayed work.
++ **/
++void ftgmac030_ptp_remove(struct ftgmac030 *adapter)
++{
++	cancel_delayed_work_sync(&adapter->systim_overflow_work);
++
++	if (adapter->ptp_clock) {
++		ptp_clock_unregister(adapter->ptp_clock);
++		adapter->ptp_clock = NULL;
++		netdev_info(adapter->netdev, "removed PHC\n");
++	}
++}
+diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
+index 0856e1b7..19d1c1d0 100644
+--- a/drivers/net/phy/icplus.c
++++ b/drivers/net/phy/icplus.c
+@@ -41,13 +41,84 @@ MODULE_LICENSE("GPL");
+ #define IP1001_APS_ON			11	/* IP1001 APS Mode  bit */
+ #define IP101A_G_APS_ON			2	/* IP101A/G APS Mode bit */
+ 
++static int ip175d_config_init(struct phy_device *phydev)
++{
++	int err, i;
++	static int full_reset_175d = 0;
++	if (full_reset_175d == 0) {
++
++        printk("ip175d_config_init\n");
++        /* master reset */
++        err = mdiobus_write(phydev->bus, 20, 2, 0x175D);
++        if (err < 0)
++            return err;
++
++        /* data sheet specifies reset period is 2 msec */
++        mdelay(2);
++
++        /*make sure it is well after reset*/
++        mdiobus_read(phydev->bus, 20,2);       
++
++        /* Set MII0 speed 100 and duplex FULL (in mac mode) */
++        err = mdiobus_read(phydev->bus, 20,4);
++        err |= (0x1 << 13 | 0x1 << 15);
++
++        err = mdiobus_write(phydev->bus, 20,4, err);
++        if (err != 0)
++            return err; 
++
++        /* reset switch ports */
++        for (i = 0; i < 5; i++) {
++        	err = mdiobus_write(phydev->bus, i,
++        			    MII_BMCR, BMCR_RESET);
++        	if (err < 0)
++        		return err;
++        }
++
++        for (i = 0; i < 5; i++)
++        	err = mdiobus_read(phydev->bus, i, MII_BMCR);
++
++        mdelay(2);
++
++        /* add to port 0~3 and port 4 isolation for IP175D */
++        err = mdiobus_write(phydev->bus, 23, 0, 0x2f2f);
++        if (err < 0)
++        	return err;
++        err = mdiobus_write(phydev->bus, 23, 1, 0x2f2f);
++        if (err < 0)
++        	return err;
++        err = mdiobus_write(phydev->bus, 23, 2, 0x3f30);
++        if (err < 0)
++        	return err;
++
++        full_reset_175d = 1;
++	}
++
++	if (phydev->addr != 4) {
++		phydev->state = PHY_RUNNING;
++		phydev->speed = SPEED_100;
++		phydev->duplex = DUPLEX_FULL;
++		phydev->link = 1;
++		netif_carrier_on(phydev->attached_dev);
++	}
++
++	return 0;
++}
++
+ static int ip175c_config_init(struct phy_device *phydev)
+ {
+ 	int err, i;
+ 	static int full_reset_performed = 0;
+ 
+-	if (full_reset_performed == 0) {
+-
++    /*read 20.0 to judge if 175D*/
++    err = mdiobus_read(phydev->bus, 20, 0);
++    if(err == 0x175D)
++    {
++        return ip175d_config_init(phydev);
++    }
++        
++	if (full_reset_performed == 0) {   
++            
+ 		/* master reset */
+ 		err = mdiobus_write(phydev->bus, 30, 0, 0x175c);
+ 		if (err < 0)
+@@ -76,7 +147,18 @@ static int ip175c_config_init(struct phy_device *phydev)
+ 			if (err < 0)
+ 				return err;
+ 		}
+-
++        /* Gavin add to port 0~3 and port 4 isolation for IP175D */
++#ifdef CONFIG_FTGMAC100_DRIVER_1
++		err = mdiobus_write(phydev->bus, 23, 0, 0x2f2f);
++		if (err < 0)
++			return err;
++		err = mdiobus_write(phydev->bus, 23, 1, 0x2f2f);
++		if (err < 0)
++			return err;
++		err = mdiobus_write(phydev->bus, 23, 2, 0x3f30);
++		if (err < 0)
++			return err;
++#endif
+ 		for (i = 0; i < 5; i++)
+ 			err = mdiobus_read(phydev->bus, i, MII_BMCR);
+ 
+@@ -154,25 +236,34 @@ static int ip1001_config_init(struct phy_device *phydev)
+ static int ip101a_g_config_init(struct phy_device *phydev)
+ {
+ 	int c;
+-
++#if 0
+ 	c = ip1xx_reset(phydev);
+ 	if (c < 0)
+ 		return c;
+-
++#else
+ 	/* Enable Auto Power Saving mode */
+ 	c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
+ 	c |= IP101A_G_APS_ON;
+-	return c;
++    if (c < 0)
++	    return c;
++#endif				
++	return 0;
+ }
+ 
+ static int ip175c_read_status(struct phy_device *phydev)
+ {
+ 	if (phydev->addr == 4) /* WAN port */
+ 		genphy_read_status(phydev);
+-	else
++	else {
+ 		/* Don't need to read status for switch ports */
+ 		phydev->irq = PHY_IGNORE_INTERRUPT;
+ 
++		phydev->state = PHY_RUNNING;
++		phydev->speed = SPEED_100;
++		phydev->duplex = DUPLEX_FULL;
++		phydev->link = 1;
++		netif_carrier_on(phydev->attached_dev);
++    }
+ 	return 0;
+ }
+ 
+@@ -232,14 +323,24 @@ static int __init icplus_init(void)
+ 	int ret = 0;
+ 
+ 	ret = phy_driver_register(&ip1001_driver);
+-	if (ret < 0)
+-		return -ENODEV;
++	if (ret)
++		goto err1;
+ 
+ 	ret = phy_driver_register(&ip101a_g_driver);
+-	if (ret < 0)
+-		return -ENODEV;
++	if (ret)
++		goto err2;
++
++	ret = phy_driver_register(&ip175c_driver);
++	if (ret)
++		goto err3;
++	return 0;
+ 
+-	return phy_driver_register(&ip175c_driver);
++err3:
++	phy_driver_unregister (&ip101a_g_driver);
++err2:
++	phy_driver_unregister (&ip1001_driver);
++err1:
++	return ret;	
+ }
+ 
+ static void __exit icplus_exit(void)
+diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
+index 590f902d..c3d7db18 100644
+--- a/drivers/net/phy/micrel.c
++++ b/drivers/net/phy/micrel.c
+@@ -1,251 +1,361 @@
+-/*
+- * drivers/net/phy/micrel.c
+- *
+- * Driver for Micrel PHYs
+- *
+- * Author: David J. Choi
+- *
+- * Copyright (c) 2010 Micrel, Inc.
+- *
+- * 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.
+- *
+- * Support : ksz9021 1000/100/10 phy from Micrel
+- *		ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/phy.h>
+-#include <linux/micrel_phy.h>
+-
+-/* general Interrupt control/status reg in vendor specific block. */
+-#define MII_KSZPHY_INTCS			0x1B
+-#define	KSZPHY_INTCS_JABBER			(1 << 15)
+-#define	KSZPHY_INTCS_RECEIVE_ERR		(1 << 14)
+-#define	KSZPHY_INTCS_PAGE_RECEIVE		(1 << 13)
+-#define	KSZPHY_INTCS_PARELLEL			(1 << 12)
+-#define	KSZPHY_INTCS_LINK_PARTNER_ACK		(1 << 11)
+-#define	KSZPHY_INTCS_LINK_DOWN			(1 << 10)
+-#define	KSZPHY_INTCS_REMOTE_FAULT		(1 << 9)
+-#define	KSZPHY_INTCS_LINK_UP			(1 << 8)
+-#define	KSZPHY_INTCS_ALL			(KSZPHY_INTCS_LINK_UP |\
+-						KSZPHY_INTCS_LINK_DOWN)
+-
+-/* general PHY control reg in vendor specific block. */
+-#define	MII_KSZPHY_CTRL			0x1F
+-/* bitmap of PHY register to set interrupt mode */
+-#define KSZPHY_CTRL_INT_ACTIVE_HIGH		(1 << 9)
+-#define KSZ9021_CTRL_INT_ACTIVE_HIGH		(1 << 14)
+-#define KS8737_CTRL_INT_ACTIVE_HIGH		(1 << 14)
+-#define KSZ8051_RMII_50MHZ_CLK			(1 << 7)
+-
+-static int kszphy_ack_interrupt(struct phy_device *phydev)
+-{
+-	/* bit[7..0] int status, which is a read and clear register. */
+-	int rc;
+-
+-	rc = phy_read(phydev, MII_KSZPHY_INTCS);
+-
+-	return (rc < 0) ? rc : 0;
+-}
+-
+-static int kszphy_set_interrupt(struct phy_device *phydev)
+-{
+-	int temp;
+-	temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ?
+-		KSZPHY_INTCS_ALL : 0;
+-	return phy_write(phydev, MII_KSZPHY_INTCS, temp);
+-}
+-
+-static int kszphy_config_intr(struct phy_device *phydev)
+-{
+-	int temp, rc;
+-
+-	/* set the interrupt pin active low */
+-	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+-	temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
+-	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+-	rc = kszphy_set_interrupt(phydev);
+-	return rc < 0 ? rc : 0;
+-}
+-
+-static int ksz9021_config_intr(struct phy_device *phydev)
+-{
+-	int temp, rc;
+-
+-	/* set the interrupt pin active low */
+-	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+-	temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
+-	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+-	rc = kszphy_set_interrupt(phydev);
+-	return rc < 0 ? rc : 0;
+-}
+-
+-static int ks8737_config_intr(struct phy_device *phydev)
+-{
+-	int temp, rc;
+-
+-	/* set the interrupt pin active low */
+-	temp = phy_read(phydev, MII_KSZPHY_CTRL);
+-	temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
+-	phy_write(phydev, MII_KSZPHY_CTRL, temp);
+-	rc = kszphy_set_interrupt(phydev);
+-	return rc < 0 ? rc : 0;
+-}
+-
+-static int kszphy_config_init(struct phy_device *phydev)
+-{
+-	return 0;
+-}
+-
+-static int ks8051_config_init(struct phy_device *phydev)
+-{
+-	int regval;
+-
+-	if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
+-		regval = phy_read(phydev, MII_KSZPHY_CTRL);
+-		regval |= KSZ8051_RMII_50MHZ_CLK;
+-		phy_write(phydev, MII_KSZPHY_CTRL, regval);
+-	}
+-
+-	return 0;
+-}
+-
+-static struct phy_driver ks8737_driver = {
+-	.phy_id		= PHY_ID_KS8737,
+-	.phy_id_mask	= 0x00fffff0,
+-	.name		= "Micrel KS8737",
+-	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+-	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+-	.config_init	= kszphy_config_init,
+-	.config_aneg	= genphy_config_aneg,
+-	.read_status	= genphy_read_status,
+-	.ack_interrupt	= kszphy_ack_interrupt,
+-	.config_intr	= ks8737_config_intr,
+-	.driver		= { .owner = THIS_MODULE,},
+-};
+-
+-static struct phy_driver ks8041_driver = {
+-	.phy_id		= PHY_ID_KS8041,
+-	.phy_id_mask	= 0x00fffff0,
+-	.name		= "Micrel KS8041",
+-	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+-				| SUPPORTED_Asym_Pause),
+-	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+-	.config_init	= kszphy_config_init,
+-	.config_aneg	= genphy_config_aneg,
+-	.read_status	= genphy_read_status,
+-	.ack_interrupt	= kszphy_ack_interrupt,
+-	.config_intr	= kszphy_config_intr,
+-	.driver		= { .owner = THIS_MODULE,},
+-};
+-
+-static struct phy_driver ks8051_driver = {
+-	.phy_id		= PHY_ID_KS8051,
+-	.phy_id_mask	= 0x00fffff0,
+-	.name		= "Micrel KS8051",
+-	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
+-				| SUPPORTED_Asym_Pause),
+-	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+-	.config_init	= ks8051_config_init,
+-	.config_aneg	= genphy_config_aneg,
+-	.read_status	= genphy_read_status,
+-	.ack_interrupt	= kszphy_ack_interrupt,
+-	.config_intr	= kszphy_config_intr,
+-	.driver		= { .owner = THIS_MODULE,},
+-};
+-
+-static struct phy_driver ks8001_driver = {
+-	.phy_id		= PHY_ID_KS8001,
+-	.name		= "Micrel KS8001 or KS8721",
+-	.phy_id_mask	= 0x00fffff0,
+-	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+-	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+-	.config_init	= kszphy_config_init,
+-	.config_aneg	= genphy_config_aneg,
+-	.read_status	= genphy_read_status,
+-	.ack_interrupt	= kszphy_ack_interrupt,
+-	.config_intr	= kszphy_config_intr,
+-	.driver		= { .owner = THIS_MODULE,},
+-};
+-
+-static struct phy_driver ksz9021_driver = {
+-	.phy_id		= PHY_ID_KSZ9021,
+-	.phy_id_mask	= 0x000fff10,
+-	.name		= "Micrel KSZ9021 Gigabit PHY",
+-	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause
+-				| SUPPORTED_Asym_Pause),
+-	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+-	.config_init	= kszphy_config_init,
+-	.config_aneg	= genphy_config_aneg,
+-	.read_status	= genphy_read_status,
+-	.ack_interrupt	= kszphy_ack_interrupt,
+-	.config_intr	= ksz9021_config_intr,
+-	.driver		= { .owner = THIS_MODULE, },
+-};
+-
+-static int __init ksphy_init(void)
+-{
+-	int ret;
+-
+-	ret = phy_driver_register(&ks8001_driver);
+-	if (ret)
+-		goto err1;
+-
+-	ret = phy_driver_register(&ksz9021_driver);
+-	if (ret)
+-		goto err2;
+-
+-	ret = phy_driver_register(&ks8737_driver);
+-	if (ret)
+-		goto err3;
+-	ret = phy_driver_register(&ks8041_driver);
+-	if (ret)
+-		goto err4;
+-	ret = phy_driver_register(&ks8051_driver);
+-	if (ret)
+-		goto err5;
+-
+-	return 0;
+-
+-err5:
+-	phy_driver_unregister(&ks8041_driver);
+-err4:
+-	phy_driver_unregister(&ks8737_driver);
+-err3:
+-	phy_driver_unregister(&ksz9021_driver);
+-err2:
+-	phy_driver_unregister(&ks8001_driver);
+-err1:
+-	return ret;
+-}
+-
+-static void __exit ksphy_exit(void)
+-{
+-	phy_driver_unregister(&ks8001_driver);
+-	phy_driver_unregister(&ks8737_driver);
+-	phy_driver_unregister(&ksz9021_driver);
+-	phy_driver_unregister(&ks8041_driver);
+-	phy_driver_unregister(&ks8051_driver);
+-}
+-
+-module_init(ksphy_init);
+-module_exit(ksphy_exit);
+-
+-MODULE_DESCRIPTION("Micrel PHY driver");
+-MODULE_AUTHOR("David J. Choi");
+-MODULE_LICENSE("GPL");
+-
+-static struct mdio_device_id __maybe_unused micrel_tbl[] = {
+-	{ PHY_ID_KSZ9021, 0x000fff10 },
+-	{ PHY_ID_KS8001, 0x00fffff0 },
+-	{ PHY_ID_KS8737, 0x00fffff0 },
+-	{ PHY_ID_KS8041, 0x00fffff0 },
+-	{ PHY_ID_KS8051, 0x00fffff0 },
+-	{ }
+-};
+-
+-MODULE_DEVICE_TABLE(mdio, micrel_tbl);
++/*
++ * drivers/net/phy/micrel.c
++ *
++ * Driver for Micrel PHYs
++ *
++ * Author: David J. Choi
++ *
++ * Copyright (c) 2010-2013 Micrel, Inc.
++ *
++ * 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.
++ *
++ * Support : Micrel Phys:
++ *		Giga phys: ksz9021, ksz9031
++ *		100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041
++ *			   ksz8021, ksz8031, ksz8051,
++ *			   ksz8081, ksz8091,
++ *			   ksz8061,
++ *		Switch : ksz8873, ksz886x
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/phy.h>
++#include <linux/micrel_phy.h>
++
++/* Operation Mode Strap Override */
++#define MII_KSZPHY_OMSO				0x16
++#define KSZPHY_OMSO_B_CAST_OFF			(1 << 9)
++#define KSZPHY_OMSO_RMII_OVERRIDE		(1 << 1)
++#define KSZPHY_OMSO_MII_OVERRIDE		(1 << 0)
++
++/* general Interrupt control/status reg in vendor specific block. */
++#define MII_KSZPHY_INTCS			0x1B
++#define	KSZPHY_INTCS_JABBER			(1 << 15)
++#define	KSZPHY_INTCS_RECEIVE_ERR		(1 << 14)
++#define	KSZPHY_INTCS_PAGE_RECEIVE		(1 << 13)
++#define	KSZPHY_INTCS_PARELLEL			(1 << 12)
++#define	KSZPHY_INTCS_LINK_PARTNER_ACK		(1 << 11)
++#define	KSZPHY_INTCS_LINK_DOWN			(1 << 10)
++#define	KSZPHY_INTCS_REMOTE_FAULT		(1 << 9)
++#define	KSZPHY_INTCS_LINK_UP			(1 << 8)
++#define	KSZPHY_INTCS_ALL			(KSZPHY_INTCS_LINK_UP |\
++						KSZPHY_INTCS_LINK_DOWN)
++
++/* general PHY control reg in vendor specific block. */
++#define	MII_KSZPHY_CTRL			0x1F
++/* bitmap of PHY register to set interrupt mode */
++#define KSZPHY_CTRL_INT_ACTIVE_HIGH		(1 << 9)
++#define KSZ9021_CTRL_INT_ACTIVE_HIGH		(1 << 14)
++#define KS8737_CTRL_INT_ACTIVE_HIGH		(1 << 14)
++#define KSZ8051_RMII_50MHZ_CLK			(1 << 7)
++
++static int ksz_config_flags(struct phy_device *phydev)
++{
++	int regval;
++
++	if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
++		regval = phy_read(phydev, MII_KSZPHY_CTRL);
++		regval |= KSZ8051_RMII_50MHZ_CLK;
++		return phy_write(phydev, MII_KSZPHY_CTRL, regval);
++	}
++	return 0;
++}
++
++static int kszphy_ack_interrupt(struct phy_device *phydev)
++{
++	/* bit[7..0] int status, which is a read and clear register. */
++	int rc;
++
++	rc = phy_read(phydev, MII_KSZPHY_INTCS);
++
++	return (rc < 0) ? rc : 0;
++}
++
++static int kszphy_set_interrupt(struct phy_device *phydev)
++{
++	int temp;
++	temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ?
++		KSZPHY_INTCS_ALL : 0;
++	return phy_write(phydev, MII_KSZPHY_INTCS, temp);
++}
++
++static int kszphy_config_intr(struct phy_device *phydev)
++{
++	int temp, rc;
++
++	/* set the interrupt pin active low */
++	temp = phy_read(phydev, MII_KSZPHY_CTRL);
++	temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH;
++	phy_write(phydev, MII_KSZPHY_CTRL, temp);
++	rc = kszphy_set_interrupt(phydev);
++	return rc < 0 ? rc : 0;
++}
++
++static int ksz9021_config_intr(struct phy_device *phydev)
++{
++	int temp, rc;
++
++	/* set the interrupt pin active low */
++	temp = phy_read(phydev, MII_KSZPHY_CTRL);
++	temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH;
++	phy_write(phydev, MII_KSZPHY_CTRL, temp);
++	rc = kszphy_set_interrupt(phydev);
++	return rc < 0 ? rc : 0;
++}
++
++static int ks8737_config_intr(struct phy_device *phydev)
++{
++	int temp, rc;
++
++	/* set the interrupt pin active low */
++	temp = phy_read(phydev, MII_KSZPHY_CTRL);
++	temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH;
++	phy_write(phydev, MII_KSZPHY_CTRL, temp);
++	rc = kszphy_set_interrupt(phydev);
++	return rc < 0 ? rc : 0;
++}
++
++static int kszphy_config_init(struct phy_device *phydev)
++{
++	return 0;
++}
++
++static int ksz8021_config_init(struct phy_device *phydev)
++{
++	int rc;
++	const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
++	phy_write(phydev, MII_KSZPHY_OMSO, val);
++	rc = ksz_config_flags(phydev);
++	return rc < 0 ? rc : 0;
++}
++
++static int ks8051_config_init(struct phy_device *phydev)
++{
++	int rc;
++
++	rc = ksz_config_flags(phydev);
++	return rc < 0 ? rc : 0;
++}
++
++#define KSZ8873MLL_GLOBAL_CONTROL_4	0x06
++#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX	(1 << 6)
++#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED	(1 << 4)
++int ksz8873mll_read_status(struct phy_device *phydev)
++{
++	int regval;
++
++	/* dummy read */
++	regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
++
++	regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
++
++	if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX)
++		phydev->duplex = DUPLEX_HALF;
++	else
++		phydev->duplex = DUPLEX_FULL;
++
++	if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_SPEED)
++		phydev->speed = SPEED_10;
++	else
++		phydev->speed = SPEED_100;
++
++	phydev->link = 1;
++	phydev->pause = phydev->asym_pause = 0;
++
++	return 0;
++}
++
++static int ksz8873mll_config_aneg(struct phy_device *phydev)
++{
++	return 0;
++}
++
++static struct phy_driver ksphy_driver[] = {
++{
++	.phy_id		= PHY_ID_KS8737,
++	.phy_id_mask	= 0x00fffff0,
++	.name		= "Micrel KS8737",
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= ks8737_config_intr,
++	.driver		= { .owner = THIS_MODULE,},
++}, {
++	.phy_id		= PHY_ID_KSZ8021,
++	.phy_id_mask	= 0x00ffffff,
++	.name		= "Micrel KSZ8021 or KSZ8031",
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
++			   SUPPORTED_Asym_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= ksz8021_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= kszphy_config_intr,
++	.driver		= { .owner = THIS_MODULE,},
++#if 0
++}, {
++	.phy_id		= PHY_ID_KSZ8031,
++	.phy_id_mask	= 0x00ffffff,
++	.name		= "Micrel KSZ8031",
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
++			   SUPPORTED_Asym_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= ksz8021_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= kszphy_config_intr,
++	.driver		= { .owner = THIS_MODULE,},
++#endif	
++}, {
++	.phy_id		= PHY_ID_KSZ8041,
++	.phy_id_mask	= 0x00fffff0,
++	.name		= "Micrel KSZ8041",
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
++				| SUPPORTED_Asym_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= kszphy_config_intr,
++	.driver		= { .owner = THIS_MODULE,},
++}, {
++	.phy_id		= PHY_ID_KSZ8051,
++	.phy_id_mask	= 0x00fffff0,
++	.name		= "Micrel KSZ8051",
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause
++				| SUPPORTED_Asym_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= ks8051_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= kszphy_config_intr,
++	.driver		= { .owner = THIS_MODULE,},
++}, {
++	.phy_id		= PHY_ID_KSZ8001,
++	.name		= "Micrel KSZ8001 or KS8721",
++	.phy_id_mask	= 0x00ffffff,
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= kszphy_config_intr,
++	.driver		= { .owner = THIS_MODULE,},
++}, {
++	.phy_id		= PHY_ID_KSZ8081,
++	.name		= "Micrel KSZ8081 or KSZ8091",
++	.phy_id_mask	= 0x00fffff0,
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= kszphy_config_intr,
++	.driver		= { .owner = THIS_MODULE,},
++}, {
++	.phy_id		= PHY_ID_KSZ8061,
++	.name		= "Micrel KSZ8061",
++	.phy_id_mask	= 0x00fffff0,
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= kszphy_config_intr,
++	.driver		= { .owner = THIS_MODULE,},
++}, {
++	.phy_id		= PHY_ID_KSZ9021,
++	.phy_id_mask	= 0x000ffffe,
++	.name		= "Micrel KSZ9021 Gigabit PHY",
++	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= ksz9021_config_intr,
++	.driver		= { .owner = THIS_MODULE, },
++}, {
++	.phy_id		= PHY_ID_KSZ9031,
++	.phy_id_mask	= 0x00fffff0,
++	.name		= "Micrel KSZ9031 Gigabit PHY",
++	.features	= (PHY_GBIT_FEATURES | SUPPORTED_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.ack_interrupt	= kszphy_ack_interrupt,
++	.config_intr	= ksz9021_config_intr,
++	.driver		= { .owner = THIS_MODULE, },
++}, {
++	.phy_id		= PHY_ID_KSZ8873MLL,
++	.phy_id_mask	= 0x00fffff0,
++	.name		= "Micrel KSZ8873MLL Switch",
++	.features	= (SUPPORTED_Pause | SUPPORTED_Asym_Pause),
++	.flags		= PHY_HAS_MAGICANEG,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= ksz8873mll_config_aneg,
++	.read_status	= ksz8873mll_read_status,
++	.driver		= { .owner = THIS_MODULE, },
++}, {
++	.phy_id		= PHY_ID_KSZ886X,
++	.phy_id_mask	= 0x00fffff0,
++	.name		= "Micrel KSZ886X Switch",
++	.features	= (PHY_BASIC_FEATURES | SUPPORTED_Pause),
++	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
++	.config_init	= kszphy_config_init,
++	.config_aneg	= genphy_config_aneg,
++	.read_status	= genphy_read_status,
++	.driver		= { .owner = THIS_MODULE, },
++} };
++
++static int __init ksphy_init(void)
++{
++	//return phy_drivers_register(ksphy_driver, ARRAY_SIZE(ksphy_driver));
++	return phy_driver_register(ksphy_driver);
++}
++
++static void __exit ksphy_exit(void)
++{
++	//phy_drivers_unregister(ksphy_driver, ARRAY_SIZE(ksphy_driver));
++	phy_driver_unregister(ksphy_driver);
++}
++
++module_init(ksphy_init);
++module_exit(ksphy_exit);
++
++MODULE_DESCRIPTION("Micrel PHY driver");
++MODULE_AUTHOR("David J. Choi");
++MODULE_LICENSE("GPL");
++
++static struct mdio_device_id __maybe_unused micrel_tbl[] = {
++	{ PHY_ID_KSZ9021, 0x000ffffe },
++	{ PHY_ID_KSZ9031, 0x00fffff0 },
++	{ PHY_ID_KSZ8001, 0x00ffffff },
++	{ PHY_ID_KS8737, 0x00fffff0 },
++	{ PHY_ID_KSZ8021, 0x00ffffff },
++	//{ PHY_ID_KSZ8031, 0x00ffffff },
++	{ PHY_ID_KSZ8041, 0x00fffff0 },
++	{ PHY_ID_KSZ8051, 0x00fffff0 },
++	{ PHY_ID_KSZ8061, 0x00fffff0 },
++	{ PHY_ID_KSZ8081, 0x00fffff0 },
++	{ PHY_ID_KSZ8873MLL, 0x00fffff0 },
++	{ PHY_ID_KSZ886X, 0x00fffff0 },
++	{ }
++};
++
++MODULE_DEVICE_TABLE(mdio, micrel_tbl);
+\ No newline at end of file
+diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
+index f414ffb5..cb32617d 100644
+--- a/drivers/net/phy/realtek.c
++++ b/drivers/net/phy/realtek.c
+@@ -27,6 +27,21 @@ MODULE_DESCRIPTION("Realtek PHY driver");
+ MODULE_AUTHOR("Johnson Leung");
+ MODULE_LICENSE("GPL");
+ 
++static int rtl820x_config_init(struct phy_device *phydev)
++{
++	int value;
++
++	phy_write(phydev, 31, 7);
++	
++	value = phy_read(phydev, 19);
++	value &= ~(0x3 << 4);
++	phy_write(phydev, 19, value);
++	
++	phy_write(phydev, 31, 0);
++
++	return 0;
++}
++
+ static int rtl821x_ack_interrupt(struct phy_device *phydev)
+ {
+ 	int err;
+@@ -51,8 +66,8 @@ static int rtl821x_config_intr(struct phy_device *phydev)
+ 
+ /* RTL8211B */
+ static struct phy_driver rtl821x_driver = {
+-	.phy_id		= 0x001cc912,
+-	.name		= "RTL821x Gigabit Ethernet",
++	.phy_id		= 0x001cc915,
++	.name		= "RTL8211E Gigabit Ethernet",
+ 	.phy_id_mask	= 0x001fffff,
+ 	.features	= PHY_GBIT_FEATURES,
+ 	.flags		= PHY_HAS_INTERRUPT,
+@@ -63,25 +78,53 @@ static struct phy_driver rtl821x_driver = {
+ 	.driver		= { .owner = THIS_MODULE,},
+ };
+ 
++/* RTL8201 */
++static struct phy_driver rtl820x_driver = {
++	.phy_id		= 0x001cc816,
++	.name		= "RTL8201 Ethernet",
++	.phy_id_mask	= 0x001fffff,
++	.features	= PHY_BASIC_FEATURES | SUPPORTED_Pause |
++			  SUPPORTED_Asym_Pause,
++	.flags		= PHY_HAS_INTERRUPT,
++	.config_init	= &rtl820x_config_init,
++	.config_aneg	= &genphy_config_aneg,
++	.read_status	= &genphy_read_status,
++	.suspend	= genphy_suspend,
++	.resume		= genphy_resume,
++	.driver		= { .owner = THIS_MODULE,},
++};
++
+ static int __init realtek_init(void)
+ {
+ 	int ret;
+ 
+ 	ret = phy_driver_register(&rtl821x_driver);
++	if (ret)
++		goto phy_1;
++
++	ret = phy_driver_register(&rtl820x_driver);
++	if (ret)
++		goto phy_2;
+ 
++	return 0;
++phy_2:
++	phy_driver_unregister (&rtl821x_driver);
++phy_1:		
+ 	return ret;
+ }
+ 
+ static void __exit realtek_exit(void)
+ {
+ 	phy_driver_unregister(&rtl821x_driver);
++	phy_driver_unregister(&rtl820x_driver);
+ }
+ 
+ module_init(realtek_init);
+ module_exit(realtek_exit);
+ 
+ static struct mdio_device_id __maybe_unused realtek_tbl[] = {
+-	{ 0x001cc912, 0x001fffff },
++	{ 0x001cc915, 0x001fffff },
++	{ 0x001cc816, 0x001fffff },
+ 	{ }
+ };
+ 
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 8293658e..e4fd463c 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -392,6 +392,31 @@ config SPI_DW_PCI
+ 	tristate "PCI interface driver for DW SPI core"
+ 	depends on SPI_DESIGNWARE && PCI
+ 
++config SPI_FTSPI020
++    	bool "Grain Media's SPI020 controller for SPI flash"
++    	depends on SPI_MASTER
++    	help
++	  This exposes the SPI020 controller IP of Grain Media Inc.
++
++config FTSPI020_USE_AHBDMA
++	bool "Use AHB DMA transfer"
++	depends on SPI_FTSPI020
++	help
++	  Use AHB DMA to transfer data instead of PIO
++
++config FTSPI020_USE_AXIDMA
++	bool "Use AXI DMA transfer"
++	depends on SPI_FTSPI020
++	help
++	  Use AXI DMA to transfer data instead of PIO
++
++config SPI_FTSSP010
++    bool "Grain Media's SSP010_1 controller for SPI mode"
++    default n
++    depends on SPI_MASTER && (PLATFORM_GM8139 || PLATFORM_GM8136)
++    help
++      This exposes the SSP010 controller IP of Grain Media Inc.
++	  
+ config SPI_DW_MID_DMA
+ 	bool "DMA support for DW SPI controller on Intel Moorestown platform"
+ 	depends on SPI_DW_PCI && INTEL_MID_DMAC
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index 61c3261c..ce2891d7 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -23,6 +23,7 @@ obj-$(CONFIG_SPI_DAVINCI)		+= spi-davinci.o
+ obj-$(CONFIG_SPI_DESIGNWARE)		+= spi-dw.o
+ obj-$(CONFIG_SPI_DW_MMIO)		+= spi-dw-mmio.o
+ obj-$(CONFIG_SPI_DW_PCI)		+= spi-dw-midpci.o
++obj-$(CONFIG_SPI_FTSPI020)      	+= ftspi020.o
+ spi-dw-midpci-objs			:= spi-dw-pci.o spi-dw-mid.o
+ obj-$(CONFIG_SPI_EP93XX)		+= spi-ep93xx.o
+ obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-lib.o
+@@ -58,4 +59,5 @@ obj-$(CONFIG_SPI_TLE62X0)		+= spi-tle62x0.o
+ obj-$(CONFIG_SPI_TOPCLIFF_PCH)		+= spi-topcliff-pch.o
+ obj-$(CONFIG_SPI_TXX9)			+= spi-txx9.o
+ obj-$(CONFIG_SPI_XILINX)		+= spi-xilinx.o
++obj-$(CONFIG_SPI_FTSSP010)		+= ftssp010_spi.o
+ 
+diff --git a/drivers/spi/ftspi020.c b/drivers/spi/ftspi020.c
+new file mode 100644
+index 00000000..ea00fde7
+--- /dev/null
++++ b/drivers/spi/ftspi020.c
+@@ -0,0 +1,1160 @@
++/*
++ * SPI interface for Faraday SPI020
++ *
++ * Copyright (c) 2011 BingJiun Luo <bjluo@faraday-tech.com>
++ * Copyright (c) 2009 Po-Yu Chuang <ratbert@faraday-tech.com>
++ *
++ * Copyright (c) 2006 Ben Dooks
++ * Copyright (c) 2006 Simtec Electronics
++ *
++ * 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 <linux/version.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/spi/spi.h>
++#include <mach/ftpmu010.h>
++#include <mach/platform/board.h>
++#include <mach/fmem.h>
++#include "ftspi020.h"
++#include <asm/io.h>
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
++#include <mach/hardware.h>
++#else
++#include <asm/hardware.h>
++#endif
++
++//#define CONFIG_FTSPI020_USE_AHBDMA//???
++
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
++
++#ifdef CONFIG_FTSPI020_USE_AHBDMA
++#include <mach/ftdmac020.h>
++#else
++#include <mach/ftdmac030.h>
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8210
++#ifdef CONFIG_FTSPI020_USE_AHBDMA
++#define AHBMASTER_R_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_R_DST   FTDMA020_AHBMASTER_0
++#define AHBMASTER_W_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_W_DST   FTDMA020_AHBMASTER_0
++#define SPI020_REQ  8
++#else
++#define SPI020_REQ  1
++#endif
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8287) || defined(CONFIG_PLATFORM_GM8136) || defined(CONFIG_PLATFORM_GM8220)
++#define AHBMASTER_R_SRC   FTDMA020_AHBMASTER_0
++#define AHBMASTER_R_DST   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_SRC   FTDMA020_AHBMASTER_1
++#define AHBMASTER_W_DST   FTDMA020_AHBMASTER_0
++#define SPI020_REQ  8
++#endif
++
++static void ftspi020_dma_callback(void *param);
++static unsigned int trigger_flag = 0;
++static wait_queue_head_t spi020_queue;
++#endif
++
++static int spi020_fd;
++
++/******************************************************************************
++ * SPI020 definitions
++ *****************************************************************************/
++#define	FTSPI020_REG_CMD0		0x00	/* Flash address */
++#define	FTSPI020_REG_CMD1		0x04
++#define	FTSPI020_REG_CMD2		0x08
++#define	FTSPI020_REG_CMD3		0x0c
++#define	FTSPI020_REG_CTRL		0x10	/* Control */
++#define	FTSPI020_REG_AC_TIME		0x14
++#define	FTSPI020_REG_STS		0x18	/* Status */
++#define	FTSPI020_REG_ICR		0x20	/* Interrupt Enable */
++#define	FTSPI020_REG_ISR		0x24	/* Interrupt Status */
++#define	FTSPI020_REG_READ_STS		0x28
++#define FTSPI020_REG_REVISION		0x50
++#define FTSPI020_REG_FEATURE		0x54
++#define FTSPI020_REG_DATA_PORT		0x100
++
++
++/*
++ * Control Register offset 0x10
++ */
++#define	FTSPI020_CTRL_READY_LOC_MASK	~(0x7 << 16)
++#define	FTSPI020_CTRL_READY_LOC(x)	(((x) & 0x7) << 16)
++
++#define	FTSPI020_CTRL_ABORT		(1 << 8)
++
++#define	FTSPI020_CTRL_CLK_MODE_MASK	~(1 << 4)
++#define	FTSPI020_CTRL_CLK_MODE_0	(0 << 4)
++#define	FTSPI020_CTRL_CLK_MODE_3	(1 << 4)
++
++#define	FTSPI020_CTRL_CLK_DIVIDER_MASK	~(3 << 0)
++#define	FTSPI020_CTRL_CLK_DIVIDER_2	(0 << 0)
++#define FTSPI020_CTRL_CLK_DIVIDER_4	(1 << 0)
++#define FTSPI020_CTRL_CLK_DIVIDER_6	(2 << 0)
++#define FTSPI020_CTRL_CLK_DIVIDER_8	(3 << 0)
++
++/*
++ * Status Register offset 0x18
++ */
++#define	FTSPI020_STS_RFR	(1 << 1) /* RX FIFO ready */
++#define	FTSPI020_STS_TFR	(1 << 0) /* TX FIFO ready */
++
++/*
++ * Interrupt Control Register
++ */
++#define	FTSPI020_ICR_RFTH(x)	(((x) & 0x3) << 12)	/* RX FIFO threshold interrupt */
++#define	FTSPI020_ICR_TFTH(x)	(((x) & 0x3) << 8)	/* TX FIFO threshold interrupt */
++#define	FTSPI020_ICR_INT	(1 << 1)		/* INT enable */
++#define	FTSPI020_ICR_DMA	(1 << 0)		/* DMA handshake enable */
++
++/*
++ * Interrupt Status Register
++ */
++#define	FTSPI020_ISR_CMD_CMPL	(1 << 0)	/* Command complete interrupt  */
++
++/*
++ * Feature Register
++ */
++#define FTSPI020_FEATURE_CLK_MODE(reg)		(((reg) >> 25) & 0x1)
++#define FTSPI020_FEATURE_DTR_MODE(reg)		(((reg) >> 24) & 0x1)
++#define FTSPI020_FEATURE_CMDQ_DEPTH(reg)	(((reg) >> 16) & 0xff)
++#define FTSPI020_FEATURE_RXFIFO_DEPTH(reg)	(((reg) >>  8) & 0xff)
++#define FTSPI020_FEATURE_TXFIFO_DEPTH(reg)	(((reg) >>  0) & 0xff)
++
++static int g_cmd_complete;
++
++/******************************************************************************
++ * spi_master (controller) private data
++ *****************************************************************************/
++struct ftspi020_ctrl {
++	spinlock_t		lock;
++
++	void __iomem		*base;
++	int			irq;
++	int			rxfifo_depth;
++	int			txfifo_depth;
++
++	struct spi_master	*master;
++
++	struct workqueue_struct	*workqueue;
++	struct work_struct	work;
++
++	wait_queue_head_t	waitq;
++	struct list_head	message_queue;
++
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++    struct dma_chan     *dma_chan;
++    dma_cap_mask_t      cap_mask;
++#ifdef CONFIG_FTSPI020_USE_AHBDMA
++    struct ftdmac020_dma_slave  dma_slave_config;
++#else
++    struct ftdmac030_dma_slave  dma_slave_config;
++#endif
++    dma_cookie_t        cookie;
++    dma_addr_t 		    mem_dmaaddr;
++    dma_addr_t 		    spi_dmaaddr;
++    unsigned char       *mem_dmabuf;
++    unsigned char       *sg_dmabuf;
++#endif
++};
++
++/******************************************************************************
++ * internal functions for FTSPI020
++ *****************************************************************************/
++#ifdef CONFIG_PLATFORM_GM8210
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x5C, (0x1 << 24), (0x1 << 24), (0x1 << 24), (0x1 << 24)},   /* pinMux with GPIO */
++#ifdef CONFIG_FTSPI020_USE_AXIDMA
++    {0xA4, (0x1 << 26), (0x1 << 26), (0x1 << 26), (0x1 << 26)},   /* DMA ack selection */
++#endif
++    {0xB4, (0x1 << 9), (0x1 << 9), (0x0 << 9), (0x1 << 9)},   /* AHB clock gate */
++};
++#endif
++#ifdef CONFIG_PLATFORM_GM8139
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x54, (0x3F << 26), 0, (0x15 << 26), (0x3F << 26)},   /* pinMux with NAND, don't lock */
++    {0x58, (0x3 << 0), 0, (0x1 << 0), (0x3 << 0)},   /* pinMux with NAND, don't lock */
++    {0xB4, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)},   /* AHB clock gate */
++};
++#endif
++#ifdef CONFIG_PLATFORM_GM8136
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0xB4, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)},   /* AHB clock gate */
++};
++#endif
++#ifdef CONFIG_PLATFORM_GM8287
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x5C, (0x3 << 20), (0x3 << 20), (0x0 << 26), (0x3 << 20)},   /* pinMux */
++    {0xB4, (0x1 << 9), (0x1 << 9), (0x0 << 9), (0x1 << 9)},   /* AHB clock gate */
++};
++#endif
++#ifdef CONFIG_PLATFORM_GM8220
++static pmuReg_t  pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x1A4, (0xFFFF << 14), (0xFFFF << 14), (0x5555 << 14), (0xFFFF << 14)},   /* pinMux */
++    //{0x1A4, (0xFFFF << 14), (0xFFFF << 14), (0xAAAA << 14), (0xFFFF << 14)},   /* pinMux, 4-bit mode */
++    {0x68, (0x1 << 17), (0x1 << 17), (0x0 << 17), (0x1 << 17)},   /* AHB clock gate */
++};
++#endif
++
++static pmuRegInfo_t	pmu_reg_info = {
++    "SPI020",
++    ARRAY_SIZE(pmu_reg),
++    ATTR_TYPE_NONE,
++    pmu_reg
++};
++
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++
++#define FTSPI020_DMA_BUF_SIZE	(4 * 1024)
++
++static void ftspi020_dma_enable(void __iomem * base)
++{
++	unsigned int	tmp = inl(base + FTSPI020_REG_ICR);
++
++	tmp |= FTSPI020_ICR_DMA;
++	outl(tmp, base + FTSPI020_REG_ICR);
++	printk(KERN_INFO "FTSPI020 enable DMA handshake 0x%x\n", inl(base + FTSPI020_REG_ICR));
++}
++
++static int ftspi020_dma_wait(void)
++{
++    int rc = 0;
++
++    rc = wait_event_timeout(spi020_queue, trigger_flag == 1, 15 * HZ);
++    if (rc == 0) {
++    	printk(KERN_ERR "spi020 dma queue wake up timeout signal arrived\n");
++    	return -1;
++    }
++
++    trigger_flag = 0;
++    return 0;
++}
++
++#else
++
++static void ftspi020_write_word(void __iomem * base, const void *data,
++				int wsize)
++{
++	if (data) {
++		switch (wsize) {
++		case 1:
++			outb(*(const u8 *)data, base + FTSPI020_REG_DATA_PORT);
++			break;
++
++		case 2:
++			outw(*(const u16 *)data, base + FTSPI020_REG_DATA_PORT);
++			break;
++
++		default:
++			outl(*(const u32 *)data, base + FTSPI020_REG_DATA_PORT);
++			break;
++		}
++	}
++
++}
++
++static void ftspi020_read_word(void __iomem * base, void *buf, int wsize)
++{
++	if (buf) {
++		switch (wsize) {
++		case 1:
++			*(u8 *) buf = inb(base + FTSPI020_REG_DATA_PORT);
++			break;
++
++		case 2:
++			*(u16 *) buf = inw(base + FTSPI020_REG_DATA_PORT);
++			break;
++
++		default:
++			*(u32 *) buf = inl(base + FTSPI020_REG_DATA_PORT);
++			break;
++		}
++	}
++}
++
++static int ftspi020_txfifo_ready(void __iomem * base)
++{
++	return inl(base + FTSPI020_REG_STS) & FTSPI020_STS_TFR;
++}
++
++static int ftspi020_rxfifo_ready(void __iomem * base)
++{
++	return inl(base + FTSPI020_REG_STS) & FTSPI020_STS_RFR;
++}
++
++#endif
++
++static unsigned int ftspi020_read_feature(void __iomem *base)
++{
++	return inl(base + FTSPI020_REG_FEATURE);
++}
++
++static int ftspi020_txfifo_depth(void __iomem * base)
++{
++	return  FTSPI020_FEATURE_TXFIFO_DEPTH(ftspi020_read_feature(base));
++}
++
++static int ftspi020_rxfifo_depth(void __iomem * base)
++{
++	return  FTSPI020_FEATURE_RXFIFO_DEPTH(ftspi020_read_feature(base));
++}
++
++static unsigned char ftspi020_read_status(void __iomem * base)
++{
++	return inb(base + FTSPI020_REG_READ_STS);
++}
++
++static void ftspi020_reset_hw(void __iomem * base)
++{
++	unsigned int	tmp = inl(base + FTSPI020_REG_CTRL);
++
++	tmp |= FTSPI020_CTRL_ABORT;
++	outl(tmp, base + FTSPI020_REG_CTRL);
++}
++
++static void ftspi020_int_enable(void __iomem * base)
++{
++	unsigned int	tmp = inl(base + FTSPI020_REG_ICR);
++
++	tmp |= FTSPI020_ICR_INT;
++	outl(tmp, base + FTSPI020_REG_ICR);
++}
++
++static void ftspi020_operate_mode(void __iomem * base, char mode)
++{
++	unsigned int	tmp = inl(base + FTSPI020_REG_CTRL);
++
++	tmp &= FTSPI020_CTRL_CLK_MODE_MASK;
++	tmp |= mode;
++	outl(tmp, base + FTSPI020_REG_CTRL);
++}
++
++static void ftspi020_busy_location(void __iomem * base, char loc)
++{
++	unsigned int	tmp = inl(base + FTSPI020_REG_CTRL);
++
++	tmp &= FTSPI020_CTRL_READY_LOC_MASK;
++	tmp |= FTSPI020_CTRL_READY_LOC(loc);
++	outl(tmp, base + FTSPI020_REG_CTRL);
++}
++
++static void ftspi020_clk_divider(void __iomem * base, char div)
++{
++	unsigned int	tmp = inl(base + FTSPI020_REG_CTRL);
++
++	tmp &= FTSPI020_CTRL_CLK_DIVIDER_MASK;
++	tmp |= div;
++	outl(tmp, base + FTSPI020_REG_CTRL);
++}
++
++/******************************************************************************
++ * workqueue
++ *****************************************************************************/
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++
++static int setup_dma(struct ftspi020_ctrl *ctrl, int direct)
++{
++    struct dma_slave_config *common;
++
++    ctrl->dma_slave_config.id = -1;
++    ctrl->dma_slave_config.handshake = SPI020_REQ;//enable
++
++    common = &ctrl->dma_slave_config.common;
++
++#ifdef CONFIG_FTSPI020_USE_AHBDMA
++    ctrl->dma_slave_config.src_size = FTDMAC020_BURST_SZ_4;//64x4=256
++
++    if(direct == DMA_DEV_TO_MEM){
++        ctrl->dma_slave_config.src_sel = AHBMASTER_R_SRC;
++        ctrl->dma_slave_config.dst_sel = AHBMASTER_R_DST;
++    }else{
++        ctrl->dma_slave_config.src_sel = AHBMASTER_W_SRC;
++        ctrl->dma_slave_config.dst_sel = AHBMASTER_W_DST;
++    }
++#else
++    common->dst_maxburst = 4;
++    common->src_maxburst = 4;
++#endif
++
++    if(direct == DMA_MEM_TO_DEV){
++     	common->src_addr = ctrl->mem_dmaaddr;
++    	common->dst_addr = ctrl->spi_dmaaddr;
++    }else{
++     	common->src_addr = ctrl->spi_dmaaddr;
++    	common->dst_addr = ctrl->mem_dmaaddr;
++    }
++
++    /* SPI kernel maybe send len = 2011, so can't div 4 */
++    common->dst_addr_width = 1;
++    common->src_addr_width = 1;
++
++    common->direction = direct;
++
++    return dmaengine_slave_config(ctrl->dma_chan, common);//step 2
++}
++
++static int spi020_dma_start(struct ftspi020_ctrl *ctrl, size_t len, int direct)
++{
++	int ret;
++	enum dma_ctrl_flags flags;
++	struct dma_async_tx_descriptor *desc;
++
++	ret = setup_dma(ctrl, direct);
++	if (ret)
++	    return ret;
++
++	flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK | DMA_COMPL_SKIP_SRC_UNMAP | DMA_COMPL_SKIP_DEST_UNMAP;
++
++	desc = dmaengine_prep_slave_single(ctrl->dma_chan, (void *)ctrl->sg_dmabuf, len, direct, flags);//step 3
++
++	if (!desc)
++	    return ret;
++
++	desc->callback = ftspi020_dma_callback;
++        desc->callback_param = &ctrl;
++        ctrl->cookie = dmaengine_submit(desc);	//step 4
++	dma_async_issue_pending(ctrl->dma_chan);//step 5
++
++	return 0;
++}
++#endif
++
++static int _ftspi020_ctrl_work_transfer(struct ftspi020_ctrl *ctrl,
++				       struct spi_device *spi,
++				       struct spi_transfer *t, int wsize)
++{
++	int		len;
++	const void	*tx_buf;
++	void		*rx_buf;
++	struct ftspi020_cmd *cmd;
++	int		ret = 0;
++
++	cmd = (struct ftspi020_cmd *) t->tx_buf;
++
++	len = cmd->data_cnt;
++
++	/* Send command: Transfer OP CODE and address(if available)  */
++	if (cmd->flags & FTSPI020_XFER_CMD_STATE) {
++		int cmdq1, cmdq3;
++
++		g_cmd_complete = 0;
++
++		outl(cmd->spi_addr, ctrl->base + FTSPI020_REG_CMD0);
++
++		cmdq1 = (cmd->conti_read_mode_en | cmd->ins_len | cmd->dum_2nd_cyc | cmd->addr_len);
++		outl(cmdq1, ctrl->base + FTSPI020_REG_CMD1);
++
++		outl(cmd->data_cnt, ctrl->base + FTSPI020_REG_CMD2);
++
++		cmdq3 = (cmd->ins_code | cmd->conti_read_mode_code | FTSPI020_CMD3_CE(spi->chip_select) | cmd->spi_mode |
++			cmd->dtr_mode | cmd->read_status | cmd->read_status_en | cmd->write_en |
++			FTSPI020_CMD3_CMD_COMPL_INTR);
++		outl(cmdq3, ctrl->base + FTSPI020_REG_CMD3);
++
++	}
++
++	if (cmd->flags & FTSPI020_XFER_DATA_STATE) {
++
++		tx_buf = cmd->tx_buf;
++		rx_buf = cmd->rx_buf;
++
++		/* Special handling for Read Status */
++		if ((cmd->read_status_en == FTSPI020_CMD3_RD_STS_EN) &&
++		    (cmd->read_status == FTSPI020_CMD3_STS_SW_READ)) {
++
++			*(u8 *) rx_buf = ftspi020_read_status(ctrl->base);
++			len = 0;
++		}
++
++		while (len > 0) {
++			int access_byte;
++
++			if (tx_buf) {
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++
++				access_byte = min_t(int, len, FTSPI020_DMA_BUF_SIZE);
++
++				memcpy(ctrl->mem_dmabuf, tx_buf, access_byte);
++
++                ret = spi020_dma_start(ctrl, access_byte, DMA_MEM_TO_DEV);
++                if (ret < 0) {
++                    printk(KERN_ERR "spi020 dma write fail\n");
++                    goto out;
++                }
++                ftspi020_dma_wait();
++
++				tx_buf += access_byte;
++				len -= access_byte;
++#else
++				access_byte = min_t(int, len, ctrl->txfifo_depth);
++				len -= access_byte;
++
++				while (!ftspi020_txfifo_ready(ctrl->base));
++
++				while (access_byte) {
++					ftspi020_write_word(ctrl->base, tx_buf, wsize);
++
++					tx_buf += wsize;
++					access_byte -= wsize;
++				}
++#endif
++			} else if (rx_buf) {
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++
++				access_byte = min_t(int, len, FTSPI020_DMA_BUF_SIZE);
++
++                ret = spi020_dma_start(ctrl, access_byte, DMA_DEV_TO_MEM);
++                if (ret < 0) {
++                    printk(KERN_ERR "spi020 dma read fail\n");
++                    goto out;
++                }
++
++                ftspi020_dma_wait();
++
++				memcpy(rx_buf, ctrl->mem_dmabuf, access_byte);
++				rx_buf += access_byte;
++				len -= access_byte;
++#else
++				while (!ftspi020_rxfifo_ready(ctrl->base));
++
++				access_byte = min_t(int, len, ctrl->rxfifo_depth);
++				len -= access_byte;
++
++				while (access_byte) {
++					ftspi020_read_word(ctrl->base, rx_buf, wsize);
++
++					rx_buf += wsize;
++					access_byte -= wsize;
++				}
++#endif
++			}
++		}
++
++		ret = cmd->data_cnt - len;
++	}
++
++	/* Wait for Command complete interrupt */
++	if (cmd->flags & FTSPI020_XFER_CHECK_CMD_COMPLETE) {
++		/* wait until command complete interrupt */
++		len = wait_event_timeout(ctrl->waitq, g_cmd_complete, 15 * HZ);
++		if (len == 0) {
++    	    printk(KERN_ERR "spi020 complete queue wake up timeout signal arrived\n");
++    	    return -1;
++        }
++	}
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++out:
++#endif
++	return ret;
++}
++
++static int ftspi020_ctrl_work_transfer(struct ftspi020_ctrl *ctrl,
++				      struct spi_device *spi,
++				      struct spi_transfer *t)
++{
++	unsigned int	bpw;
++	unsigned int	wsize;	/* word size */
++	int		ret;
++
++	dev_dbg(&spi->dev, "%s(%p)\n", __func__, t);
++
++	bpw = t->bits_per_word ? t->bits_per_word : spi->bits_per_word;
++
++	if (bpw == 0 || bpw > 32)
++		return -EINVAL;
++
++	if (bpw <= 8)
++		wsize = 1;
++	else if (bpw <= 16)
++		wsize = 2;
++	else
++		wsize = 4;
++
++	/* XXX we should check t->speed_hz */
++	ret = _ftspi020_ctrl_work_transfer(ctrl, spi, t, wsize);
++
++	if (t->delay_usecs)
++		udelay(t->delay_usecs);
++
++	return ret;
++}
++
++static void ftspi020_ctrl_work_message(struct ftspi020_ctrl *ctrl,
++				      struct spi_message *m)
++{
++	struct spi_device	*spi = m->spi;
++	struct spi_transfer	*t;
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
++	dev_dbg(&ctrl->master->dev, "%s(%p)\n", __func__, m);
++#else
++	dev_dbg(&ctrl->master->cdev.dev, "%s(%p)\n", __func__, m);
++#endif
++
++	m->status		= 0;
++	m->actual_length	= 0;
++
++	list_for_each_entry(t, &m->transfers, transfer_list) {
++		int	ret;
++
++		if ((ret =
++		     ftspi020_ctrl_work_transfer(ctrl, spi, t)) < 0) {
++			m->status = ret;
++			break;
++		}
++
++		m->actual_length += ret;
++	}
++
++	m->complete(m->context);
++}
++
++static void ftspi020_ctrl_work(struct work_struct *work)
++{
++	struct ftspi020_ctrl	*ctrl;
++	unsigned long		flags;
++
++	ctrl = container_of(work, struct ftspi020_ctrl, work);
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
++	dev_dbg(&ctrl->master->dev, "%s(%p)\n", __func__, work);
++#else
++	dev_dbg(ctrl->master->cdev.dev, "%s(%p)\n", __func__, work);
++#endif
++
++	spin_lock_irqsave(&ctrl->lock, flags);
++
++	while (!list_empty(&ctrl->message_queue)) {
++		struct spi_message	*m;
++
++		m = container_of(ctrl->message_queue.next,
++				 struct spi_message, queue);
++		list_del_init(&m->queue);
++
++		spin_unlock_irqrestore(&ctrl->lock, flags);
++		ftspi020_ctrl_work_message(ctrl, m);
++		spin_lock_irqsave(&ctrl->lock, flags);
++	}
++
++	spin_unlock_irqrestore(&ctrl->lock, flags);
++}
++
++/******************************************************************************
++ * interrupt handler
++ *****************************************************************************/
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))
++static irqreturn_t ftspi020_ctrl_interrupt(int irq, void *dev_id)
++#else
++static irqreturn_t ftspi020_ctrl_interrupt(int irq, void *dev_id,
++					  struct pt_regs *regs)
++#endif
++{
++	struct spi_master	*master = dev_id;
++	struct ftspi020_ctrl	*ctrl;
++	u32			isr;
++
++	ctrl = spi_master_get_devdata(master);
++
++	isr = inl(ctrl->base + FTSPI020_REG_ISR);
++	outl(isr, ctrl->base + FTSPI020_REG_ISR);
++
++	if (isr & FTSPI020_ISR_CMD_CMPL) {
++		g_cmd_complete = 1;
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
++		dev_dbg(&master->dev, "Command Complete !\n");
++#else
++		dev_dbg(master->cdev.dev, "Command Complete!\n");
++#endif
++	}
++	wake_up(&ctrl->waitq);
++	return IRQ_HANDLED;
++}
++
++
++/******************************************************************************
++ * struct spi_master functions
++ *****************************************************************************/
++
++static int ftspi020_ctrl_master_setup_mode(struct ftspi020_ctrl *ctrl,
++					  u8 mode)
++{
++	u8 val;
++
++	if (mode ==  SPI_MODE_0)
++		val = FTSPI020_CTRL_CLK_MODE_0;
++	else if (mode == SPI_MODE_3)
++		val = FTSPI020_CTRL_CLK_MODE_3;
++	else {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24))
++		dev_err(&ctrl->master->dev,
++			 "setup: unsupported mode bits %x\n", mode);
++#else
++		dev_err(ctrl->master->cdev.dev,
++			 "setup: unsupported mode bits %x\n", mode);
++#endif
++		return -EINVAL;
++	}
++
++	ftspi020_operate_mode(ctrl->base, val);
++
++	return 0;
++}
++
++static int ftspi020_ctrl_master_setup(struct spi_device *spi)
++{
++	struct ftspi020_ctrl	*ctrl;
++	unsigned int		bpw = spi->bits_per_word;
++	int			CLK, CLK_DIV, ret, mod;
++
++	ctrl = spi_master_get_devdata(spi->master);
++
++	if (spi->chip_select > spi->master->num_chipselect) {
++		dev_info(&spi->dev,
++			 "setup: invalid chipselect %u (%u defined)\n",
++			 spi->chip_select, spi->master->num_chipselect);
++		return -EINVAL;
++	}
++
++	/* check bits per word */
++
++	bpw = bpw ? bpw : 32;
++
++	if (bpw == 0 || bpw > 32) {
++		dev_info(&spi->dev, "setup: invalid bpw%u (1 to 32)\n", bpw);
++		return -EINVAL;
++	}
++
++	spi->bits_per_word = bpw;
++
++	/* check mode */
++
++	if ((ret = ftspi020_ctrl_master_setup_mode(ctrl, spi->mode)) < 0)
++		return ret;
++
++	dev_info(&spi->dev, "setup: bpw %u mode %d\n", bpw, spi->mode);
++
++	/* check speed */
++	if (!spi->max_speed_hz) {
++		dev_err(&spi->dev, "setup: max speed not specified\n");
++		return -EINVAL;
++	}
++
++	/* XXX we should calculate this from actual clock and max_speed_hz */
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++#ifdef CONFIG_PLATFORM_GM8139
++    if(ftpmu010_read_reg(0x28) & (1 << 13))
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL2) / 4;
++    else
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL1) / 2;
++#endif
++#ifdef CONFIG_PLATFORM_GM8136
++    if(ftpmu010_read_reg(0x28) & (1 << 10))
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL1);
++    else
++        CLK = ftpmu010_get_attr(ATTR_TYPE_PLL2);
++#endif
++    CLK /= ((ftpmu010_read_reg(0x6C) & 0x7) + 1);
++
++#else 	
++	CLK = ftpmu010_get_attr(ATTR_TYPE_AHB);
++#endif	
++	//printk("CLK = %d,%d\n",CLK,spi->max_speed_hz);
++
++    CLK_DIV = CLK;
++    mod = do_div(CLK_DIV, spi->max_speed_hz);
++    
++    if(mod)
++        CLK_DIV++;
++    
++    //printk("CLK_DIV = %d, speed_hz = %d, mod = %d\n",CLK_DIV, spi->max_speed_hz, mod);
++    if(CLK_DIV > 8){
++        printk(KERN_ERR "SPI clock too quick\n");
++        CLK_DIV = FTSPI020_CTRL_CLK_DIVIDER_8;
++    }
++    else if(CLK_DIV > 6) {
++        CLK_DIV = FTSPI020_CTRL_CLK_DIVIDER_8;
++        CLK /= 8;
++    } else if(CLK_DIV > 4) {
++        CLK_DIV = FTSPI020_CTRL_CLK_DIVIDER_6;
++        CLK /= 6;
++    } else if(CLK_DIV > 2) {
++        CLK_DIV = FTSPI020_CTRL_CLK_DIVIDER_4;
++        CLK /= 4;
++    } else {
++        CLK_DIV = FTSPI020_CTRL_CLK_DIVIDER_2;
++        CLK /= 2;
++    }
++
++    printk(KERN_NOTICE "CLK div field set %d, clock = %dHz\n", CLK_DIV, CLK);
++	ftspi020_clk_divider(ctrl->base, CLK_DIV);
++
++	/* Maybe require to clear FIFO */
++#if 0
++	ftspi020_reset_hw(ctrl->base);
++#endif
++
++	return 0;
++}
++
++static int ftspi020_ctrl_master_send_message(struct spi_device *spi,
++					    struct spi_message *m)
++{
++	struct ftspi020_ctrl	*ctrl;
++	struct spi_transfer	*t;
++	unsigned long		flags;
++
++	ctrl = spi_master_get_devdata(spi->master);
++
++	/* sanity check */
++	list_for_each_entry(t, &m->transfers, transfer_list) {
++		dev_dbg(&spi->dev,
++		        "  xfer %p: len %u tx %p/%08x rx %p/%08x\n",
++			t, t->len, t->tx_buf, t->tx_dma, t->rx_buf, t->rx_dma);
++
++		if (!t->tx_buf) {
++			dev_err(&spi->dev, "missing important tx buf\n");
++			return -EINVAL;
++		}
++		if (!t->rx_buf && t->len) {
++			dev_err(&spi->dev, "missing rx tx buf\n");
++			return -EINVAL;
++		}
++	}
++
++	m->status		= -EINPROGRESS;
++	m->actual_length	= 0;
++
++	/* transfer */
++
++	spin_lock_irqsave(&ctrl->lock, flags);
++
++	list_add_tail(&m->queue, &ctrl->message_queue);
++	queue_work(ctrl->workqueue, &ctrl->work);
++
++	spin_unlock_irqrestore(&ctrl->lock, flags);
++
++	return 0;
++
++}
++
++static int ftspi020_ctrl_master_transfer(struct spi_device *spi,
++					struct spi_message *m)
++{
++	dev_dbg(&spi->dev, "new message %p submitted for %s\n",
++		m, dev_name(&spi->dev));
++
++	if (unlikely(list_empty(&m->transfers))) {
++		dev_err(&spi->dev, "empty spi_message\n");
++		return -EINVAL;
++	}
++
++	return ftspi020_ctrl_master_send_message(spi, m);
++}
++
++static void ftspi020_ctrl_master_cleanup(struct spi_device *spi)
++{
++	dev_info(&spi->dev, "cleanup\n");
++	if (!spi->controller_state)
++		return;
++}
++
++/******************************************************************************
++ * struct platform_driver functions
++ *****************************************************************************/
++static int ftspi020_probe(struct platform_device *pdev)
++{
++	struct resource		*res;
++	int			irq;
++	void __iomem		*base;
++	int			ret = 0;
++	struct spi_master	*master;
++	struct ftspi020_ctrl	*ctrl;
++
++	if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++		return -ENXIO;
++	}
++
++	if ((irq = platform_get_irq(pdev, 0)) < 0) {
++		return irq;
++	}
++    
++	/* setup spi core */
++
++	if ((master =
++	     spi_alloc_master(&pdev->dev, sizeof *ctrl)) == NULL) {
++		ret = -ENOMEM;
++		goto err_dealloc;
++	}
++
++        //master->mode_bits = 0;
++	master->bus_num		= pdev->id;
++	master->num_chipselect	= 4;
++	master->setup		= ftspi020_ctrl_master_setup;
++	master->transfer	= ftspi020_ctrl_master_transfer;
++	master->cleanup		= ftspi020_ctrl_master_cleanup;
++	platform_set_drvdata(pdev, master);
++
++	/* setup master private data */
++
++	ctrl = spi_master_get_devdata(master);
++
++	spin_lock_init(&ctrl->lock);
++	INIT_LIST_HEAD(&ctrl->message_queue);
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
++	INIT_WORK(&ctrl->work, ftspi020_ctrl_work);
++#else
++	INIT_WORK(&ctrl->work, ftspi020_ctrl_work, &ctrl->work);
++#endif
++	init_waitqueue_head(&ctrl->waitq);
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++    ctrl->spi_dmaaddr = res->start + 0x100; //data register
++#endif
++	if ((base =
++	     ioremap_nocache(pdev->resource[0].start,pdev->resource[0].end - pdev->resource[0].start + 1)) == NULL) {
++		ret = -ENOMEM;
++		goto err_dealloc;
++	}
++
++	if ((ret =
++	     request_irq(irq, ftspi020_ctrl_interrupt, 0, dev_name(&pdev->dev),
++			 master))) {
++		goto err_unmap;
++	}
++
++	ctrl->irq		= irq;
++	ctrl->base		= base;
++	ctrl->master		= master;
++	ctrl->rxfifo_depth	= ftspi020_rxfifo_depth(base);
++	ctrl->txfifo_depth	= ftspi020_txfifo_depth(base);
++
++	if ((ctrl->workqueue =
++	     create_singlethread_workqueue(dev_name(&pdev->dev))) == NULL) {
++		goto err_free_irq;
++	}
++
++	/* Initialize the hardware */
++
++	ftspi020_reset_hw(base);
++    ftspi020_int_enable(base);
++	ftspi020_busy_location(base, 0);
++
++	/* Initialize DMA engine */
++
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++#ifdef CONFIG_FTSPI020_USE_AHBDMA
++    printk(KERN_INFO "SPI020 uses AHB DMA mode\n");
++#else
++    ftpmu010_write_reg(spi020_fd, 0xA4, (0x0 << 26), (0x1 << 26));
++    printk(KERN_INFO "SPI020 uses AXI DMA mode\n");
++#endif
++
++	ftspi020_dma_enable(base);
++
++    dma_cap_set(DMA_SLAVE, ctrl->cap_mask);
++#ifdef CONFIG_FTSPI020_USE_AHBDMA
++    {
++    	struct ftdmac020_dma_slave slave;
++    	memset(&slave, 0, sizeof(slave));
++    	ctrl->dma_chan = dma_request_channel(ctrl->cap_mask, ftdmac020_chan_filter, (void *)&slave);//step 1
++    }
++#else
++    {
++    	struct ftdmac030_dma_slave slave;
++   		memset(&slave, 0, sizeof(slave));
++   		ctrl->dma_chan = dma_request_channel(ctrl->cap_mask, ftdmac030_chan_filter, (void *)&slave);//step 1
++    }
++#endif
++    if (!ctrl->dma_chan){
++        dev_err(&pdev->dev, "SPI020 DMA channel allocation failed\n");
++        ret = -ENODEV;
++        goto out_free_chan;
++    }
++    printk(KERN_INFO "SPI020 gets DMA channel %d\n", ctrl->dma_chan->chan_id);
++
++    ctrl->mem_dmabuf = dma_alloc_coherent(&pdev->dev, FTSPI020_DMA_BUF_SIZE, &ctrl->mem_dmaaddr, GFP_KERNEL);
++
++    if (!ctrl->mem_dmabuf) {
++        ret = -ENOMEM;
++        goto out_free_dma;
++    }
++    ctrl->sg_dmabuf = dma_to_virt(&pdev->dev, ctrl->mem_dmaaddr);
++
++    //printk("sg mem pa = 0x%x, va = 0x%x\n", (u32)ctrl->mem_dmaaddr, (u32)ctrl->sg_dmabuf);
++#endif
++
++	/* go! */
++
++	dev_info(&pdev->dev, "Faraday FTSPI020 Controller at 0x%08x(0x%08x) irq %d.\n",
++		 (unsigned int)res->start, (unsigned int)ctrl->base, irq);
++
++	if ((ret = spi_register_master(master)) != 0) {
++		dev_err(&pdev->dev, "register master failed\n");
++		goto err_destroy_workqueue;
++	}
++
++	printk(KERN_INFO "Probe FTSPI020 SPI Controller at 0x%08x (irq %d)\n", (unsigned int)res->start, irq);
++	return 0;
++
++err_destroy_workqueue:
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++    if(ctrl->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, FTSPI020_DMA_BUF_SIZE, ctrl->mem_dmabuf, ctrl->mem_dmaaddr);
++  out_free_dma:
++    if(ctrl->dma_chan)
++    	dma_release_channel(ctrl->dma_chan);
++  out_free_chan:
++#endif
++	destroy_workqueue(ctrl->workqueue);
++err_free_irq:
++	free_irq(irq, master);
++
++err_unmap:
++	iounmap(base);
++err_dealloc:
++	spi_master_put(master);
++	return ret;
++}
++
++static int ftspi020_remove(struct platform_device *pdev)
++{
++	struct spi_master	*master;
++	struct ftspi020_ctrl	*ctrl;
++	struct spi_message	*m;
++
++
++	master		= platform_get_drvdata(pdev);
++	ctrl	= spi_master_get_devdata(master);
++
++	/* Terminate remaining queued transfers */
++	list_for_each_entry(m, &ctrl->message_queue, queue) {
++		m->status = -ESHUTDOWN;
++		m->complete(m->context);
++	}
++
++	destroy_workqueue(ctrl->workqueue);
++	ftpmu010_deregister_reg(spi020_fd);
++
++	free_irq(ctrl->irq, master);
++	iounmap(ctrl->base);
++
++	spi_unregister_master(master);
++	dev_info(&pdev->dev, "FTSPI020 unregistered\n");
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++    if(ctrl->mem_dmabuf)
++        dma_free_coherent(&pdev->dev, FTSPI020_DMA_BUF_SIZE, ctrl->mem_dmabuf, ctrl->mem_dmaaddr);
++    if(ctrl->dma_chan)
++    	dma_release_channel(ctrl->dma_chan);
++#endif
++	return 0;
++}
++
++#define ftspi020_suspend NULL
++#define ftspi020_resume NULL
++
++static struct platform_driver ftspi020_driver = {
++	.probe		= ftspi020_probe,
++	.remove		= ftspi020_remove,
++	.suspend	= ftspi020_suspend,
++	.resume		= ftspi020_resume,
++	.driver		= {
++		.name = "ftspi020",
++		.owner = THIS_MODULE,
++	},
++};
++
++/******************************************************************************
++ * initialization / finalization
++ *****************************************************************************/
++static int __init ftspi020_init(void)
++{
++	int	ret = 0;
++
++#ifdef CONFIG_PLATFORM_GM8210
++	fmem_pci_id_t pci_id;
++	fmem_cpu_id_t cpu_id;
++	fmem_get_identifier(&pci_id, &cpu_id);
++	if((cpu_id != FMEM_CPU_FA726) || (pci_id != FMEM_PCI_HOST))
++		return 0;
++#endif
++
++	printk(KERN_INFO "SPI020 init\n");
++
++    /* check if the system is running SPI system
++     */
++    if (platform_check_flash_type() >= 0) {
++        printk(KERN_INFO "Not for SPI NOR pin mux\n");
++        return 0;
++    }
++
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++    init_waitqueue_head(&spi020_queue);
++#endif
++
++   /* Register PMU and turn on gate clock
++    */
++   spi020_fd = ftpmu010_register_reg(&pmu_reg_info);
++   if (spi020_fd < 0)
++       printk(KERN_ERR "SPI020: register PMU fail");
++
++	ret = platform_driver_register(&ftspi020_driver);
++
++	if (ret)
++		printk(KERN_ERR "register platform driver failed(%d)\n", ret);
++
++	return ret;
++}
++
++static void __exit ftspi020_exit(void)
++{
++	printk(KERN_DEBUG "%s()\n", __func__);
++
++    /* check if the system is running SPI system
++     */
++    if (platform_check_flash_type() >= 0)
++        return;
++
++	platform_driver_unregister(&ftspi020_driver);
++}
++
++#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA)
++
++void ftspi020_dma_callback(void *param)
++{
++    //printk("%s\n", __func__);
++
++    trigger_flag = 1;
++    wake_up(&spi020_queue);
++
++    return;
++}
++#endif
++
++module_init(ftspi020_init);
++module_exit(ftspi020_exit);
++
++MODULE_AUTHOR("BingJiun Luo <bjluo@faraday-tech.com>");
++MODULE_DESCRIPTION("FTSPI020 SPI Flash Controller Driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/spi/ftspi020.h b/drivers/spi/ftspi020.h
+new file mode 100644
+index 00000000..4a436929
+--- /dev/null
++++ b/drivers/spi/ftspi020.h
+@@ -0,0 +1,93 @@
++/**
++ * Command arguments definition for FTSPI020.
++ *
++ * Author: BingJiun Luo <bjluo@faraday-tech.com> 
++ *
++ * Copyright (c) 2011, Faraday Technology Corp.
++ *
++ */
++
++/*
++ * Settings value required to send command.
++ */
++struct ftspi020_cmd {
++	char flags;
++	/* offset 0x00: CMD Queue first word */
++	u32 spi_addr;	
++	/* offset 0x04: CMD Queue second word */
++	u32 addr_len;
++	u32 dum_2nd_cyc;
++	u32 ins_len;
++	u32 conti_read_mode_en;
++	/* offset 0x08: CMD queue third word */
++	u32 data_cnt;
++	/* offset 0x0C: CMD queue fourth word */
++	u32 write_en;
++	u32 read_status_en;
++	u32 read_status;
++	u32 dtr_mode;
++	u32 spi_mode;
++	u32 conti_read_mode_code;
++	u32 ins_code;
++
++	/* User data buffer pointer */
++	const void *tx_buf;
++	void *rx_buf;
++
++};
++
++/*
++ * In what state this command belong ?
++ */
++#define FTSPI020_XFER_BEGIN			0x01
++#define FTSPI020_XFER_END			0x02
++#define FTSPI020_XFER_CMD_STATE			0x04
++#define FTSPI020_XFER_DATA_STATE		0x08
++#define FTSPI020_XFER_CHECK_CMD_COMPLETE	0x10
++
++/*
++ * CMD1 Register offset 4: Command Queue Second Word
++ */
++#define FTSPI020_CMD1_CONT_READ_MODE_EN		(1 << 28)
++#define FTSPI020_CMD1_CONT_READ_MODE_DIS	(0 << 28)
++
++#define FTSPI020_CMD1_OP_CODE_0_BYTE		(0 << 24)
++#define FTSPI020_CMD1_OP_CODE_1_BYTE		(1 << 24)
++#define FTSPI020_CMD1_OP_CODE_2_BYTE		(2 << 24)
++
++#define FTSPI020_CMD1_DUMMY_CYCLE(x)	(((x) & 0xff) << 16)
++
++#define FTSPI020_CMD1_NO_ADDR		(0 << 0)
++#define FTSPI020_CMD1_ADDR_1BYTE	(1 << 0)
++#define FTSPI020_CMD1_ADDR_2BYTE	(2 << 0)
++#define FTSPI020_CMD1_ADDR_3BYTE	(3 << 0)
++#define FTSPI020_CMD1_ADDR_4BYTE	(4 << 0)
++
++
++/*
++ * CMD3 Register offset 0xc: Command Queue Fourth Word
++ */
++#define FTSPI020_CMD3_INSTR_CODE(x)	(((x) & 0xff) << 24)
++#define FTSPI020_CMD3_CONT_READ_CODE(x)	(((x) & 0xff) << 16)
++
++#define FTSPI020_CMD3_CE(x)		(((x) & 0x3) << 8)
++
++#define FTSPI020_CMD3_SERIAL_MODE	(0 << 5)
++#define FTSPI020_CMD3_DUAL_MODE		(1 << 5)
++#define FTSPI020_CMD3_QUAD_MODE		(2 << 5)
++#define FTSPI020_CMD3_DUAL_IO_MODE	(3 << 5)
++#define FTSPI020_CMD3_QUAD_IO_MODE	(4 << 5)
++
++#define FTSPI020_CMD3_DTR_MODE_EN	(1 << 4)
++#define FTSPI020_CMD3_DTR_MODE_DIS	(0 << 4)
++
++#define FTSPI020_CMD3_STS_SW_READ	(1 << 3)
++#define FTSPI020_CMD3_STS_HW_READ	(0 << 3)
++
++#define FTSPI020_CMD3_RD_STS_EN		(1 << 2)
++#define FTSPI020_CMD3_RD_STS_DIS	(0 << 2)
++
++#define	FTSPI020_CMD3_WRITE		(1 << 1)	
++#define	FTSPI020_CMD3_READ		(0 << 1)	
++
++#define FTSPI020_CMD3_CMD_COMPL_INTR	(1 << 0)
+\ No newline at end of file
+diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
+new file mode 100644
+index 00000000..9a285e8c
+--- /dev/null
++++ b/drivers/spi/ftssp010_spi.c
+@@ -0,0 +1,976 @@
++/** 
++ * @file ftssp010_spi.c
++ * @brief this file realizes grain media's spi controller, Copyright (C) 2014 GM Corp. 
++ * @date 2014-09-15
++ *
++ */
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++//#include <linux/gpio.h>
++#include <linux/sched.h>
++#include <linux/io.h>
++#include <mach/ftpmu010.h>
++#include "ftssp010_spi.h"
++#include <mach/hardware.h>
++#include <linux/gpio.h>
++
++#define GPIO_CS   // cs use GPIO. if not, please disable this definition
++
++#ifdef GPIO_CS
++#define GPIO_pin_cs0    14
++#define GPIO_pin_cs1    18  // depend on EVB design
++#define GPIO_pin_cs2    19  // depend on EVB design
++#define GPIO_pin_cs3    26  // depend on EVB design
++#endif
++
++#define DRV_NAME "ssp_spi"
++
++/* the spi->mode bits understood by this driver: */
++#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP)
++/******************************************************************************
++ * internal functions for FTSSP010
++ *****************************************************************************/
++static inline void ftssp010_tx_enable(void __iomem *base)
++{
++    u32 cr2 = inl(base + FTSSP010_OFFSET_CR2);
++
++    cr2 |= (FTSSP010_CR2_SSPEN | FTSSP010_CR2_TXDOE | FTSSP010_CR2_TXEN);
++    outl(cr2, base + FTSSP010_OFFSET_CR2);
++}
++
++static inline void ftssp010_enable(void __iomem *base)
++{
++    u32 cr2 = inl(base + FTSSP010_OFFSET_CR2);
++
++    cr2 |= (FTSSP010_CR2_SSPEN | FTSSP010_CR2_TXDOE | FTSSP010_CR2_RXEN | FTSSP010_CR2_TXEN);
++    outl(cr2, base + FTSSP010_OFFSET_CR2);
++}
++
++static inline void ftssp010_disable(void __iomem *base)
++{
++    u32 cr2 = inl(base + FTSSP010_OFFSET_CR2);
++
++    cr2 &= ~(FTSSP010_CR2_SSPEN | FTSSP010_CR2_RXEN | FTSSP010_CR2_TXEN);
++    outl(cr2, base + FTSSP010_OFFSET_CR2);
++}
++
++static inline void ftssp010_clear_fifo(void __iomem *base)
++{
++    u32 cr2 = inl(base + FTSSP010_OFFSET_CR2);
++
++    cr2 |= FTSSP010_CR2_TXFCLR | FTSSP010_CR2_RXFCLR;
++    outl(cr2, base + FTSSP010_OFFSET_CR2);
++}
++
++static void ftssp010_set_bits_per_word(void __iomem *base, int bpw)
++{
++    u32 cr1 = inl(base + FTSSP010_OFFSET_CR1);
++
++    cr1 &= ~FTSSP010_CR1_SDL_MASK;
++
++    if (unlikely(((bpw - 1) < 0) || ((bpw - 1) > 32))) {
++        FTSSP010_SPI_PRINT("%s fails: bpw - 1 = %d\n", __func__, bpw - 1);
++        return;
++    } else {
++        cr1 |= FTSSP010_CR1_SDL(bpw - 1);
++    }
++
++    outl(cr1, base + FTSSP010_OFFSET_CR1);
++}
++
++static void ftssp010_write_word(void __iomem *base, const void *data, int wsize)
++{
++    u32 tmp = 0;
++
++    if (data) {
++        switch (wsize) {
++        case 1:
++            tmp = *(const u8 *)data;
++            //printk("&w%x&",tmp);
++            break;
++
++        case 2:
++            tmp = *(const u16 *)data;
++            break;
++
++        default:
++            tmp = *(const u32 *)data;
++            break;
++        }
++    }
++
++    outl(tmp, base + FTSSP010_OFFSET_DATA);
++}
++
++static void ftssp010_read_word(void __iomem *base, void *buf, int wsize)
++{
++    u32 data = inl(base + FTSSP010_OFFSET_DATA);
++
++    if (buf) {
++        switch (wsize) {
++        case 1:
++            *(u8 *) buf = data;
++            //printk("&r%x&",data);
++            break;
++
++        case 2:
++            *(u16 *) buf = data;
++            break;
++
++        default:
++            *(u32 *) buf = data;
++            break;
++        }
++    }
++}
++
++static inline unsigned int ftssp010_read_status(void __iomem *base)
++{
++    u32 data = inl(base + FTSSP010_OFFSET_STATUS);
++    return data;
++}
++
++static inline int ftssp010_txfifo_not_full(void __iomem *base)
++{
++    return ftssp010_read_status(base) & FTSSP010_STATUS_TFNF;
++}
++
++static inline int ftssp010_rxfifo_valid_entries(void __iomem *base)
++{
++    u32 data = ftssp010_read_status(base);
++    return FTSSP010_STATUS_GET_RFVE(data);
++}
++
++static inline unsigned int ftssp010_read_feature(void __iomem *base)
++{
++    return inl(base + FTSSP010_OFFSET_FEATURE);
++}
++
++static inline int ftssp010_rxfifo_depth(void __iomem *base)
++{
++    return FTSSP010_FEATURE_RXFIFO_DEPTH(ftssp010_read_feature(base)) + 1;
++}
++
++/**
++ * Note: due to PMU and IP clock limitation, speed_hz may be not just the same as real bclk, it is likely higher
++ */
++static inline int ftssp010_set_speed(struct ftssp010_spi *ftssp010_spi, u32 speed_hz)
++{
++    u32 scldiv = 0, cr1 = 0;   
++
++    cr1 = inl(ftssp010_spi->base + FTSSP010_OFFSET_CR1);
++    cr1 &= ~0xFFFF;
++    scldiv = ftssp010_spi->hw_platform->working_clk / 2;
++    do_div(scldiv, speed_hz);
++   
++    if(scldiv > 0xFFFF)
++        printk(KERN_ERR "SSP speed too fast, can't be div to %dHz\n",speed_hz);
++
++    cr1 |= (scldiv - 1);
++    outl(cr1, ftssp010_spi->base + FTSSP010_OFFSET_CR1);
++
++    return 0;
++}
++
++static inline void ftssp010_cs_high(struct ftssp010_spi *ftssp010_spi, u8 cs)
++{
++#ifdef GPIO_CS
++	switch (cs) {
++	  case 0:
++        gpio_direction_output(GPIO_pin_cs0, 1);
++	    break;
++	  case 1:
++        gpio_direction_output(GPIO_pin_cs1, 1);
++	    break;
++	  case 2:
++        gpio_direction_output(GPIO_pin_cs2, 1);
++	    break;
++	  case 3:
++        gpio_direction_output(GPIO_pin_cs3, 1);
++	    break;	    	    
++	  default:
++	    printk(KERN_ERR "Not support this cs value = %d\n", cs);
++	    break;
++	}
++#endif 
++}
++
++static inline void ftssp010_cs_low(struct ftssp010_spi *ftssp010_spi, u8 cs)
++{
++#ifdef GPIO_CS
++	switch (cs) {
++	  case 0:
++        gpio_direction_output(GPIO_pin_cs0, 0);
++	    break;
++	  case 1:
++        gpio_direction_output(GPIO_pin_cs1, 0);
++	    break;
++	  case 2:
++        gpio_direction_output(GPIO_pin_cs2, 0);
++	    break;
++	  case 3:
++        gpio_direction_output(GPIO_pin_cs3, 0);
++	    break;	    	    
++	  default:
++	    printk(KERN_ERR "Not support this cs value = %d\n", cs);
++	    break;
++	}
++#endif    
++}
++
++/** 
++ * @brief real spi transfer work is done here
++ * 
++ * @param ftssp010_spi alias of controller
++ * @param spi specific spi device
++ * @param t one spi transfer
++ * @param wsize bytes per word, one byte is 8 bits
++ * 
++ * @return return the number of transfered words 
++ */
++static int _ftssp010_spi_work_transfer(struct ftssp010_spi *ftssp010_spi,
++                                       struct spi_device *spi, struct spi_transfer *t, int wsize)
++{
++    unsigned long flags;
++    unsigned len = t->len;
++    const void *tx_buf = t->tx_buf;
++    void *rx_buf = t->rx_buf;
++    unsigned int dummy_buf;
++
++#if 0//RichardLin
++    if(rx_buf == NULL){
++	    u32 tmp;
++
++		FTSSP010_SPI_PRINT("rx_buf NULL\n");	
++	    tmp= inl(ftssp010_spi->base + 0x00);
++	    tmp &= ~(0x03);
++	    outl(tmp, ftssp010_spi->base+ 0x00);
++
++	    tmp= inl(ftssp010_spi->base + 0x04);
++	    tmp &= ~(0x00FFFF);
++	    tmp |= 0x000001;
++	    outl(tmp, ftssp010_spi->base + 0x04);
++
++	    while (len > 0) {
++	        int count = 0;
++	        int i = 0;
++	
++	        spin_lock_irqsave(&ftssp010_spi->lock, flags);
++	
++	        /* tx FIFO not full */
++	        while (ftssp010_txfifo_not_full(ftssp010_spi->base)) {
++
++	            ftssp010_write_word(ftssp010_spi->base, tx_buf, wsize);
++	
++	            if (tx_buf) {
++	                tx_buf += wsize;
++	            }
++	
++	            count++;
++	            len -= wsize;
++
++	            if (len <= 0) {
++	                break;
++	            }
++	        }
++	
++	        FTSSP010_SPI_PRINT("In %s: tx done\n", __func__);
++	
++	        spin_unlock_irqrestore(&ftssp010_spi->lock, flags);
++	    }
++    }
++    else
++#endif
++	{
++	    while (len > 0) {
++	        int count = 0;
++	        int i = 0;
++	
++	        spin_lock_irqsave(&ftssp010_spi->lock, flags);
++	
++	        /* tx FIFO not full */
++	        while (ftssp010_txfifo_not_full(ftssp010_spi->base)) {
++	            if (len <= 0) {
++	                break;
++	            }
++	
++	            ftssp010_write_word(ftssp010_spi->base, tx_buf, wsize);
++	
++	            if (tx_buf) {
++	                tx_buf += wsize;
++	            }
++	
++	            count++;
++	            len -= wsize;
++	
++	            /* avoid Rx FIFO overrun */
++	            if (count >= ftssp010_spi->rxfifo_depth) {
++	                break;
++	            }
++	        }
++	
++	        FTSSP010_SPI_PRINT("In %s: tx done\n", __func__);
++	        
++	        if (rx_buf == NULL)
++	            rx_buf = (void *)&dummy_buf;
++	            
++	        /* receive the same number as transfered */
++	        for (i = 0; i < count; i++) {
++	            /* wait until sth. in rx fifo */
++	            int j = 0;
++	            while (!ftssp010_rxfifo_valid_entries(ftssp010_spi->base)
++	                   && (++j < 0x1000000)) {
++	                FTSSP010_SPI_PRINT("In %s: wait ftssp010_rxfifo_valid_entries\n", __func__);
++	            }
++	
++	            if(j >= 0x1000000)
++	                printk(KERN_ERR "wait ftssp010_rxfifo_valid_entries timeout\n");
++	                
++	            ftssp010_read_word(ftssp010_spi->base, rx_buf, wsize);
++	
++	            if (rx_buf && (rx_buf != (void *)&dummy_buf)) {
++	                rx_buf += wsize;
++	            }
++	        }
++	
++	        FTSSP010_SPI_PRINT("In %s: rx done\n", __func__);
++	
++	        spin_unlock_irqrestore(&ftssp010_spi->lock, flags);
++	    }
++	}
++    
++    return t->len - len;
++}
++                                       
++/** 
++ * @brief based on the specific spi device's parameters to set controller properly work
++ * 
++ * @param ftssp010_spi alias of controller 
++ * @param spi specific spi device
++ * @param t one spi transfer
++ * 
++ * @return 0 to indicate success else a negative to show the error type
++ */
++static int ftssp010_spi_work_transfer(struct ftssp010_spi *ftssp010_spi,
++                                      struct spi_device *spi, struct spi_transfer *t)
++{
++    unsigned int bpw = 0;
++    unsigned int wsize = 0;     /* word size */
++    int ret = 0;
++
++    bpw = t->bits_per_word ? t->bits_per_word : spi->bits_per_word;
++
++    if (bpw == 0 || bpw > 32) {
++        FTSSP010_SPI_PRINT("%s fails: wrong bpw(%d) by CS(%d)\n", __func__, bpw,
++                           spi->chip_select);
++        return -EINVAL;
++    }
++
++#if 0//RichardLin
++	FTSSP010_SPI_PRINT("t->len = %d, bpw = %d\n", t->len, bpw);
++   	wsize = (unsigned int)t->len;
++   	if(t->len == 1){
++    	ftssp010_set_bits_per_word(ftssp010_spi->base, 8);
++   	}
++   	else if(t->len == 2){
++    	ftssp010_set_bits_per_word(ftssp010_spi->base, 16);
++   	}
++   	else if(t->len == 3){
++    	ftssp010_set_bits_per_word(ftssp010_spi->base, 24);
++   	}
++   	else{
++    	ftssp010_set_bits_per_word(ftssp010_spi->base, 32);
++    	wsize = 4; 
++   	}
++#else
++    if (bpw <= 8) {
++        wsize = 1;
++    } else if (bpw <= 16) {
++        wsize = 2;
++    } else {
++        wsize = 4;
++    }
++
++    ftssp010_set_bits_per_word(ftssp010_spi->base, bpw);
++#endif
++    
++    if ((t->speed_hz == 0) || (t->speed_hz > spi->max_speed_hz)) {
++        //use default device's clk
++        t->speed_hz = spi->max_speed_hz;
++    }
++
++    ftssp010_set_speed(ftssp010_spi, t->speed_hz);
++    
++    ftssp010_cs_low(ftssp010_spi, spi->chip_select);
++
++    ret = _ftssp010_spi_work_transfer(ftssp010_spi, spi, t, wsize);
++
++    if (t->cs_change) {
++        FTSSP010_SPI_PRINT("cs %d change\n", spi->chip_select);
++        ftssp010_cs_high(ftssp010_spi, spi->chip_select);
++    }
++
++    if (t->delay_usecs) {
++        udelay(t->delay_usecs);
++    }
++
++    return ret;
++}
++
++#if DEBUG_FTSSP010_SPI
++static void dump_ssp_reg(void __iomem * base)
++{
++    printk("\n");
++    printk("0x00 = 0x%x\n", readl(base));
++    printk("0x04 = 0x%x\n", readl((base + 0x04)));
++    printk("0x08 = 0x%x\n", readl((base + 0x08)));
++    printk("0x0C = 0x%x\n", readl((base + 0x0C)));
++    printk("0x10 = 0x%x\n", readl((base + 0x10)));
++    printk("0x14 = 0x%x\n", readl((base + 0x14)));
++    printk("0x18 = 0x%x\n", readl((base + 0x18)));
++    printk("0x60 = 0x%x\n", readl((base + 0x60)));
++    printk("0x64 = 0x%x\n", readl((base + 0x64)));
++}
++#endif
++
++/** 
++ * @brief work until all transfers in one spi message done
++ * 
++ * @param ftssp010_spi alias of controller
++ * @param m one spi message
++ */
++static void ftssp010_spi_work_message(struct ftssp010_spi *ftssp010_spi, struct spi_message *m)
++{
++    struct spi_device *spi = m->spi;
++    struct spi_transfer *t;
++    
++    m->status = 0;
++    m->actual_length = 0;
++
++    ftssp010_enable(ftssp010_spi->base);
++
++    FTSSP010_SPI_PRINT("<FS%d low>", spi->chip_select);
++
++#if DEBUG_FTSSP010_SPI
++    dump_ssp_reg(ftssp010_spi->base);
++#endif
++    list_for_each_entry(t, &m->transfers, transfer_list) {
++        int ret;
++        
++        FTSSP010_SPI_PRINT("<add_tail>");
++        if ((ret = ftssp010_spi_work_transfer(ftssp010_spi, spi, t)) < 0) {
++            m->status = ret;
++            break;
++        }
++        m->actual_length += ret;
++    }
++
++    ftssp010_cs_high(ftssp010_spi, spi->chip_select);
++    //ftssp010_disable(ftssp010_spi->base);
++    FTSSP010_SPI_PRINT("<FS%d high>", spi->chip_select);
++    //ftssp010_clear_fifo(ftssp010_spi->base);//justin
++    m->complete(m->context);
++}
++
++
++/** 
++ * @brief work until all spi messages requested by a specific device done
++ * 
++ * @param work one requested work to be done
++ */
++static void ftssp010_spi_work(struct work_struct *work)
++{
++    struct ftssp010_spi *ftssp010_spi = NULL;
++    unsigned long flags = 0;
++
++    ftssp010_spi = container_of(work, struct ftssp010_spi, work);
++    
++    spin_lock_irqsave(&ftssp010_spi->lock, flags);
++
++    while (!list_empty(&ftssp010_spi->message_queue)) {
++        struct spi_message *m = NULL;
++
++        m = container_of(ftssp010_spi->message_queue.next, struct spi_message, queue);
++        list_del_init(&m->queue);
++
++        spin_unlock_irqrestore(&ftssp010_spi->lock, flags);
++        ftssp010_spi_work_message(ftssp010_spi, m);
++
++        spin_lock_irqsave(&ftssp010_spi->lock, flags);
++    }
++
++    spin_unlock_irqrestore(&ftssp010_spi->lock, flags);
++}
++
++/** 
++ * @brief ISR for SPI controller get something wrong
++ * 
++ * @param irq spi's irq number
++ * @param dev_id specific spi info
++ * 
++ * @return always return IRQ_HANDLED to indicate we got the irq
++ */
++static irqreturn_t ftssp010_spi_interrupt(int irq, void *dev_id)
++{
++    struct spi_master *master = dev_id;
++    struct ftssp010_spi *ftssp010_spi = NULL;
++    u32 isr = 0;
++
++    ftssp010_spi = spi_master_get_devdata(master);
++
++    isr = inl(ftssp010_spi->base + FTSSP010_OFFSET_ISR);
++
++    if (isr & FTSSP010_ISR_RFOR) {
++        outl(FTSSP010_ISR_RFOR, ftssp010_spi->base + FTSSP010_OFFSET_ISR);
++        FTSSP010_SPI_PRINT("In %s: RX Overrun\n", __func__);
++    }
++
++    wake_up(&ftssp010_spi->waitq);
++
++    return IRQ_HANDLED;
++}
++
++/** 
++ * @brief set proper controller's state based on specific device
++ * 
++ * @param ftssp010_spi alias of controller
++ * @param mode device's specific mode
++ * 
++ * @return always return 0 to indicate set up done
++ */
++static int ftssp010_spi_master_setup_mode(struct ftssp010_spi
++                                          *ftssp010_spi, u8 mode)
++{
++    u32 cr0 = 0;
++    
++    if (mode & ~MODEBITS) {
++        FTSSP010_SPI_PRINT("%s fails: some SPI mode not support currently\n", __func__);
++        return -EINVAL;
++    }
++
++    cr0 |= FTSSP010_CR0_FFMT_SPI | FTSSP010_CR0_OPM_MASTER_STEREO;
++
++    if (mode & SPI_CPOL) {
++        cr0 |= FTSSP010_CR0_SCLKPO;
++    }
++
++    if (mode & SPI_CPHA) {
++        cr0 |= FTSSP010_CR0_SCLKPH;
++    }
++
++    if (mode & SPI_LOOP) {
++        cr0 |= FTSSP010_CR0_LBM;
++    }
++
++    if (mode & SPI_LSB_FIRST) {
++        cr0 |= FTSSP010_CR0_LSB;
++    }
++
++    outl(cr0, ftssp010_spi->base + FTSSP010_OFFSET_CR0);
++
++    return 0;
++}
++
++/** 
++ * @brief init specific spi divice's setting, this should be given by device. Or, we will give normal value.
++ *        
++ * @param spi specific device
++ * 
++ * @return return 0 when everything goes fine else return a negative to indicate error
++ */
++static int ftssp010_spi_master_setup(struct spi_device *spi)
++{
++    struct ftssp010_spi *ftssp010_spi = NULL;
++    unsigned int bpw = spi->bits_per_word;
++    int ret = 0;
++    
++    ftssp010_spi = spi_master_get_devdata(spi->master);
++
++    if (spi->chip_select > spi->master->num_chipselect) {
++        FTSSP010_SPI_PRINT
++            ("%s fails: invalid chipselect %u (%u defined)\n",
++             __func__, spi->chip_select, spi->master->num_chipselect);
++        return -EINVAL;
++    }
++
++    /* check bits per word */
++    if (bpw == 0) {
++        FTSSP010_SPI_PRINT("In %s: bpw == 0, use 8 bits by default\n", __func__);
++        bpw = 8;
++    }
++
++    if (bpw == 0 || bpw > 32) {
++        FTSSP010_SPI_PRINT("%s fails: invalid bpw%u (1 to 32)\n", __func__, bpw);
++        return -EINVAL;
++    }
++
++    spi->bits_per_word = bpw;
++
++    /* check mode */
++    spi->mode |= SPI_LSB_FIRST;    
++    printk(KERN_INFO "Setup device %s, chip select %d, mode = 0x%x, speed = %d\n", spi->modalias, spi->chip_select, spi->mode, spi->max_speed_hz);
++
++    if ((ret = ftssp010_spi_master_setup_mode(ftssp010_spi, spi->mode)) < 0) {
++        FTSSP010_SPI_PRINT("%s fails: ftssp010_spi_master_setup_mode not OK\n", __func__);
++        return ret;
++    }
++
++    /* check speed */
++    if (!spi->max_speed_hz) {
++        FTSSP010_SPI_PRINT("%s fails: max speed not specified\n", __func__);
++        return -EINVAL;
++    }
++   
++    if (spi->max_speed_hz > ftssp010_spi->hw_platform->working_clk) {
++        printk(KERN_ERR "Error => In %s: spi->max_speed_hz(%dHz) is out of current IP's capability(%d).\n", 
++               __func__, spi->max_speed_hz, ftssp010_spi->hw_platform->working_clk);
++    }
++
++    ftssp010_set_bits_per_word(ftssp010_spi->base, bpw);
++
++    /* init */
++    ftssp010_cs_high(ftssp010_spi, spi->chip_select);
++    ftssp010_clear_fifo(ftssp010_spi->base);
++
++    return 0;
++}
++
++/** 
++ * @brief send a complete spi message
++ * 
++ * @param spi specific spi device
++ * @param m the message to be sent
++ * 
++ * @return return 0 when everything goes fine else return a negative to indicate error
++ */
++static int ftssp010_spi_master_send_message(struct spi_device *spi, struct spi_message *m)
++{
++    struct ftssp010_spi *ftssp010_spi;
++    struct spi_transfer *t;
++    unsigned long flags;
++
++    ftssp010_spi = spi_master_get_devdata(spi->master);
++
++    /* sanity check */
++    list_for_each_entry(t, &m->transfers, transfer_list) {
++        if (!(t->tx_buf || t->rx_buf) && t->len) {
++            FTSSP010_SPI_PRINT("%s fails: missing rx or tx buf\n", __func__);
++            return -EINVAL;
++        }
++    }
++
++    m->status = -EINPROGRESS;
++    m->actual_length = 0;
++
++    /* transfer */
++
++    spin_lock_irqsave(&ftssp010_spi->lock, flags);
++
++    list_add_tail(&m->queue, &ftssp010_spi->message_queue);
++    queue_work(ftssp010_spi->workqueue, &ftssp010_spi->work);
++
++    spin_unlock_irqrestore(&ftssp010_spi->lock, flags);
++    
++    return 0;
++}
++
++static int ftssp010_spi_master_transfer(struct spi_device *spi, struct spi_message *m)
++{    
++    if (unlikely(list_empty(&m->transfers))) {
++        return -EINVAL;
++    }
++
++    return ftssp010_spi_master_send_message(spi, m);
++}
++
++static void ftssp010_spi_master_cleanup(struct spi_device *spi)
++{
++    if (!spi->controller_state) {
++        return;
++    }
++}
++
++#ifdef CONFIG_PLATFORM_GM8220
++static pmuReg_t ssp1_pmu_reg[] = {
++	/* off, bitmask,   lockbit,    init val,   init mask */
++	//{0x28, (0x3 << 22), (0x3 << 22), (0x2 << 22), (0x3 << 22)}, /* Clock source */
++	//{0x50, (0x1 << 31), (0x1 << 31), (0x1 << 31), (0x1 << 31)}, /* pinMux */
++	//{0x74, (0x3F << 6), (0x3F << 6), (0x5 << 6), (0x3F << 6)}, /*  Divider Setting */
++	{0x6C, (0x1 << 23), (0x1 << 23), (0x0 << 23), (0x1 << 23)}, /* clock gate */
++	{0x74, (0x1 << 31), (0x1 << 31), (0x0 << 31), (0x1 << 31)}, /* clock gate */
++};
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8287
++static pmuReg_t ssp1_pmu_reg[] = {
++	/* off, bitmask,   lockbit,    init val,   init mask */
++	{0x28, (0x3 << 22), (0x3 << 22), (0x2 << 22), (0x3 << 22)}, /* Clock source */
++	{0x50, (0x1 << 31), (0x1 << 31), (0x1 << 31), (0x1 << 31)}, /* pinMux */
++	{0x74, (0x3F << 6), (0x3F << 6), (0x5 << 6), (0x3F << 6)}, /*  Divider Setting */
++	{0xB8, (0x1 << 7), (0x1 << 7), (0x0 << 7), (0x1 << 7)}, /* AHB clock gate */
++};
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8139
++static pmuReg_t  ssp1_pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x28, (0x1 << 15), (0x1 << 15), (0x0 << 15), (0x1 << 15)},   /* SSP1 CLK from PLL2 */
++    {0x54, (0xFF << 14), (0xFF << 14), (0xFF << 14), (0xFF << 14)},   /* pinMux *///justin
++    {0x74, (0x3F << 8), (0x3F << 8), (0x2C << 8), (0x3F << 8)},   /* SSP1 clock divided value */
++    {0x7C, (0x1 << 29), (0x1 << 29), (0x1 << 29), (0x1 << 29)},   /* SSP1 source select external */
++    {0xB8, (0x1 << 5), (0x1 << 5), (0x0 << 5), (0x1 << 5)},   /* apb mclk on */
++};
++#endif
++
++#ifdef CONFIG_PLATFORM_GM8136
++static pmuReg_t  ssp1_pmu_reg[] = {
++    /* off, bitmask,   lockbit,    init val,   init mask */
++    {0x28, (0x3 << 13), (0x3 << 13), (0x2 << 13), (0x3 << 13)},   /* SSP1 CLK from PLL2 */
++
++    {0x54, (0xFF << 14), (0xFF << 14), (0xFF << 14), (0xFF << 14)},   /* pinMux 0x54 use spi*/
++//    {0x54, (0xFF << 14), (0xFF << 14), (0xFC << 14), (0xFF << 14)},   /* pinMux 0x54 use spi, FS use GPIO0[14]*/    
++//    {0x64, (0xFF << 0), (0xFF << 0), (0x55 << 0), (0xFF << 0)},   /* pinMux 0x64 USE spi, pin mux with UART1 */
++//    {0x64, (0xFF << 0), (0xFF << 0), (0x51 << 0), (0xFF << 0)},   /* pinMux 0x64 USE spi, FS use GPIO1[24] */
++
++    {0x74, (0x3F << 8), (0x3F << 8), (0x31 << 8), (0x3F << 8)},   /* SSP1 clock divided value */
++    {0x7C, (0x1 << 29), (0x1 << 29), (0x1 << 29), (0x1 << 29)},   /* SSP1 source select external */
++    {0xB8, (0x1 << 5), (0x1 << 5), (0x0 << 5), (0x1 << 5)},   /* apb mclk on */
++};
++#endif
++
++static pmuRegInfo_t	spi_1_clk_pinmux_info = {
++    "SSP010_1",
++    ARRAY_SIZE(ssp1_pmu_reg),
++    ATTR_TYPE_NONE,
++    ssp1_pmu_reg
++};
++
++static void spi_1_pmu_init(struct ftssp010_spi_hw_platform *hw_platform)
++{
++    u32 ssp1clk_pvalue = 0, CLK;
++    int spi_1_fd = -1;
++
++    spi_1_fd = ftpmu010_register_reg(&spi_1_clk_pinmux_info);
++    if (unlikely(spi_1_fd < 0)){
++        printk(KERN_ERR "In %s: SPI 1 registers to PMU fail! \n", __func__);
++    }
++
++    // read current SPI1 working clock, NOTE: the working of SSP on 8126 can not be over 81MHz due to HW limitation
++    ssp1clk_pvalue = (ftpmu010_read_reg(0x74) >> 8) & 0x7F;
++#ifdef CONFIG_PLATFORM_GM8139
++    CLK = ftpmu010_get_attr(ATTR_TYPE_PLL3);
++#else    
++    CLK = ftpmu010_get_attr(ATTR_TYPE_PLL2);
++#endif
++    hw_platform->working_clk = (CLK / (ssp1clk_pvalue + 1));
++
++    //printk("ssp1clk_pvalue = %d\n", ssp1clk_pvalue);
++    FTSSP010_SPI_PRINT("SSP1 source clock = %d\n", hw_platform->working_clk);
++}
++
++struct ftssp010_spi_hw_platform *ftssp010_spi_get_hw_platform(u8 controller_id)
++{
++    struct ftssp010_spi_hw_platform *hw_platform = NULL;
++
++    hw_platform = kzalloc(sizeof(struct ftssp010_spi_hw_platform), GFP_KERNEL);
++    if (!hw_platform) {
++        printk(KERN_ERR "Error => In %s: alloc fail.\n", __func__);
++    }
++
++    // currently, only SSP0 and SSP1 can use SPI driver
++    if (controller_id == 0) {
++        //spi_hw_init_0(hw_platform);
++        printk(KERN_WARNING "SSP0 be used for audio\n");
++    } else if (controller_id == 1) {
++        spi_1_pmu_init(hw_platform);
++    }
++
++    return hw_platform;
++}
++
++/** 
++ * @brief probe spi controller
++ * 
++ * @param pdev the spi controller is a platform device specified in arch/arm/mach-GM/platform-XXX/platform.c
++ * 
++ * @return return 0 when everything goes fine else return a negative to indicate error
++ */
++static int ftssp010_spi_probe(struct platform_device *pdev)
++{
++    struct resource *res = NULL;
++    int irq = 0;
++    void __iomem *base = NULL;
++    int ret = 0;
++    struct spi_master *master = NULL;
++    struct ftssp010_spi *ftssp010_spi = NULL;
++    struct ftssp010_spi_hw_platform *spi_hw_platform = NULL;    
++
++    spi_hw_platform = ftssp010_spi_get_hw_platform(pdev->id);
++    if (unlikely(spi_hw_platform == NULL)) {
++        printk(KERN_ERR "Error => %s: SSP(%d) spi_hw_platform is NULL.\n", __func__, pdev->id);
++    }
++    
++    if ((res = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == 0) {
++        return -ENXIO;
++    }
++
++    if ((irq = platform_get_irq(pdev, 0)) < 0) {
++        return irq;
++    }
++
++    /* setup spi core */
++    if ((master = spi_alloc_master(&pdev->dev, sizeof(struct ftssp010_spi))) == NULL) {
++        ret = -ENOMEM;
++        goto err_dealloc;
++    }
++            
++#ifdef GPIO_CS
++    if(gpio_request(GPIO_pin_cs0, "gpio_cs0") < 0) {
++        printk(KERN_ERR "gpio#%d request failed!\n", GPIO_pin_cs0);
++        ret = -1;
++        goto err_dealloc;
++    }
++#if 0   // how many devices users want to use
++    if(gpio_request(GPIO_pin_cs1, "gpio_cs1") < 0) {
++        printk(KERN_ERR "gpio#%d request failed!\n", GPIO_pin_cs1);
++        ret = -1;
++        goto err_dealloc;
++    }
++    if(gpio_request(GPIO_pin_cs2, "gpio_cs2") < 0) {
++        printk(KERN_ERR "gpio#%d request failed!\n", GPIO_pin_cs2);
++        ret = -1;
++        goto err_dealloc;
++    }
++    if(gpio_request(GPIO_pin_cs3, "gpio_cs3") < 0) {
++        printk(KERN_ERR "gpio#%d request failed!\n", GPIO_pin_cs3);
++        ret = -1;
++        goto err_dealloc;
++    }        
++#endif    
++#endif            
++    master->bus_num = pdev->id;
++    master->mode_bits = MODEBITS;
++    master->num_chipselect = 4;
++    printk(KERN_INFO "bus num = %d, chip select = %d\n",master->bus_num,master->num_chipselect);
++    master->setup = ftssp010_spi_master_setup;
++    master->transfer = ftssp010_spi_master_transfer;
++    master->cleanup = ftssp010_spi_master_cleanup;
++    platform_set_drvdata(pdev, master);
++
++    /* setup master private data */
++    ftssp010_spi = spi_master_get_devdata(master);
++
++    spin_lock_init(&ftssp010_spi->lock);
++    INIT_LIST_HEAD(&ftssp010_spi->message_queue);
++    INIT_WORK(&ftssp010_spi->work, ftssp010_spi_work);
++    init_waitqueue_head(&ftssp010_spi->waitq);
++
++    if ((base = ioremap_nocache(res->start, (res->end - res->start + 1))) == NULL) {
++        ret = -ENOMEM;
++        goto err_dealloc;
++    }
++    
++    /* Error Handler */
++    if ((ret = request_irq(irq, ftssp010_spi_interrupt, 0, dev_name(&pdev->dev), master))) {
++        goto err_unmap;
++    }
++
++    ftssp010_spi->hw_platform = spi_hw_platform; 
++    ftssp010_spi->irq = irq;
++    ftssp010_spi->pbase = res->start;
++    ftssp010_spi->base = base;
++    ftssp010_spi->master = master;
++    ftssp010_spi->rxfifo_depth = ftssp010_rxfifo_depth(base);
++
++    if ((ftssp010_spi->workqueue = create_singlethread_workqueue(dev_name(&pdev->dev))) == NULL) {
++        goto err_free_irq;
++    }
++
++    /* Initialize the hardware */
++    outl(FTSSP010_ICR_RFTHOD(1),
++         base + FTSSP010_OFFSET_ICR);
++    
++    if ((ret = spi_register_master(master)) != 0) {
++        dev_err(&pdev->dev, "register master failed\n");
++        goto err_destroy_workqueue;
++    }
++    
++    /* go! */
++    printk(KERN_INFO "Probe FTSSP010 SPI Controller at 0x%08x (irq %d)\n", (unsigned int)res->start, irq);
++
++    return 0;
++
++  err_destroy_workqueue:
++    destroy_workqueue(ftssp010_spi->workqueue);
++  err_free_irq:
++    free_irq(irq, master);
++  err_unmap:
++    iounmap(base);
++  err_dealloc:
++    spi_master_put(master);
++
++    return ret;
++}
++
++/** 
++ * @brief remove the spi controller from kernel
++ * 
++ * @param pdev the spi controller 
++ * 
++ * @return always return 0 to indicate it is not workable any more
++ */
++static int __devexit ftssp010_spi_remove(struct platform_device *pdev)
++{
++    struct spi_master *master = NULL;
++    struct ftssp010_spi *ftssp010_spi = NULL;
++    struct spi_message *m = NULL;
++
++    printk(KERN_INFO "Remove FTSSP010 Controller\n");
++
++    master = platform_get_drvdata(pdev);
++    ftssp010_spi = spi_master_get_devdata(master);
++
++    /* Terminate remaining queued transfers */
++    list_for_each_entry(m, &ftssp010_spi->message_queue, queue) {
++        m->status = -ESHUTDOWN;
++        m->complete(m->context);
++    }
++
++    destroy_workqueue(ftssp010_spi->workqueue);
++    free_irq(ftssp010_spi->irq, master);
++    iounmap(ftssp010_spi->base);
++    spi_unregister_master(master);
++
++    return 0;
++}
++
++/** 
++ * @brief SPI controller driver is a platform driver to probe platform device SPI controller 
++ */
++static struct platform_driver ftssp010_spi_driver = {
++    .probe = ftssp010_spi_probe,
++    .remove = __devexit_p(ftssp010_spi_remove),
++    .suspend = NULL,
++    .resume = NULL,
++    .driver = {
++               .name = DRV_NAME,
++               .owner = THIS_MODULE,
++               },
++};
++
++module_platform_driver(ftssp010_spi_driver);
++
++MODULE_AUTHOR("Grain Media Corp");
++MODULE_DESCRIPTION("FTSSP010 SPI Driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRV_NAME);
+\ No newline at end of file
+diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
+new file mode 100644
+index 00000000..acb7e7da
+--- /dev/null
++++ b/drivers/spi/ftssp010_spi.h
+@@ -0,0 +1,186 @@
++#ifndef __FTSSP010_SPI_H__
++#define __FTSSP010_SPI_H__
++
++#include <linux/types.h>
++#include <linux/spinlock_types.h>
++#include <linux/workqueue.h>
++#include <linux/wait.h>
++
++#define DEBUG_FTSSP010_SPI      0
++
++//debug helper
++#if DEBUG_FTSSP010_SPI
++#define FTSSP010_SPI_PRINT(FMT, ARGS...)    printk(FMT, ##ARGS)
++#else
++#define FTSSP010_SPI_PRINT(FMT, ARGS...)
++#endif
++/******************************************************************************
++ * SSP010 definitions
++ *****************************************************************************/
++#define FTSSP010_OFFSET_CR0     0x00
++#define FTSSP010_OFFSET_CR1     0x04
++#define FTSSP010_OFFSET_CR2     0x08
++#define FTSSP010_OFFSET_STATUS  0x0c
++#define FTSSP010_OFFSET_ICR     0x10
++#define FTSSP010_OFFSET_ISR     0x14
++#define FTSSP010_OFFSET_DATA        0x18
++
++#define FTSSP010_OFFSET_ACLSV       0x20        /* AC-Link slot valid register */
++
++#define FTSSP010_OFFSET_REVISION    0x60
++#define FTSSP010_OFFSET_FEATURE     0x64
++
++/*
++ * Control Register 0
++ */
++#define FTSSP010_CR0_SCLKPH     (1 << 0)        /* SPI SCLK phase */
++#define FTSSP010_CR0_SCLKPO     (1 << 1)        /* SPI SCLK polarity */
++#define FTSSP010_CR0_OPM_SLAVE_MONO (0x0 << 2)
++#define FTSSP010_CR0_OPM_SLAVE_STEREO   (0x1 << 2)
++#define FTSSP010_CR0_OPM_MASTER_MONO    (0x2 << 2)
++#define FTSSP010_CR0_OPM_MASTER_STEREO  (0x3 << 2)
++#define FTSSP010_CR0_FSJSTFY        (1 << 4)
++#define FTSSP010_CR0_FSPO       (1 << 5)
++#define FTSSP010_CR0_LSB        (1 << 6)
++#define FTSSP010_CR0_LBM        (1 << 7)
++#define FTSSP010_CR0_FSDIST(x)      (((x) & 0x3) << 8)
++#define FTSSP010_CR0_FFMT_TI_SSP    (0x0 << 12)
++#define FTSSP010_CR0_FFMT_SPI       (0x1 << 12) /* Motorola  SPI */
++#define FTSSP010_CR0_FFMT_MICROWIRE (0x2 << 12) /* NS  Microwire */
++#define FTSSP010_CR0_FFMT_I2S       (0x3 << 12) /* Philips   I2S */
++#define FTSSP010_CR0_FFMT_ACLINK    (0x4 << 12) /* Intel AC-Link */
++
++/*
++ * Control Register 1
++ */
++#define FTSSP010_CR1_SCLKDIV(x) (((x) & 0xffff) << 0)   /* SCLK divider */
++#define FTSSP010_CR1_SDL_MASK   (0x1f << 16)    /* serial  data length */
++#define FTSSP010_CR1_SDL(x) (((x) & 0x1f) << 16)        /* serial  data length */
++#define FTSSP010_CR1_PDL(x) (((x) & 0xff) << 24)        /* padding data length */
++/*
++ * Control Register 2
++ */
++#define FTSSP010_CR2_SSPEN  (1 << 0)    /* SSP enable */
++#define FTSSP010_CR2_TXDOE  (1 << 1)    /* transmit data output enable */
++#define FTSSP010_CR2_RXFCLR (1 << 2)    /* receive  FIFO clear */
++#define FTSSP010_CR2_TXFCLR (1 << 3)    /* transmit FIFO clear */
++#define FTSSP010_CR2_ACWRST (1 << 4)    /* AC-Link warm reset enable */
++#define FTSSP010_CR2_ACCRST (1 << 5)    /* AC-Link cold reset enable */
++#define FTSSP010_CR2_SSPRST (1 << 6)    /* SSP reset */
++#define FTSSP010_CR2_RXEN   (1 << 7)    /* rx enable */
++#define FTSSP010_CR2_TXEN   (1 << 8)    /* tx enable */
++#define FTSSP010_CR2_FS     (1 << 9)    /* frame sync */
++
++/*
++ * Status Register
++ */
++#define FTSSP010_STATUS_RFF     (1 << 0)        /* receive FIFO full */
++#define FTSSP010_STATUS_TFNF        (1 << 1)    /* transmit FIFO not full */
++#define FTSSP010_STATUS_BUSY        (1 << 2)    /* bus is busy */
++#define FTSSP010_STATUS_GET_RFVE(reg)   (((reg) >> 4) & 0x1f)   /* receive  FIFO valid entries */
++#define FTSSP010_STATUS_GET_TFVE(reg)   (((reg) >> 12) & 0x1f)  /* transmit FIFO valid entries */
++
++/*
++ * Interrupt Control Register
++ */
++#define FTSSP010_ICR_RFOR       (1 << 0)        /* receive  FIFO overrun   interrupt */
++#define FTSSP010_ICR_TFUR       (1 << 1)        /* transmit FIFO underrun  interrupt */
++#define FTSSP010_ICR_RFTH       (1 << 2)        /* receive  FIFO threshold interrupt */
++#define FTSSP010_ICR_TFTH       (1 << 3)        /* transmit FIFO threshold interrupt */
++#define FTSSP010_ICR_RFDMA      (1 << 4)        /* receive  DMA request */
++#define FTSSP010_ICR_TFDMA      (1 << 5)        /* transmit DMA request */
++#define FTSSP010_ICR_AC97FCEN       (1 << 6)    /* AC97 frame complete  */
++#define FTSSP010_ICR_RFTHOD(x)      (((x) & 0x1f) << 7)  /* receive  FIFO threshold */
++#define FTSSP010_ICR_TFTHOD(x)      (((x) & 0xf) << 12) /* transmit FIFO threshold */
++
++/*
++ * Interrupt Status Register
++ */
++#define FTSSP010_ISR_RFOR       (1 << 0)        /* receive  FIFO overrun  */
++#define FTSSP010_ISR_TFUR       (1 << 1)        /* transmit FIFO underrun */
++#define FTSSP010_ISR_RFTH       (1 << 2)        /* receive  FIFO threshold */
++#define FTSSP010_ISR_TFTH       (1 << 3)        /* transmit FIFO threshold */
++#define FTSSP010_ISR_AC97FC     (1 << 4)        /* AC97 frame complete */
++
++/*
++ * AC-Link Slot Valid Register
++ */
++#define FTSSP010_ACLSV_CODECID(x)   (((x) & 0x3) << 0)
++#define FTSSP010_ACLSV_SLOT12V      (1 << 3)
++#define FTSSP010_ACLSV_SLOT11V      (1 << 4)
++#define FTSSP010_ACLSV_SLOT10V      (1 << 5)
++#define FTSSP010_ACLSV_SLOT9V       (1 << 6)
++#define FTSSP010_ACLSV_SLOT8V       (1 << 7)
++#define FTSSP010_ACLSV_SLOT7V       (1 << 8)
++#define FTSSP010_ACLSV_SLOT6V       (1 << 9)
++#define FTSSP010_ACLSV_SLOT5V       (1 << 10)
++#define FTSSP010_ACLSV_SLOT4V       (1 << 11)
++#define FTSSP010_ACLSV_SLOT3V       (1 << 12)
++#define FTSSP010_ACLSV_SLOT2V       (1 << 13)
++#define FTSSP010_ACLSV_SLOT1V       (1 << 14)
++
++/*
++ * Revision Register
++ */
++#define FTSSP010_REVISION_RELEASE(reg)  (((reg) >> 0) & 0xff)
++#define FTSSP010_REVISION_MINOR(reg)    (((reg) >> 8) & 0xff)
++#define FTSSP010_REVISION_MAJOR(reg)    (((reg) >> 16) & 0xff)
++
++/*
++ * Feature Register
++ */
++#define FTSSP010_FEATURE_WIDTH(reg)     (((reg) >>  0) & 0xff)
++#define FTSSP010_FEATURE_RXFIFO_DEPTH(reg)  (((reg) >>  8) & 0xff)
++#define FTSSP010_FEATURE_TXFIFO_DEPTH(reg)  (((reg) >> 16) & 0xff)
++#define FTSSP010_FEATURE_AC97           (1 << 24)
++#define FTSSP010_FEATURE_I2S            (1 << 25)
++#define FTSSP010_FEATURE_SPI_MWR        (1 << 26)
++#define FTSSP010_FEATURE_SSP            (1 << 27)
++
++enum FTSSP010_SPI_CS {
++    FTSSP010_SPI_CS_FIRST,
++    FTSSP010_SPI_CS_SECOND,
++    FTSSP010_SPI_CS_THIRD,
++    FTSSP010_SPI_CS_FOUR,
++    FTSSP010_SPI_CS_FIVE,
++    FTSSP010_SPI_CS_SIX,
++};
++
++struct ftssp010_spi_cs_descriptor {
++    enum FTSSP010_SPI_CS cs;
++    u8 enable;
++};
++
++struct ftssp010_spi;
++
++struct ftssp010_spi_hw_platform {
++    u8 nr_chip_select; // the max number of chip select
++    u32 working_clk; // current SPI controller's working clock, only valid after hw_init, otherwise will be 0
++    int rx_dma_ch;
++    int tx_dma_ch;
++    int hw_rx_dma_pin;
++    int hw_tx_dma_pin;
++};
++
++/** 
++ * @brief this structure resides in spi private data to indicate controller info 
++ */
++struct ftssp010_spi {
++    u8 controller_id;
++    spinlock_t lock;
++    void __iomem *base;
++    u32 pbase;
++    int irq;
++    int rxfifo_depth;
++    struct spi_master *master;
++    struct workqueue_struct *workqueue;
++    struct work_struct work;
++    wait_queue_head_t waitq;
++    struct list_head message_queue;
++    struct ftssp010_spi_hw_platform *hw_platform;
++};
++
++struct ftssp010_spi_hw_platform *ftssp010_spi_get_hw_platform(u8 controller_id);
++void ftssp010_spi_free_hw_platform(struct ftssp010_spi_hw_platform *hw_platform);
++
++#endif //end of __FTSSP010_SPI_H__
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index b2ccdea3..7df0520f 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -838,7 +838,7 @@ EXPORT_SYMBOL_GPL(spi_async);
+ /**
+  * spi_async_locked - version of spi_async with exclusive bus usage
+  * @spi: device with which data will be exchanged
+- * @message: describes the data transfers, including completion callback
++* @message: describes the data transfers, including completion callback
+  * Context: any (irqs may be blocked, etc)
+  *
+  * This call may be used in_irq and other contexts which can't sleep,
+@@ -1121,6 +1121,7 @@ static int __init spi_init(void)
+ 	status = class_register(&spi_master_class);
+ 	if (status < 0)
+ 		goto err2;
++
+ 	return 0;
+ 
+ err2:
+diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
+index 9b7336fc..6eeab969 100644
+--- a/drivers/tty/serial/8250/8250.c
++++ b/drivers/tty/serial/8250/8250.c
+@@ -41,13 +41,19 @@
+ 
+ #include <asm/io.h>
+ #include <asm/irq.h>
++#include <asm/cputype.h>
+ 
+ #include "8250.h"
++#include <mach/ftpmu010.h>
+ 
+ #ifdef CONFIG_SPARC
+ #include "../suncore.h"
+ #endif
+ 
++#ifdef CONFIG_SERIAL_CTSRTS
++#include <linux/gpio.h>
++#endif
++
+ /*
+  * Configuration:
+  *   share_irqs - whether we pass IRQF_SHARED to request_irq().  This option
+@@ -140,6 +146,11 @@ struct irq_info {
+ static struct hlist_head irq_lists[NR_IRQ_HASH];
+ static DEFINE_MUTEX(hash_mutex);	/* Used to walk the hash */
+ 
++#ifdef CONFIG_SERIAL_CTSRTS
++#define RTS_PIN 28
++#define CTS_PIN 29
++static unsigned char tx_stop = 0;
++#endif
+ /*
+  * Here we define the default xmit fifo size used for each type of UART.
+  */
+@@ -168,7 +179,11 @@ static const struct serial8250_config uart_config[] = {
+ 		.name		= "16550A",
+ 		.fifo_size	= 16,
+ 		.tx_loadsz	= 16,
++#ifdef CONFIG_SERIAL_CTSRTS
++		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
++#else
+ 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
++#endif
+ 		.flags		= UART_CAP_FIFO,
+ 	},
+ 	[PORT_CIRRUS] = {
+@@ -292,6 +307,122 @@ static const struct serial8250_config uart_config[] = {
+ 	},
+ };
+ 
++#if CONFIG_SERIAL_8250_RUNTIME_UARTS >= 2
++static int uart_fd = -1;
++
++static pmuReg_t regUARTArray[] = {
++    /* reg_off      bit_masks       lock_bits       init_val        init_mask */
++#ifdef CONFIG_PLATFORM_GM8210
++    {0xB8,          (0x1 << 0),    (0x1 << 0),    (0x0 << 0),    (0x1 << 0)},   // uart0 clk on
++    {0x58,          (0x1 << 8), 	 (0x1 << 8), 	  (0x0 << 8), 	 (0x1 << 8)},   // uart1 pinmux, uart1 for 626
++    {0xB8,          (0x1 << 1),    (0x1 << 1),    (0x0 << 1),    (0x1 << 1)},   // uart1 clk on
++#ifdef CONFIG_SERIAL_UART2_IP
++    {0x58,          (0x3 << 12), 	 (0x3 << 12), 	(0x0 << 12), 	 (0x3 << 12)},  // uart2 pinmux
++    {0xB8,          (0x1 << 2),    (0x1 << 2),    (0x0 << 2),    (0x1 << 2)},   // uart2 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART3_IP
++    {0x58,          (0x3 << 16), 	 (0x3 << 16), 	(0x0 << 16), 	 (0x3 << 16)},  // uart3 pinmux
++    {0xB8,          (0x1 << 3),    (0x1 << 3),    (0x0 << 3),    (0x1 << 3)},   // uart3 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART4_IP
++    {0x58,          (0x3 << 20), 	 (0x3 << 20), 	(0x0 << 20), 	 (0x3 << 20)},  // uart4 pinmux
++    {0xB8,          (0x1 << 4),    (0x1 << 4),    (0x0 << 4),    (0x1 << 4)},   // uart4 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART5_IP
++    {0x4C,          (0x3 << 6),    (0x3 << 6),    (0x0 << 6),    (0x3 << 6)},   // uart5 pinmux for 7500
++    {0xB8,          (0x1 << 5),    (0x1 << 5),    (0x0 << 5),    (0x1 << 5)},   // uart5 clk on
++#endif
++#endif //#ifdef CONFIG_PLATFORM_GM8210
++
++#ifdef CONFIG_PLATFORM_GM8287
++    {0xB8,          (0x1 << 0),    (0x1 << 0),    (0x0 << 0),    (0x1 << 0)},   // uart0 clk on
++#ifdef CONFIG_SERIAL_UART1_IP
++    {0x58,          (0x1 << 8), 	 (0x1 << 8), 	  (0x0 << 8), 	 (0x1 << 8)},   // uart1 pinmux
++    {0xB8,          (0x1 << 1),    (0x1 << 1),    (0x0 << 1),    (0x1 << 1)},   // uart1 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART2_IP
++    {0x58,          (0x3 << 12), 	 (0x3 << 12), 	(0x0 << 12), 	 (0x3 << 12)},  // uart2 pinmux
++    {0xB8,          (0x1 << 2),    (0x1 << 2),    (0x0 << 2),    (0x1 << 2)},   // uart2 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART3_IP
++#if 1
++    {0x5C,          (0x3 << 14),   (0x3 << 14),   (0x2 << 14),   (0x3 << 14)},  // uart3 pinmux
++#else
++    {0x5C,          (0x3 << 18),   (0x3 << 18),   (0x1 << 18),   (0x3 << 18)},  // uart3 pinmux, default irda use it. For uart function, field [15:14] and [19:18] only select one to use
++#endif
++    {0xB8,          (0x1 << 3),    (0x1 << 3),    (0x0 << 3),    (0x1 << 3)},   // uart3 clk on
++#endif
++#endif //#ifdef CONFIG_PLATFORM_GM8287
++
++#ifdef CONFIG_PLATFORM_GM8139
++    {0x58,          (0xF << 28), 	 (0xF << 28), 	(0x5 << 28), 	 (0xF << 28)},  // uart0 pinmux
++    {0xB8,          (0x1 << 0),    (0x1 << 0),    (0x0 << 0),    (0x1 << 0)},   // uart0 clk on
++#ifdef CONFIG_SERIAL_UART1_IP
++    {0x64,          (0xF << 2), 	 (0xF << 2), 	  (0xA << 2), 	 (0xF << 2)},   // uart1 pinmux
++    {0xB8,          (0x1 << 1),    (0x1 << 1),    (0x0 << 1),    (0x1 << 1)},   // uart1 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART2_IP
++    {0x58,          (0xF << 24), 	 (0xF << 24), 	(0xF << 24), 	 (0xF << 24)},  // uart2 pinmux
++    {0xB8,          (0x1 << 2),    (0x1 << 2),    (0x0 << 2),    (0x1 << 2)},   // uart2 clk on
++#endif
++#endif //#ifdef CONFIG_PLATFORM_GM8139
++
++#ifdef CONFIG_PLATFORM_GM8136
++    {0x58,          (0xF << 28), 	 (0xF << 28), 	(0x5 << 28), 	 (0xF << 28)},  // uart0 pinmux
++    {0xB8,          (0x1 << 0),    (0x1 << 0),    (0x0 << 0),    (0x1 << 0)},   // uart0 clk on
++#ifdef CONFIG_SERIAL_UART1_IP
++    {0x64,          (0xF << 2), 	 (0xF << 2), 	  (0xA << 2), 	 (0xF << 2)},   // uart1 pinmux
++    {0xB8,          (0x1 << 1),    (0x1 << 1),    (0x0 << 1),    (0x1 << 1)},   // uart1 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART2_IP
++    {0x58,          (0xF << 24), 	 (0xF << 24), 	(0x5 << 24), 	 (0xF << 24)},  // uart2 pinmux
++    {0xB8,          (0x1 << 2),    (0x1 << 2),    (0x0 << 2),    (0x1 << 2)},   // uart2 clk on
++#endif
++#endif //#ifdef CONFIG_PLATFORM_GM8136
++
++#ifdef CONFIG_PLATFORM_GM8220
++    {0x1A8,          (0xF << 6), 	 (0xF << 6), 	(0x5 << 6), 	 (0xF << 6)},  // uart0 pinmux
++    {0x78,          (0x1 << 2),    (0x1 << 2),    (0x0 << 2),    (0x1 << 2)},   // uart0 clk on
++#ifdef CONFIG_SERIAL_UART1_IP
++    {0x1A8,          (0xF << 10), 	 (0xF << 10), 	(0x5 << 10), 	 (0xF << 10)},   // uart1 pinmux
++    {0x78,          (0x1 << 3),    (0x1 << 3),    (0x0 << 3),    (0x1 << 3)},   // uart1 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART2_IP
++    {0x1A8,          (0xF << 14), 	 (0xF << 14), 	(0x5 << 14), 	 (0xF << 14)},  // uart2 pinmux
++    {0x78,          (0x1 << 4),    (0x1 << 4),    (0x0 << 4),    (0x1 << 4)},   // uart2 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART3_IP
++    {0x1A8,          (0xF << 18), 	 (0xF << 18), 	(0x5 << 18), 	 (0xF << 18)},   // uart3 pinmux
++    {0x78,          (0x1 << 5),    (0x1 << 5),    (0x0 << 5),    (0x1 << 5)},   // uart3 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART4_IP
++    {0x1A8,          (0xF << 22), 	 (0xF << 22), 	(0x5 << 22), 	 (0xF << 22)},  // uart4 pinmux
++    {0x78,          (0x1 << 6),    (0x1 << 6),    (0x0 << 6),    (0x1 << 6)},   // uart4 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART5_IP
++    {0x1A8,          (0xF << 26), 	 (0xF << 26), 	(0x5 << 26), 	 (0xF << 26)},   // uart5 pinmux
++    {0x78,          (0x1 << 7),    (0x1 << 7),    (0x0 << 7),    (0x1 << 7)},   // uart5 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART6_IP
++    {0x1A8,          (0x3 << 30), 	 (0x3 << 30), 	(0x1 << 30), 	 (0x3 << 30)},  // uart6 pinmux
++    {0x1AC,          (0x3 << 0), 	 (0x3 << 0), 	(0x1 << 0), 	 (0x3 << 0)},
++    {0x78,          (0x1 << 8),    (0x1 << 8),    (0x0 << 8),    (0x1 << 8)},   // uart6 clk on
++#endif
++#ifdef CONFIG_SERIAL_UART7_IP
++    {0x1AC,          (0xF << 2), 	 (0xF << 2), 	(0x5 << 2), 	 (0xF << 2)},   // uart7 pinmux
++    {0x78,          (0x1 << 9),    (0x1 << 9),    (0x0 << 9),    (0x1 << 9)},   // uart7 clk on
++#endif
++#endif //#ifdef CONFIG_PLATFORM_GM8220
++};
++
++static pmuRegInfo_t uart_clk_pinmux_info = {
++    "uart_clk_pinmux",
++    ARRAY_SIZE(regUARTArray),
++    ATTR_TYPE_NONE,
++    regUARTArray
++};
++#endif
++
+ #if defined(CONFIG_MIPS_ALCHEMY)
+ 
+ /* Au1x00 UART hardware has a weird register layout */
+@@ -374,6 +505,18 @@ static inline int map_8250_out_reg(struct uart_port *p, int offset)
+ 
+ #endif
+ 
++#ifdef CONFIG_PLATFORM_GM8210
++static inline u32 get_cpu_id(void)
++{
++    static u32 cpu_id = 0;
++
++    if (!cpu_id)
++        cpu_id = (read_cpuid_id() >> 0x4) & 0xFFF;
++
++    return cpu_id;
++}
++#endif
++
+ static unsigned int hub6_serial_in(struct uart_port *p, int offset)
+ {
+ 	offset = map_8250_in_reg(p, offset) << p->regshift;
+@@ -564,7 +707,7 @@ static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
+ 	serial_out(up, UART_SCR, offset);
+ 	serial_out(up, UART_ICR, value);
+ }
+-
++#if !defined(CONFIG_ARCH_GM) && !defined(CONFIG_ARCH_GM_DUO) && !defined(CONFIG_ARCH_GM_SMP)
+ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
+ {
+ 	unsigned int value;
+@@ -576,7 +719,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
+ 
+ 	return value;
+ }
+-
++#endif
+ /*
+  * FIFO support.
+  */
+@@ -685,6 +828,7 @@ static void disable_rsa(struct uart_8250_port *up)
+  * This is a quickie test to see how big the FIFO is.
+  * It doesn't work at all the time, more's the pity.
+  */
++#if !defined(CONFIG_ARCH_GM) && !defined(CONFIG_ARCH_GM_DUO) && !defined(CONFIG_ARCH_GM_SMP)
+ static int size_fifo(struct uart_8250_port *up)
+ {
+ 	unsigned char old_fcr, old_mcr, old_lcr;
+@@ -865,14 +1009,14 @@ static int broken_efr(struct uart_8250_port *up)
+ 	/*
+ 	 * Exar ST16C2550 "A2" devices incorrectly detect as
+ 	 * having an EFR, and report an ID of 0x0201.  See
+-	 * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html 
++	 * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html
+ 	 */
+ 	if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16)
+ 		return 1;
+ 
+ 	return 0;
+ }
+-
++#endif
+ static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
+ {
+ 	unsigned char status;
+@@ -896,6 +1040,7 @@ static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
+  * we know the top two bits of the IIR are currently set.  The
+  * EFR should contain zero.  Try to read the EFR.
+  */
++#if !defined(CONFIG_ARCH_GM) && !defined(CONFIG_ARCH_GM_DUO) && !defined(CONFIG_ARCH_GM_SMP)
+ static void autoconfig_16550a(struct uart_8250_port *up)
+ {
+ 	unsigned char status1, status2;
+@@ -1049,6 +1194,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
+ 		up->capabilities |= UART_CAP_AFE;
+ 	}
+ }
++#endif
+ 
+ /*
+  * This routine is called by rs_init() to initialize a specific serial
+@@ -1057,6 +1203,17 @@ static void autoconfig_16550a(struct uart_8250_port *up)
+  * whether or not this UART is a 16550A or not, since this will
+  * determine whether or not we can use its FIFO features or not.
+  */
++// Luke Lee 04/28/2005 ins #if block
++#if defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP)
++static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
++{
++    	up->port.type = PORT_16550A;
++	up->bugs = 0;
++	serial_outp(up, UART_IER, 0x0F);
++
++    	return ;
++}
++#else
+ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
+ {
+ 	unsigned char status1, scratch, scratch2, scratch3;
+@@ -1150,8 +1307,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
+ 	 * We also initialise the EFR (if any) to zero for later.  The
+ 	 * EFR occupies the same register location as the FCR and IIR.
+ 	 */
++#ifndef CONFIG_SERIAL_8250_FTUART010	/* FTUART010 does not have EFR */
+ 	serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ 	serial_outp(up, UART_EFR, 0);
++#endif
+ 	serial_outp(up, UART_LCR, 0);
+ 
+ 	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+@@ -1226,6 +1385,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
+ 	spin_unlock_irqrestore(&up->port.lock, flags);
+ 	DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
+ }
++#endif
+ 
+ static void autoconfig_irq(struct uart_8250_port *up)
+ {
+@@ -1315,8 +1475,35 @@ static void serial8250_start_tx(struct uart_port *port)
+ 			up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+ 			if ((up->port.type == PORT_RM9000) ?
+ 				(lsr & UART_LSR_THRE) :
+-				(lsr & UART_LSR_TEMT))
++				(lsr & UART_LSR_TEMT)) {
++
++#ifdef CONFIG_SERIAL_CTSRTS
++				{
++					ssize_t	status;
++					unsigned int tmout;
++			
++					if(up->port.irq == UART_FTUART010_2_IRQ) {
++						//printk("<w=0x%x>",gpio_get_value(CTS_PIN));
++						for (tmout = 1000000; tmout; tmout--) {
++							status = gpio_get_value(CTS_PIN); /* input */
++							if (!status)	/* CTS send must low */
++								break;
++		
++							udelay(1);
++						}
++						//printk("<e>");
++						if(!tmout) {
++							printk("Wait CTS low timeout, status = 0x%x", status);
++							tx_stop = 1;
++							return;
++						} else {
++							tx_stop = 0;
++						}
++					}
++				}
++#endif
+ 				serial8250_tx_chars(up);
++			}
+ 		}
+ 	}
+ 
+@@ -1450,6 +1637,10 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
+ 		if (uart_handle_sysrq_char(&up->port, ch))
+ 			goto ignore_char;
+ 
++#ifdef CONFIG_SERIAL_CTSRTS
++		if(up->port.irq == UART_FTUART010_2_IRQ)
++			gpio_direction_output(RTS_PIN, 1); /* output high to stop receive */
++#endif
+ 		uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+ 
+ ignore_char:
+@@ -1457,7 +1648,15 @@ ignore_char:
+ 	} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+ 	spin_unlock(&up->port.lock);
+ 	tty_flip_buffer_push(tty);
++
++#ifdef CONFIG_SERIAL_CTSRTS
++		if(up->port.irq == UART_FTUART010_2_IRQ) {
++			//printk("<r>");
++			gpio_direction_output(RTS_PIN, 0); /* output low to resume */
++		}
++#endif
+ 	spin_lock(&up->port.lock);
++
+ 	return lsr;
+ }
+ EXPORT_SYMBOL_GPL(serial8250_rx_chars);
+@@ -1467,6 +1666,11 @@ void serial8250_tx_chars(struct uart_8250_port *up)
+ 	struct circ_buf *xmit = &up->port.state->xmit;
+ 	int count;
+ 
++#ifdef CONFIG_SERIAL_CTSRTS
++	if((tx_stop) && (up->port.irq == UART_FTUART010_2_IRQ))
++		return;
++#endif
++
+ 	if (up->port.x_char) {
+ 		serial_outp(up, UART_TX, up->port.x_char);
+ 		up->port.icount.tx++;
+@@ -2060,7 +2264,12 @@ static int serial8250_startup(struct uart_port *port)
+ 		 * If the interrupt is not reasserted, setup a timer to
+ 		 * kick the UART on a regular basis.
+ 		 */
++/* lichun modify: when kernel boot-up, some last message can't show on terminal */
++#if defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP)
++		if (iir & UART_IIR_NO_INT) {
++#else
+ 		if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) {
++#endif
+ 			up->bugs |= UART_BUG_THRE;
+ 			pr_debug("ttyS%d - using backup timer\n",
+ 				 serial_index(port));
+@@ -2645,6 +2854,7 @@ static void serial8250_config_port(struct uart_port *port, int flags)
+ 
+ 	if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)
+ 		serial8250_release_rsa_resource(up);
++
+ 	if (up->port.type == PORT_UNKNOWN)
+ 		serial8250_release_std_resource(up);
+ }
+@@ -2741,10 +2951,23 @@ static void __init serial8250_isa_init_ports(void)
+ 	for (i = 0, up = serial8250_ports;
+ 	     i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
+ 	     i++, up++) {
++#ifdef CONFIG_PLATFORM_GM8210
++        /* for fa626, map UART1 to ttyS0 and skip others */
++        if (get_cpu_id() == 0x626) {
++            if (i == 0)
++                i = 1;
++            else
++                continue;
++        }
++#endif
+ 		up->port.iobase   = old_serial_port[i].port;
+ 		up->port.irq      = irq_canonicalize(old_serial_port[i].irq);
+ 		up->port.irqflags = old_serial_port[i].irqflags;
++#ifdef CONFIG_PLATFORM_GM8136
++        up->port.uartclk  = ft_get_uartclk();
++#else
+ 		up->port.uartclk  = old_serial_port[i].baud_base * 16;
++#endif
+ 		up->port.flags    = old_serial_port[i].flags;
+ 		up->port.hub6     = old_serial_port[i].hub6;
+ 		up->port.membase  = old_serial_port[i].iomem_base;
+@@ -2782,6 +3005,24 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+ 	for (i = 0; i < nr_uarts; i++) {
+ 		struct uart_8250_port *up = &serial8250_ports[i];
+ 
++#ifdef CONFIG_SERIAL_8250_FTUART010
++        /*
++         * Skip adding unconfigured device node to make one-one mapping
++         * with hardware naming.
++         */
++        if (up->port.iobase == 0)
++            continue;
++
++#ifdef CONFIG_PLATFORM_GM8210
++        /* UART1 is used by fa626 as default console, skip it for fa726 */
++        if ((get_cpu_id() == 0x726) && (i == 1))
++            continue;
++        /* for fa626, UART1 is already mapped to ttyS0, register ttyS0 only */
++        if ((get_cpu_id() == 0x626) && (i != 0))
++            continue;
++#endif
++#endif
++
+ 		up->port.dev = dev;
+ 
+ 		if (up->port.flags & UPF_FIXED_TYPE)
+@@ -3271,6 +3512,54 @@ static int __init serial8250_init(void)
+ 		"%d ports, IRQ sharing %sabled\n", nr_uarts,
+ 		share_irqs ? "en" : "dis");
+ 
++#if CONFIG_SERIAL_8250_RUNTIME_UARTS >= 2
++    /* register UART to pmu core */
++    uart_fd = ftpmu010_register_reg(&uart_clk_pinmux_info);
++    if (unlikely(uart_fd < 0)){
++        printk("UART registers to PMU fail! \n");
++        ret = uart_fd;
++        goto out;
++    }
++///////////////
++#ifdef CONFIG_PLATFORM_GM8210
++#ifdef CONFIG_SERIAL_UART2_IP
++    ftpmu010_write_reg(uart_fd, 0x58, 0, (0x3 << 12));
++    ftpmu010_write_reg(uart_fd, 0xB8, 0, (0x1 << 2));
++#endif
++#ifdef CONFIG_SERIAL_UART3_IP
++    ftpmu010_write_reg(uart_fd, 0x58, 0, (0x3 << 16));
++    ftpmu010_write_reg(uart_fd, 0xB8, 0, (0x1 << 3));
++#endif
++#ifdef CONFIG_SERIAL_UART4_IP
++    ftpmu010_write_reg(uart_fd, 0x58, 0, (0x3 << 20));
++    ftpmu010_write_reg(uart_fd, 0xB8, 0, (0x1 << 4));
++#endif
++#endif
++///////////////
++#ifdef CONFIG_SERIAL_CTSRTS
++	printk("Enable CTS-RTS mode\n");
++
++	/* RTS */
++    if ((ret = gpio_request(RTS_PIN, "RTS_PIN")) != 0) {
++    	printk("Request GPIO%d fail! \n", RTS_PIN);
++    	goto out;
++    }
++    /* CTS */
++    if ((ret = gpio_request(CTS_PIN, "CTS_PIN")) != 0) {
++    	printk("Request GPIO%d fail! \n", CTS_PIN);
++    	goto out;
++    }
++    
++    if ((ret = gpio_direction_input(CTS_PIN)) != 0) {
++    	printk("GPIO%d set input fail! \n", CTS_PIN);
++    	goto out;
++    }
++    
++    gpio_direction_output(RTS_PIN, 0); /* initial output low */
++#endif
++
++#endif
++
+ #ifdef CONFIG_SPARC
+ 	ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+ #else
+diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
+index eaafb98d..04a8fc19 100644
+--- a/drivers/tty/serial/8250/8250_early.c
++++ b/drivers/tty/serial/8250/8250_early.c
+@@ -3,7 +3,9 @@
+  *
+  * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
+  *	Bjorn Helgaas <bjorn.helgaas@hp.com>
+- *
++ * Copyright (C) 2005 Faraday Corp.
++ *	Luke Lee, modified for register offset shifts.
++
+  * 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.
+@@ -24,6 +26,20 @@
+  *	console=uart8250,io,0x3f8,9600n8
+  *	console=uart8250,mmio,0xff5e0000,115200n8
+  *	console=uart8250,mmio32,0xff5e0000,115200n8
++ *
++ * If the baudrate is not specified, current baud will be probed.
++ * e.g.,
++ *	console=uart,io,0x3f8
++ *	console=uart,mmio,0xff5e0000
++ *
++ * The optional "shift,n" is used to indicate how many bits should
++ * be shifted for the register offset. For some systems like Faraday's
++ * UART IP, each register is 4-bytes long which is different from
++ * standard 16550A UART 1-byte register, but they are actually
++ * compatible as long as register offsets shifted left by 2 bits.
++ * e.g.
++ *	console=uart,shift,2,io,0xf9820000,115200n8
++ *	console=uart,shift,2,mmio,0xff5e000         (auto probe baud)
+  */
+ 
+ #include <linux/tty.h>
+@@ -50,6 +66,7 @@ static struct early_serial8250_device early_device;
+ 
+ static unsigned int __init serial_in(struct uart_port *port, int offset)
+ {
++	offset <<= port->regshift;
+ 	switch (port->iotype) {
+ 	case UPIO_MEM:
+ 		return readb(port->membase + offset);
+@@ -64,6 +81,7 @@ static unsigned int __init serial_in(struct uart_port *port, int offset)
+ 
+ static void __init serial_out(struct uart_port *port, int offset, int value)
+ {
++	offset <<= port->regshift;
+ 	switch (port->iotype) {
+ 	case UPIO_MEM:
+ 		writeb(value, port->membase + offset);
+@@ -159,6 +177,13 @@ static int __init parse_options(struct early_serial8250_device *device,
+ 
+ 	port->uartclk = BASE_BAUD * 16;
+ 
++	if (!strncmp(options, "shift,",6)) {
++		options += 6;
++		port->regshift = simple_strtoul(options, 0, 0);
++		options = strchr(options, ',') + 1;
++	} else
++		port->regshift = 0;
++
+ 	mmio = !strncmp(options, "mmio,", 5);
+ 	mmio32 = !strncmp(options, "mmio32,", 7);
+ 	if (mmio || mmio32) {
+@@ -203,15 +228,17 @@ static int __init parse_options(struct early_serial8250_device *device,
+ 
+ 	if (mmio || mmio32)
+ 		printk(KERN_INFO
+-		       "Early serial console at MMIO%s 0x%llx (options '%s')\n",
++			"Early serial console at MMIO%s 0x%llx (options '%s', shift %d)\n",
+ 			mmio32 ? "32" : "",
+ 			(unsigned long long)port->mapbase,
+-			device->options);
++			device->options,
++			port->regshift);
+ 	else
+ 		printk(KERN_INFO
+-		      "Early serial console at I/O port 0x%lx (options '%s')\n",
++			"Early serial console at I/O port 0x%lx (options '%s', shift %d)\n",
+ 			port->iobase,
+-			device->options);
++			device->options,
++			port->regshift);
+ 
+ 	return 0;
+ }
+diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
+index 591f8018..d94b0e1a 100644
+--- a/drivers/tty/serial/8250/Kconfig
++++ b/drivers/tty/serial/8250/Kconfig
+@@ -133,6 +133,54 @@ config SERIAL_8250_RUNTIME_UARTS
+ 	  with the module parameter "nr_uarts", or boot-time parameter
+ 	  8250.nr_uarts
+ 
++config SERIAL_UART1_IP
++	bool "Use GM UART1 IP"
++	default n	
++	depends on SERIAL_8250 && !PLATFORM_GM8210
++	help
++	  Enable GM UART1 IP, please check pin mux issue
++
++config SERIAL_UART2_IP
++	bool "Use GM UART2 IP"
++	default n	
++	depends on SERIAL_8250
++	help
++	  Enable GM UART2 IP, please check pin mux issue
++
++config SERIAL_UART3_IP
++	bool "Use GM UART3 IP"
++	default n	
++	depends on SERIAL_8250
++	help
++	  Enable GM UART3 IP, please check pin mux issue
++
++config SERIAL_UART4_IP
++	bool "Use GM UART4 IP"
++	default n	
++	depends on SERIAL_8250
++	help
++	  Enable GM UART4 IP, please check pin mux issue
++
++config SERIAL_UART5_IP
++	bool "Use GM UART5 IP"
++	default n	
++	depends on SERIAL_8250
++	help
++	  Enable GM UART5 IP, please check pin mux issue
++
++config SERIAL_UART6_IP
++	bool "Use GM UART6 IP"
++	default n	
++	depends on SERIAL_8250 && PLATFORM_GM8220
++	help
++	  Enable GM UART6 IP, please check pin mux issue
++
++config SERIAL_UART7_IP
++	bool "Use GM UART7 IP"
++	default n	
++	depends on SERIAL_8250 && PLATFORM_GM8220
++	help
++	  Enable GM UART7 IP, please check pin mux issue
+ config SERIAL_8250_EXTENDED
+ 	bool "Extended 8250/16550 serial driver options"
+ 	depends on SERIAL_8250
+@@ -258,6 +306,14 @@ config SERIAL_8250_ACORN
+ 	  system, say Y to this option.  The driver can handle 1, 2, or 3 port
+ 	  cards.  If unsure, say N.
+ 
++config SERIAL_8250_FTUART010
++	bool "Faraday FTUART010 serial port support"
++	depends on SERIAL_8250
++	help
++	  If you have an Faraday SOC based board and want to use the serial port,
++	  say Y to this option. The driver can handle up to 4 serial ports,
++	  depending on the SOC. If unsure, say N.
++
+ config SERIAL_8250_RM9K
+ 	bool "Support for MIPS RM9xxx integrated serial port"
+ 	depends on SERIAL_8250 != n && SERIAL_RM9000
+diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
+index 9314d93c..0f3e7836 100644
+--- a/drivers/tty/tty_ioctl.c
++++ b/drivers/tty/tty_ioctl.c
+@@ -539,7 +539,9 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
+ 			wake_up_interruptible(&tty->link->read_wait);
+ 		}
+ 	}
+-
++#if (defined(CONFIG_PLATFORM_GM8136) || defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8210) || defined(CONFIG_PLATFORM_GM8287))
++	tty->termios->c_cflag &= ~CRTSCTS;
++#endif
+ 	if (tty->ops->set_termios)
+ 		(*tty->ops->set_termios)(tty, &old_termios);
+ 	else
+diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
+index 75823a1a..8f27c3f7 100644
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -76,6 +76,9 @@ config USB_ARCH_HAS_EHCI
+ 	default y if MICROBLAZE
+ 	default y if SPARC_LEON
+ 	default y if ARCH_MMP
++	default y if ARCH_GM
++	default y if ARCH_GM_DUO
++	default y if ARCH_GM_SMP
+ 	default PCI
+ 
+ # some non-PCI HCDs implement xHCI
+@@ -94,7 +97,7 @@ config USB
+ 	  traditional PC serial port.  The bus supplies power to peripherals
+ 	  and allows for hot swapping.  Up to 127 USB peripherals can be
+ 	  connected to a single USB host in a tree structure.
+-	  
++
+ 	  The USB host is the root of the tree, the peripherals are the
+ 	  leaves and the inner nodes are special USB devices called hubs.
+ 	  Most PCs now have USB host ports, used to connect peripherals
+diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
+index 53a7bc07..8b872820 100644
+--- a/drivers/usb/Makefile
++++ b/drivers/usb/Makefile
+@@ -14,6 +14,8 @@ obj-$(CONFIG_USB_MON)		+= mon/
+ 
+ obj-$(CONFIG_PCI)		+= host/
+ obj-$(CONFIG_USB_EHCI_HCD)	+= host/
++obj-$(CONFIG_GM_FUSBH200)	+= host/
++obj-$(CONFIG_GM_FOTG2XX)	+= host/
+ obj-$(CONFIG_USB_ISP116X_HCD)	+= host/
+ obj-$(CONFIG_USB_OHCI_HCD)	+= host/
+ obj-$(CONFIG_USB_UHCI_HCD)	+= host/
+diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
+index e1282328..41011884 100644
+--- a/drivers/usb/core/hcd.c
++++ b/drivers/usb/core/hcd.c
+@@ -6,7 +6,7 @@
+  * (C) Copyright Deti Fliegl 1999
+  * (C) Copyright Randy Dunlap 2000
+  * (C) Copyright David Brownell 2000-2002
+- * 
++ *
+  * 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
+@@ -44,6 +44,10 @@
+ 
+ #include "usb.h"
+ 
++#if defined(CONFIG_GM_FUSBH200) || defined(CONFIG_GM_FOTG2XX)
++#include "../host/fotg2xx-ehci-macro.h"
++#endif
++
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+@@ -206,13 +210,13 @@ static const u8 fs_rh_config_descriptor [] = {
+ 	0x01,       /*  __u8  bNumInterfaces; (1) */
+ 	0x01,       /*  __u8  bConfigurationValue; */
+ 	0x00,       /*  __u8  iConfiguration; */
+-	0xc0,       /*  __u8  bmAttributes; 
++	0xc0,       /*  __u8  bmAttributes;
+ 				 Bit 7: must be set,
+ 				     6: Self-powered,
+ 				     5: Remote wakeup,
+ 				     4..0: resvd */
+ 	0x00,       /*  __u8  MaxPower; */
+-      
++
+ 	/* USB 1.1:
+ 	 * USB 2.0, single TT organization (mandatory):
+ 	 *	one interface, protocol 0
+@@ -234,7 +238,7 @@ static const u8 fs_rh_config_descriptor [] = {
+ 	0x00,       /*  __u8  if_bInterfaceSubClass; */
+ 	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+ 	0x00,       /*  __u8  if_iInterface; */
+-     
++
+ 	/* one endpoint (status change endpoint) */
+ 	0x07,       /*  __u8  ep_bLength; */
+ 	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+@@ -253,13 +257,13 @@ static const u8 hs_rh_config_descriptor [] = {
+ 	0x01,       /*  __u8  bNumInterfaces; (1) */
+ 	0x01,       /*  __u8  bConfigurationValue; */
+ 	0x00,       /*  __u8  iConfiguration; */
+-	0xc0,       /*  __u8  bmAttributes; 
++	0xc0,       /*  __u8  bmAttributes;
+ 				 Bit 7: must be set,
+ 				     6: Self-powered,
+ 				     5: Remote wakeup,
+ 				     4..0: resvd */
+ 	0x00,       /*  __u8  MaxPower; */
+-      
++
+ 	/* USB 1.1:
+ 	 * USB 2.0, single TT organization (mandatory):
+ 	 *	one interface, protocol 0
+@@ -281,7 +285,7 @@ static const u8 hs_rh_config_descriptor [] = {
+ 	0x00,       /*  __u8  if_bInterfaceSubClass; */
+ 	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+ 	0x00,       /*  __u8  if_iInterface; */
+-     
++
+ 	/* one endpoint (status change endpoint) */
+ 	0x07,       /*  __u8  ep_bLength; */
+ 	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+@@ -2049,7 +2053,7 @@ static void hcd_resume_work(struct work_struct *work)
+ }
+ 
+ /**
+- * usb_hcd_resume_root_hub - called by HCD to resume its root hub 
++ * usb_hcd_resume_root_hub - called by HCD to resume its root hub
+  * @hcd: host controller for this root hub
+  *
+  * The USB host controller calls this function when its root hub is
+@@ -2112,6 +2116,19 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
+ #endif
+ 
+ /*-------------------------------------------------------------------------*/
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++static int is_hcd_irq = 0;
++void set_irq_is_hcd(int val)
++{
++	is_hcd_irq = val;
++}
++EXPORT_SYMBOL(set_irq_is_hcd);
++int get_irq_is_hcd(void)
++{
++	return is_hcd_irq;
++}
++EXPORT_SYMBOL(get_irq_is_hcd);
++#endif
+ 
+ /**
+  * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
+@@ -2125,7 +2142,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
+ {
+ 	struct usb_hcd		*hcd = __hcd;
+ 	unsigned long		flags;
+-	irqreturn_t		rc;
++	irqreturn_t		rc = IRQ_NONE;
+ 
+ 	/* IRQF_DISABLED doesn't work correctly with shared IRQs
+ 	 * when the first handler doesn't use it.  So let's just
+@@ -2133,9 +2150,12 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
+ 	 */
+ 	local_irq_save(flags);
+ 
+-	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
+-		rc = IRQ_NONE;
+-	else if (hcd->driver->irq(hcd) == IRQ_NONE)
++	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) {
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++		if (is_hcd_irq)
++#endif
++			rc = IRQ_NONE;
++	} else if (hcd->driver->irq(hcd) == IRQ_NONE)
+ 		rc = IRQ_NONE;
+ 	else
+ 		rc = IRQ_HANDLED;
+@@ -2519,7 +2539,7 @@ err_allocate_root_hub:
+ err_register_bus:
+ 	hcd_buffer_destroy(hcd);
+ 	return retval;
+-} 
++}
+ EXPORT_SYMBOL_GPL(usb_add_hcd);
+ 
+ /**
+@@ -2606,7 +2626,7 @@ struct usb_mon_operations *mon_ops;
+  * Notice that the code is minimally error-proof. Because usbmon needs
+  * symbols from usbcore, usbcore gets referenced and cannot be unloaded first.
+  */
+- 
++
+ int usb_mon_register (struct usb_mon_operations *ops)
+ {
+ 
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index 265c2f67..c3497f61 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -30,6 +30,9 @@
+ 
+ #include "usb.h"
+ 
++#include "../host/fotg2xx-ehci-macro.h"
++#include "../host/fotg2xx_opt-macro.h"
++
+ /* if we are in debug mode, always announce new devices */
+ #ifdef DEBUG
+ #ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
+@@ -608,7 +611,7 @@ static int hub_hub_status(struct usb_hub *hub,
+ 			"%s failed (err = %d)\n", __func__, ret);
+ 	else {
+ 		*status = le16_to_cpu(hub->status->hub.wHubStatus);
+-		*change = le16_to_cpu(hub->status->hub.wHubChange); 
++		*change = le16_to_cpu(hub->status->hub.wHubChange);
+ 		ret = 0;
+ 	}
+ 	mutex_unlock(&hub->status_mutex);
+@@ -2748,7 +2751,7 @@ EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+  * Between connect detection and reset signaling there must be a delay
+  * of 100ms at least for debounce and power-settling.  The corresponding
+  * timer shall restart whenever the downstream port detects a disconnect.
+- * 
++ *
+  * Apparently there are some bluetooth and irda-dongles and a number of
+  * low-speed devices for which this debounce period may last over a second.
+  * Not covered by the spec - but easy to deal with.
+@@ -2840,6 +2843,8 @@ static int hub_set_address(struct usb_device *udev, int devnum)
+ 	return retval;
+ }
+ 
++void ftusb_reset_host(struct usb_hcd *hcd);
++
+ /* Reset device, (re)assign address, get device descriptor.
+  * Device connection must be stable, no more debouncing needed.
+  * Returns device in USB_STATE_ADDRESS, except on error.
+@@ -2926,11 +2931,14 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
+ 	else
+ 		speed = usb_speed_string(udev->speed);
+ 
+-	if (udev->speed != USB_SPEED_SUPER)
+-		dev_info(&udev->dev,
+-				"%s %s USB device number %d using %s\n",
+-				(udev->config) ? "reset" : "new", speed,
+-				devnum, udev->bus->controller->driver->name);
++    /*  */
++    if (udev->speed != USB_SPEED_SUPER) {
++        if (!udev->config || udev->speed != USB_SPEED_LOW) // if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++            dev_info(&udev->dev,
++                    "%s %s USB device number %d using %s\n",
++                    (udev->config) ? "reset" : "new", speed,
++                    devnum, udev->bus->controller->driver->name);
++    }
+ 
+ 	/* Set up TT records, if needed  */
+ 	if (hdev->tt) {
+@@ -2946,7 +2954,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
+ 		udev->tt = &hub->tt;
+ 		udev->ttport = port1;
+ 	}
+- 
++
+ 	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
+ 	 * Because device hardware and firmware is sometimes buggy in
+ 	 * this area, and this is how Linux has done it for ages.
+@@ -2976,6 +2984,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
+ 			 * 512 (WUSB1.0[4.8.1]).
+ 			 */
+ 			for (j = 0; j < 3; ++j) {
++                //u32 temp = 0;
+ 				buf->bMaxPacketSize0 = 0;
+ 				r = usb_control_msg(udev, usb_rcvaddr0pipe(),
+ 					USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+@@ -2997,6 +3006,31 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
+ 				}
+ 				if (r == 0)
+ 					break;
++
++#if 0 //#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++                /* ZTE 3G dongle cause system died, need to restart host here. */
++                temp = *((volatile u32 *)(hcd->regs+0x10));
++                if (!(temp & 0x01) || (r == -ETIMEDOUT)) {
++                    printk("%s:%d, host controller is stopped\n", __func__, __LINE__);
++                    if (hdev == hdev->bus->root_hub) {
++                        printk("restart host controller\n");
++#if 1
++                        ftusb_reset_host(hcd);
++#else
++                        hcd->driver->stop(hcd);
++                        hcd->driver->reset(hcd);
++                        hcd->driver->start(hcd);
++#endif
++                        // force to reconnect device
++                        mdwOTGC_Control_A_BUS_REQ_Clr(hcd->regs);
++                        mdwOTGC_Control_A_BUS_DROP_Set(hcd->regs);
++                        mdwOTGC_Control_A_BUS_DROP_Clr(hcd->regs) ;
++                        mdwOTGC_Control_A_BUS_REQ_Set(hcd->regs);
++
++                        break;
++                    }
++                }
++#endif
+ 			}
+ 			udev->descriptor.bMaxPacketSize0 =
+ 					buf->bMaxPacketSize0;
+@@ -3090,7 +3124,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
+ 		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
+ 		usb_ep0_reinit(udev);
+ 	}
+-  
++
+ 	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
+ 	if (retval < (signed)sizeof(udev->descriptor)) {
+ 		dev_err(&udev->dev, "device descriptor read/all, error %d\n",
+@@ -3325,6 +3359,44 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
+ 		if (status < 0)
+ 			goto loop;
+ 
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++        /* workaround for bad mice */
++        if (!hdev->parent && !udev->config && udev->speed == USB_SPEED_LOW) {
++            static int f_toggle_vbus[5] = {1, 1, 1, 1 ,1};
++            int hcd_id = 0;
++
++            switch (hcd->rsrc_start) {
++                case USB_FOTG2XX_0_PA_BASE:
++                    hcd_id = 0;
++                    break;
++#if FOTG_DEV_NR >= 2
++                case USB_FOTG2XX_1_PA_BASE:
++                    hcd_id = 1;
++                    break;
++#endif
++#if FOTG_DEV_NR >= 3
++                case USB_FOTG2XX_2_PA_BASE:
++                    hcd_id = 2;
++                    break;
++#endif
++                default:
++                    panic("%s : Invalid HCD base\n", __func__);
++            }
++
++            if (f_toggle_vbus[hcd_id]) {
++                // force to reconnect device
++                dev_info(&udev->dev, ">>>> force to reconnect device on hcd %d\n", hcd_id);
++                mdwOTGC_Control_A_BUS_REQ_Clr(hcd->regs);
++                mdwOTGC_Control_A_BUS_DROP_Set(hcd->regs);
++                mdwOTGC_Control_A_BUS_DROP_Clr(hcd->regs) ;
++                mdwOTGC_Control_A_BUS_REQ_Set(hcd->regs);
++                f_toggle_vbus[hcd_id] = 0;
++                status = -ENOTCONN; // fake result for workaround
++                goto loop;
++            }
++        }
++#endif
++
+ 		usb_detect_quirks(udev);
+ 		if (udev->quirks & USB_QUIRK_DELAY_INIT)
+ 			msleep(1000);
+@@ -3359,7 +3431,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
+ 				goto loop_disable;
+ 			}
+ 		}
+- 
++
+ 		/* check for devices running slower than they could */
+ 		if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
+ 				&& udev->speed == USB_SPEED_FULL
+@@ -3417,7 +3489,17 @@ loop:
+ 			!(hcd->driver->port_handed_over)(hcd, port1))
+ 		dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
+ 				port1);
+- 
++
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++    if ((strncmp(hcd->self.bus_name, "fotg", 4) == 0) && !hdev->parent) {
++        // force to reconnect device
++        mdwOTGC_Control_A_BUS_REQ_Clr(hcd->regs);
++        mdwOTGC_Control_A_BUS_DROP_Set(hcd->regs);
++        mdwOTGC_Control_A_BUS_DROP_Clr(hcd->regs) ;
++        mdwOTGC_Control_A_BUS_REQ_Set(hcd->regs);
++    }
++#endif
++
+ done:
+ 	hub_port_disable(hub, port1, 1);
+ 	if (hcd->driver->relinquish_port && !hub->hdev->parent)
+@@ -3543,7 +3625,7 @@ static void hub_events(void)
+ 				 * EM interference sometimes causes badly
+ 				 * shielded USB devices to be shutdown by
+ 				 * the hub, this hack enables them again.
+-				 * Works at least with mouse driver. 
++				 * Works at least with mouse driver.
+ 				 */
+ 				if (!(portstatus & USB_PORT_STAT_ENABLE)
+ 				    && !connect_change
+@@ -3581,7 +3663,7 @@ static void hub_events(void)
+ 					"resume on port %d, status %d\n",
+ 					i, ret);
+ 			}
+-			
++
+ 			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+ 				u16 status = 0;
+ 				u16 unused;
+@@ -3904,7 +3986,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
+ 
+ 	if (ret < 0)
+ 		goto re_enumerate;
+- 
++
+ 	/* Device might have changed firmware (DFU or similar) */
+ 	if (descriptors_changed(udev, &descriptor)) {
+ 		dev_info(&udev->dev, "device firmware changed\n");
+@@ -3977,7 +4059,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
+ 
+ done:
+ 	return 0;
+- 
++
+ re_enumerate:
+ 	hub_port_logical_disconnect(parent_hub, port1);
+ 	return -ENODEV;
+diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
+index b3bdfede..a4a4119e 100644
+--- a/drivers/usb/core/message.c
++++ b/drivers/usb/core/message.c
+@@ -54,6 +54,9 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
+ 	if (unlikely(retval))
+ 		goto out;
+ 
++	//john, acrual_length is not initialized,
++	//once urb failed, may cause serious error
++	*actual_length=0;
+ 	expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
+ 	if (!wait_for_completion_timeout(&ctx.done, expire)) {
+ 		usb_kill_urb(urb);
+diff --git a/drivers/usb/gadget/GM_test.c b/drivers/usb/gadget/GM_test.c
+new file mode 100644
+index 00000000..e8a094dc
+--- /dev/null
++++ b/drivers/usb/gadget/GM_test.c
+@@ -0,0 +1,1743 @@
++/*
++ * zero.c -- Gadget Zero, for USB development
++ *
++ * Copyright (C) 2003-2004 David Brownell
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions, and the following disclaimer,
++ *    without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ *    to endorse or promote products derived from this software without
++ *    specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") as published by the Free Software
++ * Foundation, either version 2 of that License or (at your option) any
++ * later version.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++
++
++#define DEBUG 1
++// #define VERBOSE
++
++//#define BULK_USBS_DEBUG
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++//#include <linux/smp_lock.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/utsname.h>
++#include <linux/device.h>
++#include <linux/moduleparam.h>
++
++#include <asm/byteorder.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/unaligned.h>
++
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#include "gadget_chips.h"
++#include "../host/fotg2xx-config.h"
++#include "../host/fotg2xx.h"
++#include "../host/fotg2xx-ehci-macro.h"
++#include "../host/fotg2xx_opt-macro.h"
++#include "GM_udc.h"
++#include "GM_test.h"
++#include <linux/dma-mapping.h>
++
++/* ////////////////////////////////////////////////////////////////////////////////
++//
++//  Variables and definitions of System for Enumeration
++//
++//////////////////////////////////////////////////////////////////////////////// */
++
++
++/*-------------------------------------------------------------------------*/
++
++#define DRIVER_VERSION		"St Patrick's Day 2004"
++
++static const char shortname [] = "ftst";
++static const char longname [] = "Gadget Test";
++
++static const char source_sink [] = "source and sink data";
++static const char loopback [] = "Not support lookback" ;
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * driver assumes self-powered hardware, and
++ * has no way for users to trigger remote wakeup.
++ *
++ * this version autoconfigures as much as possible,
++ * which is reasonable for most "bulk-only" drivers.
++ */
++static const char *EP_BULK_IN_NAME;		/* source */
++static const char *EP_BULK_OUT_NAME;		/* sink */
++static const char *EP_INTR_IN_NAME;		/* source */
++static const char *EP_INTR_OUT_NAME;		/* sink */
++
++/*-------------------------------------------------------------------------*/
++
++/* big enough to hold our biggest descriptor */
++#define USB_BUFSIZ	256
++
++struct ftst_dev {
++	spinlock_t		lock;
++	struct usb_gadget	*gadget;
++	struct usb_request	*req;		/* for control responses */
++
++	/* when configured, we have one of two configs:
++	 * - source data (in to host) and sink it (out from host)
++	 * - or loop it back (out from host back in to host)
++	 */
++	u8			config;
++	struct usb_ep		*bulkin_ep, *bulkout_ep,*intrin_ep,*introut_ep;
++
++	/* autoresume timer */
++	struct timer_list	resume;
++};
++
++#ifdef xprintk
++#undef xprintk
++#endif
++#define xprintk(d,level,fmt,args...) \
++	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
++
++#ifdef DEBUG
++#define DBG(dev,fmt,args...) \
++	xprintk(dev , KERN_DEBUG , fmt , ## args)
++#else
++#define DBG(dev,fmt,args...) \
++	do { } while (0)
++#endif /* DEBUG */
++
++#ifdef VERBOSE
++#define VDBG	DBG
++#else
++#define VDBG(dev,fmt,args...) \
++	do { } while (0)
++#endif /* VERBOSE */
++
++#define ERROR(dev,fmt,args...) \
++	xprintk(dev , KERN_ERR , fmt , ## args)
++#define UWARN(dev,fmt,args...) \
++	xprintk(dev , KERN_WARNING , fmt , ## args)
++#define INFO(dev,fmt,args...) \
++	xprintk(dev , KERN_INFO , fmt , ## args)
++
++/*-------------------------------------------------------------------------*/
++
++static unsigned qlen = 32;
++static unsigned pattern = 0;
++
++/* module_param (buflen, uint, S_IRUGO|S_IWUSR); */
++module_param (qlen, uint, S_IRUGO|S_IWUSR);
++module_param (pattern, uint, S_IRUGO|S_IWUSR);
++
++/*
++ * if it's nonzero, autoresume says how many seconds to wait
++ * before trying to wake up the host after suspend.
++ */
++static unsigned autoresume = 0;
++module_param (autoresume, uint, 0);
++
++/*-------------------------------------------------------------------------*/
++
++/* Thanks to NetChip Technologies for donating this product ID.
++ *
++ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
++ * Instead:  allocate your own, using normal USB-IF procedures.
++ */
++#define DRIVER_VENDOR_NUM	0x2310		/* GM */
++#define DRIVER_PRODUCT_NUM	0x5678		/* Linux-USB "Gadget Zero" */
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * DESCRIPTORS ... most are static, but strings and (full)
++ * configuration descriptors are built on demand.
++ */
++
++#define STRING_MANUFACTURER		25
++#define STRING_PRODUCT			42
++#define STRING_SERIAL			101
++#define STRING_SOURCE_SINK		250
++#define STRING_LOOPBACK			251
++
++/*
++ * This device advertises two configurations; these numbers work
++ * on a pxa250 as well as more flexible hardware.
++ */
++#define	CONFIG_SOURCE_SINK	3
++#define	CONFIG_LOOPBACK		2
++
++static struct usb_device_descriptor
++device_desc = {
++	.bLength =		sizeof device_desc,
++	.bDescriptorType =	USB_DT_DEVICE,
++
++	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
++	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,
++
++	.idVendor =		__constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
++	.idProduct =		__constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
++	.iManufacturer =	STRING_MANUFACTURER,
++	.iProduct =		STRING_PRODUCT,
++	.iSerialNumber =	STRING_SERIAL,
++	.bNumConfigurations =	1,
++};
++
++static struct usb_config_descriptor
++source_sink_config = {
++	.bLength =		sizeof source_sink_config,
++	.bDescriptorType =	USB_DT_CONFIG,
++
++	/* compute wTotalLength on the fly */
++	.bNumInterfaces =	1,
++	.bConfigurationValue =	CONFIG_SOURCE_SINK,
++	.iConfiguration =	STRING_SOURCE_SINK,
++	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
++	.bMaxPower =		1,	/* self-powered */
++};
++
++static struct usb_otg_descriptor
++otg_descriptor = {
++	.bLength =		sizeof otg_descriptor,
++	.bDescriptorType =	USB_DT_OTG,
++
++	.bmAttributes =		USB_OTG_SRP,
++};
++
++/* one interface in each configuration */
++
++static const struct usb_interface_descriptor
++source_sink_intf = {
++	.bLength =		sizeof source_sink_intf,
++	.bDescriptorType =	USB_DT_INTERFACE,
++
++	.bNumEndpoints =	4,
++	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
++	.iInterface =		STRING_SOURCE_SINK,
++};
++
++/* two full speed bulk endpoints; their use is config-dependent */
++
++static struct usb_endpoint_descriptor
++fs_bulkin_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++
++	.bEndpointAddress =	USB_DIR_IN,
++	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor
++fs_bulkout_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++
++	.bEndpointAddress =	USB_DIR_OUT,
++	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
++};
++
++static struct usb_endpoint_descriptor
++fs_intrin_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++
++	.bEndpointAddress =	USB_DIR_IN,
++	.bInterval = 		1,
++	.bmAttributes =		USB_ENDPOINT_XFER_INT,
++};
++
++static struct usb_endpoint_descriptor
++fs_introut_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++
++	.bEndpointAddress =	USB_DIR_OUT,
++	.bInterval = 		1,
++	.bmAttributes =		USB_ENDPOINT_XFER_INT,
++};
++
++static const struct usb_descriptor_header *fs_source_sink_function [] = {
++	(struct usb_descriptor_header *) &otg_descriptor,
++	(struct usb_descriptor_header *) &source_sink_intf,
++	(struct usb_descriptor_header *) &fs_bulkout_desc,
++	(struct usb_descriptor_header *) &fs_bulkin_desc,
++	(struct usb_descriptor_header *) &fs_introut_desc,
++	(struct usb_descriptor_header *) &fs_intrin_desc,
++	NULL,
++};
++
++
++/*
++ * usb 2.0 devices need to expose both high speed and full speed
++ * descriptors, unless they only run at full speed.
++ *
++ * that means alternate endpoint descriptors (bigger packets)
++ * and a "device qualifier" ... plus more construction options
++ * for the config descriptor.
++ */
++
++static struct usb_endpoint_descriptor
++hs_bulkin_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++
++	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
++	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
++};
++
++static struct usb_endpoint_descriptor
++hs_bulkout_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++
++	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
++	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
++};
++
++static struct usb_endpoint_descriptor
++hs_intrin_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++
++	.bmAttributes =		USB_ENDPOINT_XFER_INT,
++	.bInterval = 		1,
++	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
++};
++
++static struct usb_endpoint_descriptor
++hs_introut_desc = {
++	.bLength =		USB_DT_ENDPOINT_SIZE,
++	.bDescriptorType =	USB_DT_ENDPOINT,
++
++	.bInterval = 		1,
++	.bmAttributes =		USB_ENDPOINT_XFER_INT,
++	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
++};
++
++static struct usb_qualifier_descriptor
++dev_qualifier = {
++	.bLength =		sizeof dev_qualifier,
++	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
++
++	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
++	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,
++
++	.bNumConfigurations =	2,
++};
++
++static const struct usb_descriptor_header *hs_source_sink_function [] = {
++	(struct usb_descriptor_header *) &otg_descriptor,
++	(struct usb_descriptor_header *) &source_sink_intf,
++	(struct usb_descriptor_header *) &hs_bulkin_desc,
++	(struct usb_descriptor_header *) &hs_bulkout_desc,
++	(struct usb_descriptor_header *) &hs_intrin_desc,
++	(struct usb_descriptor_header *) &hs_introut_desc,
++	NULL,
++};
++
++
++/* maxpacket and other transfer characteristics vary by speed. */
++#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
++
++static char				manufacturer [50];
++static char				serial [128];
++
++/* static strings, in UTF-8 */
++static struct usb_string		strings [] = {
++	{ STRING_MANUFACTURER, manufacturer, },
++	{ STRING_PRODUCT, longname, },
++	{ STRING_SERIAL, serial, },
++	{ STRING_LOOPBACK, loopback, },
++	{ STRING_SOURCE_SINK, source_sink, },
++	{  }			/* end of list */
++};
++
++static struct usb_gadget_strings	stringtab = {
++	.language	= 0x0409,	/* en-us */
++	.strings	= strings,
++};
++
++/////////////////////////////////////////////////////////////////////////////////
++MassStorageState eUsbProessCBW(struct usb_request *req);
++MassStorageState eUsbDataOut(struct usb_request *req);
++void eUsbDataIn(struct usb_request *req);
++void ShowCBW(void);
++void ShowCSW(void);
++void vUsbSendCSW(struct usb_request *req);
++
++static MassStorageState eUsbMassStorageState;
++static u8   u8VirtMemory[MAX_BUFFER_SIZE];
++static u32* u32VirtMemory;
++static CSW tCSW;
++static u16 u16VirtMemoryIndex;
++static CBW tCBW;
++
++static u8 u8InterruptCount;
++static u8 u8Interrupt_TX_COUNT ;
++static u8 u8Interrupt_RX_COUNT ;
++static u8 u8InterruptOutCount ;
++
++u8 u8LineCount;
++u8 u8UsbMessageLevel;
++u8 *u8InterruptArray;
++
++/* ////////////////////////////////////////////////////////////////////////////////
++//
++//  Functions for Endpoints' Access
++//
++//////////////////////////////////////////////////////////////////////////////// */
++
++/*
++ * config descriptors are also handcrafted.  these must agree with code
++ * that sets configurations, and with code managing interfaces and their
++ * altsettings.  other complexity may come from:
++ *
++ *  - high speed support, including "other speed config" rules
++ *  - multiple configurations
++ *  - interfaces with alternate settings
++ *  - embedded class or vendor-specific descriptors
++ *
++ * this handles high speed, and has a second config that could as easily
++ * have been an alternate interface setting (on most hardware).
++ *
++ * NOTE:  to demonstrate (and test) more USB capabilities, this driver
++ * should include an altsetting to test interrupt transfers, including
++ * high bandwidth modes at high speed.  (Maybe work like Intel's test
++ * device?)
++ */
++static int
++config_buf (struct usb_gadget *gadget,
++		u8 *buf, u8 type, unsigned index)
++{
++	int				is_source_sink;
++	int				len;
++	const struct usb_descriptor_header **function;
++	int				hs = (gadget->speed == USB_SPEED_HIGH);
++
++	/* two configurations will always be index 0 and index 1 */
++	if (index > 1)
++		return -EINVAL;
++	is_source_sink = 1;
++
++	if (type == USB_DT_OTHER_SPEED_CONFIG)
++		hs = !hs;
++	if (hs)
++		function = hs_source_sink_function;
++	else
++		function = fs_source_sink_function;
++
++	/* for now, don't advertise srp-only devices */
++	if (!gadget->is_otg)
++		function++;
++
++	len = usb_gadget_config_buf (&source_sink_config,
++			buf, USB_BUFSIZ, function);
++	if (len < 0)
++		return len;
++	((struct usb_config_descriptor *) buf)->bDescriptorType = type;
++	return len;
++}
++
++/*-------------------------------------------------------------------------*/
++//static void *FTC_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
++//					dma_addr_t *dma, unsigned  gfp_flags);
++//static void FTC_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes);
++
++static struct usb_request *
++alloc_ep_req (struct usb_ep *ep, unsigned length)
++{
++	struct usb_request	*req;
++	struct FTC_ep           *my_ep;
++	struct FTC_request	*my_req;
++
++	req = usb_ep_alloc_request (ep, GFP_ATOMIC);
++
++        if (req) {
++	   my_ep = container_of(ep, struct FTC_ep, ep);
++	   my_req = container_of(req, struct FTC_request, req);
++	   my_req->req.buf = dma_alloc_coherent(&my_ep->dev->gadget.dev,length,&(my_req->req.dma),GFP_ATOMIC);
++	   if (!my_req->req.buf) {
++              printk("cannot allocate DMA buffer for EP:%x\n", (u32) ep);
++	   }
++	   else {
++	      my_req->req.length = length;
++	      my_ep->dma=1;
++	      //printk("EP %x== alloc buffer = 0x%x\n", (u32) ep, (u32) my_req->req.buf);
++	   }
++	}
++	else
++	   printk("Error :usb_ep_alloc_request Not Success !!\n");
++
++	return req;
++}
++
++static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
++{
++	struct FTC_request	*my_req;
++	struct FTC_ep	*my_ep;
++
++	if (req->buf) {
++	   my_ep = container_of(ep, struct FTC_ep, ep);
++	   my_req = container_of(req, struct FTC_request, req);
++	   if (my_ep->dma !=0)
++	      dma_free_coherent(&my_ep->dev->gadget.dev,my_req->req.length,my_req->req.buf,my_req->req.dma);
++	   my_ep->dma=0;
++	}
++
++	usb_ep_free_request (ep, req);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*-------------------------------------------------------------------------*/
++
++/* if there is only one request in the queue, there'll always be an
++ * irq delay between end of one request and start of the next.
++ * that prevents using hardware dma queues.
++ */
++static void source_sink_test (struct usb_ep *ep, struct usb_request *req)
++{
++	struct ftst_dev	*dev = ep->driver_data;
++	int		status = req->status;
++
++	printk("source_sink_test Not implement\n");
++	status = usb_ep_queue (ep, req, GFP_ATOMIC);
++	if (status) {
++		ERROR (dev, "kill %s:  resubmit %d bytes --> %d\n",
++				ep->name, req->length, status);
++		usb_ep_set_halt (ep);
++		/* FIXME recover later ... somehow */
++	}
++
++}
++static void ftst_bulkin_complete(struct usb_ep *ep, struct usb_request *req);
++static void ftst_bulkout_complete(struct usb_ep *ep, struct usb_request *req);
++static void ftst_intrin_complete(struct usb_ep *ep, struct usb_request *req);
++static void ftst_introut_complete(struct usb_ep *ep, struct usb_request *req);
++
++static unsigned int buflen[] = {
++	0,
++	512, /* Bulkin i.e. Endpoint 1 buffer size */
++	512, /* Bulkout i.e. Endpoint 2 buffer size */
++	64, /* Bulkin i.e. Endpoint 3 buffer size */
++	64 /* Bulkout i.e. Endpoint 4 buffer size */
++};
++
++static void (*source_sink_complete[])(struct usb_ep *ep, struct usb_request *req) = {
++		&source_sink_test,
++		&ftst_bulkin_complete,
++		&ftst_bulkout_complete,
++		&ftst_intrin_complete,
++		&ftst_introut_complete,
++		NULL
++};
++
++static struct usb_request *
++source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags,int sz,int i)
++{
++	struct usb_request	*req;
++	int			status;
++
++	req = alloc_ep_req (ep, sz);
++	if (!req)
++		return NULL;
++
++	memset (req->buf, 0, req->length);
++	req->complete = source_sink_complete[i];
++
++	status = usb_ep_queue (ep, req, gfp_flags);
++	if (status) {
++		struct ftst_dev	*dev = ep->driver_data;
++
++		ERROR (dev, "start %s --> %d\n", ep->name, status);
++		free_ep_req (ep, req);
++		req = NULL;
++	}
++
++	return req;
++}
++
++////////////////////////////////////////////////////////////////////////////////
++//
++//  Bulk IN/OUT transfer test functions
++//
++////////////////////////////////////////////////////////////////////////////////
++
++///////////////////////////////////////////////////////////////////////////////
++//		vUsb_APInit()
++//		Description: User specified circuit (AP) init
++//		input: none
++//		output: none
++///////////////////////////////////////////////////////////////////////////////
++void vUsb_APInit(void)
++{
++   u32 i;
++   //u8 u8_i = 0;
++
++   ////// initial Bulk //////
++   eUsbMassStorageState = STATE_CBW;	// Init State
++
++   for(i = 0; i < MAX_BUFFER_SIZE; i++) {
++      u8VirtMemory[i] = 0;			// Init Buffer
++      //u8VirtMemory[u16_i] = u8_i++;		// Init Buffer
++   }
++
++   u32VirtMemory = (u32 *)kmalloc(MAX_BUFFER_SIZE,GFP_KERNEL);
++   memcpy(u32VirtMemory,u8VirtMemory,MAX_BUFFER_SIZE);
++
++   tCSW.u32Signature = CSW_SIGNATE;	// Init u32Signature
++
++   ////// initial INT and ISO test ////////////
++   u8InterruptCount = 0;
++   u8Interrupt_TX_COUNT = 1;
++   u8InterruptOutCount = 0;
++   u8Interrupt_RX_COUNT = 1;
++}
++
++void vUsb_queue_reqest(struct ftst_dev *dev,MassStorageState eState)
++{
++   struct usb_request *req;
++
++   switch(eState){
++      case STATE_CBW:
++         if((req = source_sink_start_ep (dev->bulkout_ep, GFP_ATOMIC,512,2)) == NULL){
++	    usb_ep_disable (dev->bulkout_ep);
++	    printk("Allocate error 1!!\n");
++	    return;
++	 }
++	 break;
++      case STATE_CB_DATA_OUT:
++	 if((req = source_sink_start_ep (dev->bulkout_ep, GFP_ATOMIC,512,2)) == NULL){
++	    usb_ep_disable (dev->bulkout_ep);
++	    printk("Allocate error 2!!\n");
++	    return;
++	 }
++	 break;
++      case STATE_CSW:
++	 if((req = source_sink_start_ep (dev->bulkin_ep, GFP_ATOMIC,13,1)) == NULL){
++	    usb_ep_disable (dev->bulkin_ep);
++	    printk("Allocate error 3!!\n");
++	    return;
++	 }
++	 vUsbSendCSW(req);
++	 break;
++      case STATE_CB_DATA_IN:
++         if(tCSW.u32DataResidue > 512){
++	    if((req=source_sink_start_ep (dev->bulkin_ep, GFP_ATOMIC,512,1)) == NULL){
++	       usb_ep_disable (dev->bulkin_ep);
++	       printk("Allocate error 4!!\n");
++	       return;
++	    }
++	 }
++	 else if ((req=source_sink_start_ep (dev->bulkin_ep, GFP_ATOMIC,tCSW.u32DataResidue,1)) == NULL){
++	    usb_ep_disable (dev->bulkin_ep);
++	    printk("Allocate error 5!!\n");
++	    return;
++         }
++	 eUsbDataIn(req);
++	 break;
++      default:
++	 break;
++   }
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		cyg_usb_bulk_in()
++//		Description: USB FIFO0 interrupt service process
++//		input: none
++//		output: none
++///////////////////////////////////////////////////////////////////////////////
++static void ftst_bulkin_complete(struct usb_ep *ep, struct usb_request *req)
++{
++   struct FTC_ep *my_ep;
++
++   my_ep = container_of(ep, struct FTC_ep, ep);
++
++   switch(eUsbMassStorageState)
++   {
++      case STATE_CSW:
++         eUsbMassStorageState = STATE_CBW;
++	 break;
++      case STATE_CB_DATA_IN:
++#ifdef BULK_USBS_DEBUG
++	 printk("EP1 CS DATA IN\n");
++#endif
++	 if (tCSW.u32DataResidue == 0)
++	    eUsbMassStorageState = STATE_CSW;
++	 else
++	    eUsbMassStorageState = STATE_CB_DATA_IN;
++	 break;
++      default:
++	 printk("L%x: Error FIFO0_IN interrupt.\n", u8LineCount);
++	 break;
++   }
++   free_ep_req(ep,req);   //release current request
++   if (my_ep->stopped)
++      vUsb_queue_reqest((struct ftst_dev *)(ep->driver_data),eUsbMassStorageState);
++}
++
++
++static void ftst_bulkout_complete(struct usb_ep *ep, struct usb_request *req)
++{
++   struct FTC_ep		*my_ep;
++
++   my_ep = container_of(ep, struct FTC_ep, ep);
++
++   switch(eUsbMassStorageState)
++   {
++      case STATE_CBW:
++#ifdef BULK_USBS_DEBUG
++         printk("EP2 Out CBW:0x%x\n",req->actual);
++#endif
++	 if (req->actual == 31)
++	    eUsbMassStorageState = eUsbProessCBW(req);
++	 else {
++#ifdef BULK_USBS_DEBUG
++	    printk("EP out STAL SET\n");
++#endif
++	    usb_ep_set_halt (ep);
++         }
++	 //printf("FIFO 2:0x%x\n",mUsbFIFOOutByteCount(FIFO2));
++	 break;
++      case STATE_CB_DATA_OUT:
++#if 0
++         if((u16)tCBW.u32DataTransferLength != u16FIFOByteCount)
++	    printf("Byte Count Error = %d. (Correct = %d)\n",
++		u8LineCount, u16FIFOByteCount, (u16)tCBW.u32DataTransferLength);
++	 else
++#endif
++	    eUsbMassStorageState = eUsbDataOut(req);
++  	 break;
++      default:
++         printk("L%x: Error FIFO2_OUT interrupt.\n", u8LineCount);
++ 	 break;
++   }
++   free_ep_req(ep,req);
++   if (my_ep->stopped)
++      vUsb_queue_reqest((struct ftst_dev *)(ep->driver_data),eUsbMassStorageState);
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		ShowCBW()
++//		Description: show the whole CBW structure
++//		input: none
++//		output: none
++///////////////////////////////////////////////////////////////////////////////
++void ShowCBW(void)
++{
++#if 1
++	int i;
++	printk("tCBW.u32Signature = 0x%x\n",tCBW.u32Signature);
++	printk("tCBW.u32Tag =  0x%x\n",tCBW.u32Tag);
++	printk("tCBW.u32DataTransferLength =  0x%x\n",tCBW.u32DataTransferLength);
++	printk("tCBW.u8Flags =  0x%x\n",tCBW.u8Flags);
++	printk("tCBW.u8LUN = 0x%x\n", tCBW.u8LUN);
++	printk("tCBW.u8CBLength =  0x%x\n", tCBW.u8CBLength);
++	printk("tCBW.u8CB[0 ~ 15] =");
++	for(i = 0; i < 16; i ++)
++	{
++		printk("%x ", tCBW.u8CB[i]);
++		if ((i%8) == 7) printk("\n");
++	}
++	printk("\n");
++#else
++	u8 i;
++	u8 * pp;
++	pp = (u8 *)&tCBW;
++	printk("tCBW: \n");
++	for (i = 0; i < 16; i ++)
++		printk("%02x ", *(pp ++));
++	printk("\n");
++	for (i = 16; i < 31; i ++)
++		printk("%02x ", *(pp ++));
++	printk("\n");
++#endif
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		ShowCSW()
++//		Description: show the whole CSW structure
++//		input: none
++//		output: none
++///////////////////////////////////////////////////////////////////////////////
++void ShowCSW(void)
++{
++#if 1
++	printk("tCSW.u32Signature =  0x%x\n",tCSW.u32Signature);
++	printk("tCSW.u32Tag =  0x%x\n",tCSW.u32Tag);
++	printk("tCSW.u32DataResidue =  0x%x\n",tCSW.u32DataResidue);
++	printk("tCSW.u8Status = %x\n", tCSW.u8Status);
++#else
++	if(u8UsbMessageLevel & (MESS_INFO))
++	{
++		u8 i;
++		u8 * pp;
++		pp = (u8 *)&tCSW;
++		printk("tCSW: \n");
++		for (i = 0; i < 13; i ++)
++			printk("%02x ", *(pp ++));
++		printk("\n");
++	}
++#endif
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		eUsbProessCBW()
++//		Description: Process the CBW
++//		input: none
++//		output: MassStorageState
++///////////////////////////////////////////////////////////////////////////////
++MassStorageState eUsbProessCBW(	struct usb_request *req)
++{
++	  MassStorageState eState;
++	memcpy(&tCBW,req->buf,31);
++
++#ifdef BULK_USBS_DEBUG
++	ShowCBW();
++#endif
++
++	if(tCBW.u32Signature != CBW_SIGNATE)
++		eState = STATE_CBW;
++	else
++	{
++		// pass u32DataTransferLength to u32DataResidue
++		tCSW.u32DataResidue = tCBW.u32DataTransferLength;
++		// pass Tag from CBW to CSW
++		tCSW.u32Tag = tCBW.u32Tag;
++		// Assume Status is CMD_PASS
++		tCSW.u8Status = CSW_STATUS_CMD_PASS;
++		// Get Virtual Memory start address.
++		u16VirtMemoryIndex = tCBW.u8CB[0] | (tCBW.u8CB[1] << 8); // marked by silas???
++		u16VirtMemoryIndex=0;// add by silas
++
++		if (tCSW.u32DataResidue == 0)
++			eState = STATE_CSW;
++		else if (tCBW.u8Flags == 0x00)
++			eState = STATE_CB_DATA_OUT;
++		else
++			eState = STATE_CB_DATA_IN;
++	}
++	return eState;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		vUsbSendCSW()
++//		Description: Send out the CSW structure to PC
++//		input: none
++//		output: none
++///////////////////////////////////////////////////////////////////////////////
++void vUsbSendCSW(struct usb_request *req)
++{
++//	u8 u8Tmp = mUsbHbfCountRd();
++	// Send CSW to F0 via DBUS;
++#ifdef BULK_USBS_DEBUG
++	printk("EP1 IN CSW\n");
++	ShowCSW();
++#endif
++//	printf("Buffer counter = %d",u8Tmp);
++	memcpy(req->buf,&tCSW,13);
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		eUsbDataIn()
++//		Description: Process the data intput stage
++//		input: none
++//		output: MassStorageState
++///////////////////////////////////////////////////////////////////////////////
++void eUsbDataIn(struct usb_request *req)
++{
++   //u16 u16count;
++   u32 u16count;
++
++#ifdef BULK_USBS_DEBUG
++   printk("eUsbDataIn -> u32DataResidue:%x \n",tCSW.u32DataResidue);
++#endif
++
++   if((u16count = tCSW.u32DataResidue) > req->length)
++      u16count = req->length;
++   //printf("CSW DataTransfer Length:0x%x\n",tCSW.u32DataResidue);
++   //printf("count:0x%x\n",u16count);
++
++   // Send u16FIFOByteCount Bytes data to F0 via DBUS;
++   memcpy(req->buf,&u8VirtMemory[u16VirtMemoryIndex],u16count);
++
++   u16VirtMemoryIndex += u16count;
++   tCSW.u32DataResidue -= u16count;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		eUsbDataOut()
++//		Description: Process the data output stage
++//		input: none
++//		output: MassStorageState
++///////////////////////////////////////////////////////////////////////////////
++MassStorageState eUsbDataOut(struct usb_request *req)
++{
++   u32 u32State;
++
++   // Get u16FIFOByteCount Bytes data from F1 via DBUS;
++#ifdef BULK_USBS_DEBUG
++   printk("EP2 Out CB Data Out \n");
++#endif
++   memcpy(&u8VirtMemory[u16VirtMemoryIndex],req->buf,req->actual);
++
++#ifdef BULK_USBS_DEBUG
++   {
++      u32 i;
++      u8 *ptr = req->buf;
++      for (i=0;i<req->actual;i++)
++         printk("%02x ",*(ptr+i));
++      printk("\n");
++   }
++#endif
++   u16VirtMemoryIndex += req->actual;
++   tCSW.u32DataResidue -= req->actual;
++   // printk("EP2 u32DataResidue:0x%x\n",tCSW.u32DataResidue);
++   if (tCSW.u32DataResidue == 0)
++      u32State= STATE_CSW;
++   else
++      u32State= STATE_CB_DATA_OUT;
++
++   return u32State;
++}
++
++////////////////////////////////////////////////////////////////////////////////
++//
++//  Interrupt IN/OUT transfer test functions
++//
++////////////////////////////////////////////////////////////////////////////////
++
++
++///////////////////////////////////////////////////////////////////////////////
++//		vUsb_Interrupt_Initial()
++//		Description: Initial Interrupt test
++//		input: none
++//		output: None
++///////////////////////////////////////////////////////////////////////////////
++
++void vUsb_Interrupt_Initial(struct ftst_dev *dev)
++{
++	u8 u8i = 0;
++	u16 u16i;
++	struct usb_request	*req;
++	u8 *u8Array;
++
++	u8InterruptArray =  (u8 *)kmalloc(512,GFP_KERNEL);
++	for (u16i = 0; u16i < 512; u16i ++)
++		u8InterruptArray[u16i] = u8i ++;
++
++	if((req=source_sink_start_ep (dev->intrin_ep, GFP_ATOMIC,u8Interrupt_TX_COUNT,3)) == NULL){
++                usb_ep_disable (dev->intrin_ep);
++                printk("Allocate error 6!!\n");
++                return;
++        }
++	u8Array = (u8 *)req->buf;
++	for (u8i = 0; u8i < u8Interrupt_TX_COUNT; u8i ++){
++		u8Array[u8i] = (u8InterruptCount);
++		u8InterruptCount ++;
++	}
++	u8Interrupt_TX_COUNT++;
++	if(u8Interrupt_TX_COUNT > dev->intrin_ep->maxpacket)
++		u8Interrupt_TX_COUNT = 1;
++
++	if((req=source_sink_start_ep (dev->introut_ep, GFP_ATOMIC,u8Interrupt_RX_COUNT,4)) == NULL){
++		usb_ep_disable (dev->introut_ep);
++		printk("Allocate error 7!!\n");
++		return;
++	}
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		vUsb_Interrupt_In()
++//		Description: FIFO4 interrupt service process
++//		input: none
++//		output: none
++///////////////////////////////////////////////////////////////////////////////
++static void ftst_intrin_complete(struct usb_ep *ep, struct usb_request *req)
++{
++	u8 u8i;
++	u8 *u8Array;
++	struct ftst_dev *dev;
++	struct FTC_ep		*my_ep;
++
++#if IntTransSizeFix
++	u8Interrupt_TX_COUNT = 13;
++#endif
++	free_ep_req(ep,req);
++
++	my_ep = container_of(ep, struct FTC_ep, ep);
++	if (!my_ep->stopped)
++	   return;
++
++	dev = (struct ftst_dev *)(ep->driver_data);
++	if((req=source_sink_start_ep (dev->intrin_ep, GFP_ATOMIC,u8Interrupt_TX_COUNT,3)) == NULL){
++		usb_ep_disable (dev->intrin_ep);
++		printk("Allocate error 8!!\n");
++		return;
++	}
++
++	u8Array = (u8 *)req->buf;
++	for (u8i = 0; u8i < u8Interrupt_TX_COUNT; u8i ++){
++		u8Array[u8i] = (u8InterruptCount);
++		u8InterruptCount ++;
++	}
++
++//	if(u8UsbMessageLevel & MESS_INFO)
++//		printf("L%x: Interrupt_IN...\n", u8LineCount ++);
++
++	u8Interrupt_TX_COUNT++;
++	if(u8Interrupt_TX_COUNT > ep->maxpacket)
++		u8Interrupt_TX_COUNT = 1;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//		vUsb_Interrupt_Out()
++//		Description: FIFO4 interrupt service process
++//		input: none
++//		output: none
++///////////////////////////////////////////////////////////////////////////////
++static void ftst_introut_complete(struct usb_ep *ep, struct usb_request *req)
++{
++   u16 i,u16Interrupt_RX_Count = req->actual;
++   u8 *u8Array;
++   struct ftst_dev *dev;
++   struct FTC_ep		*my_ep;
++
++#if IntTransSizeFix
++   u8Interrupt_RX_COUNT = 13;
++#endif
++
++   u8Array = (u8 *)req->buf;
++   if(u16Interrupt_RX_Count != u8Interrupt_RX_COUNT)
++      printk("L%x: Interrupt_Out Byte Count Error = %x...(Correct = %x)\n",
++	      u8LineCount ++, u16Interrupt_RX_Count, u8Interrupt_RX_COUNT);
++
++   if (memcmp(u8InterruptArray + u8InterruptOutCount, u8Array, u8Interrupt_RX_COUNT) != 0)
++   {
++      printk("L%x: Interrupt_Out Data error...\n", u8LineCount ++);
++
++      printk("Device Get Data...");
++      for (i = 0; i< u16Interrupt_RX_Count; i++) {
++         if(i % 8 == 0)
++            printk("\n");
++            printk("%02x  ",u8Array[i]);
++      }
++      printk("\n");
++
++      printk("Correct Data...");
++      for (i = 0; i< u8Interrupt_RX_COUNT; i++){
++      if(i % 8 == 0)
++         printk("\n");
++         printk("%02x  ", *(u8InterruptArray + u8InterruptOutCount + i));
++      }
++      printk("\n");
++   }
++
++   u8InterruptOutCount = u8InterruptOutCount + u8Interrupt_RX_COUNT;
++
++   u8Interrupt_RX_COUNT++;
++   if(u8Interrupt_RX_COUNT > ep->maxpacket)
++      u8Interrupt_RX_COUNT = 1;
++
++   free_ep_req(ep,req);
++
++   my_ep = container_of(ep, struct FTC_ep, ep);
++   if (!my_ep->stopped)
++      return;
++
++   dev = (struct ftst_dev *)(ep->driver_data);
++   /*if((req=source_sink_start_ep (dev->introut_ep, GFP_ATOMIC,u8Interrupt_RX_COUNT,4)) == NULL){ */
++   if ((req=source_sink_start_ep (dev->introut_ep, GFP_ATOMIC,64,4)) == NULL){
++      usb_ep_disable (dev->introut_ep);
++      printk("Allocate error 9!!\n");
++      return;
++   }
++}
++
++/* ////////////////////////////////////////////////////////////////////////////////
++//
++//  Functions for Enumeration
++//
++//////////////////////////////////////////////////////////////////////////////// */
++
++
++/*-------------------------------------------------------------------------*/
++
++static int
++set_source_sink_config (struct ftst_dev *dev, unsigned gfp_flags)
++{
++	int			result = 0;
++	struct usb_ep		*ep;
++	struct usb_gadget	*gadget = dev->gadget;
++
++	gadget_for_each_ep (ep, gadget) {
++		const struct usb_endpoint_descriptor	*d;
++
++		/* one endpoint writes (sources) zeroes in (to the host) */
++		if (strcmp (ep->name, EP_BULK_IN_NAME) == 0) {
++			d = ep_desc (gadget, &hs_bulkin_desc, &fs_bulkin_desc);
++			ep->desc = d;
++			result = usb_ep_enable (ep);
++			if (result == 0) {
++				ep->driver_data = dev;
++				dev->bulkin_ep = ep;
++				continue;
++			}
++
++		/* one endpoint reads (sinks) anything out (from the host) */
++		} else if (strcmp (ep->name, EP_BULK_OUT_NAME) == 0) {
++			d = ep_desc (gadget, &hs_bulkout_desc, &fs_bulkout_desc);
++			ep->desc = d;
++			result = usb_ep_enable (ep);
++			if (result == 0) {
++				ep->driver_data = dev;
++				dev->bulkout_ep = ep;
++				continue;
++			}
++
++		/* ignore any other endpoints */
++		}else if (strcmp (ep->name, EP_INTR_IN_NAME) == 0) {
++			d = ep_desc (gadget, &hs_intrin_desc, &fs_intrin_desc);
++			ep->desc = d;
++			result = usb_ep_enable (ep);
++			if (result == 0) {
++				ep->driver_data = dev;
++				dev->intrin_ep = ep;
++				continue;
++				/*if (source_sink_start_ep (ep, gfp_flags,64,3) != 0) {
++					dev->intrin_ep = ep;
++					continue;
++				}
++				usb_ep_disable (ep);
++				result = -EIO;*/
++			}
++
++		/* one endpoint reads (sinks) anything out (from the host) */
++		} else if (strcmp (ep->name, EP_INTR_OUT_NAME) == 0) {
++			d = ep_desc (gadget, &hs_introut_desc, &fs_introut_desc);
++			ep->desc = d;
++			result = usb_ep_enable (ep);
++			if (result == 0) {
++				ep->driver_data = dev;
++				dev->introut_ep = ep;
++				continue;
++				/*if (source_sink_start_ep (ep, gfp_flags,64,4) != 0) {
++					dev->introut_ep = ep;
++					continue;
++				}
++				usb_ep_disable (ep);
++				result = -EIO;*/
++			}
++
++		/* ignore any other endpoints */
++		} else
++			continue;
++
++		/* stop on error */
++		ERROR (dev, "can't start %s, result %d\n", ep->name, result);
++		break;
++	}
++	if (result == 0)
++		DBG (dev, "buflen %p\n", buflen);
++
++	/* caller is responsible for cleanup on error */
++	return result;
++}
++
++/*-------------------------------------------------------------------------*/
++static void ftst_reset_config (struct ftst_dev *dev)
++{
++	if (dev->config == 0)
++		return;
++
++	DBG (dev, "reset config\n");
++
++	/* just disable endpoints, forcing completion of pending i/o.
++	 * all our completion handlers free their requests in this case.
++	 */
++	if (dev->bulkin_ep) {
++		usb_ep_disable (dev->bulkin_ep);
++		dev->bulkin_ep = NULL;
++	}
++	if (dev->bulkout_ep) {
++		usb_ep_disable (dev->bulkout_ep);
++		dev->bulkout_ep = NULL;
++	}
++	if (dev->intrin_ep) {
++		usb_ep_disable (dev->intrin_ep);
++		dev->intrin_ep = NULL;
++	}
++	if (dev->introut_ep) {
++		usb_ep_disable (dev->introut_ep);
++		dev->introut_ep = NULL;
++	}
++	dev->config = 0;
++	del_timer (&dev->resume);
++}
++
++/* change our operational config.  this code must agree with the code
++ * that returns config descriptors, and altsetting code.
++ *
++ * it's also responsible for power management interactions. some
++ * configurations might not work with our current power sources.
++ *
++ * note that some device controller hardware will constrain what this
++ * code can do, perhaps by disallowing more than one configuration or
++ * by limiting configuration choices (like the pxa2xx).
++ */
++static int
++ftst_set_config (struct ftst_dev *dev, unsigned number, unsigned gfp_flags)
++{
++	int			result = 0;
++	struct usb_gadget	*gadget = dev->gadget;
++	struct FTC_udc		*ftc_dev = container_of (dev->gadget, struct FTC_udc, gadget);
++
++	if (number == dev->config)
++		return 0;
++
++#define	gadget_is_sa1100(g)	(!strcmp("sa1100_udc", (g)->name))
++	if (gadget_is_sa1100 (gadget) && dev->config) {
++		/* tx fifo is full, but we can't clear it...*/
++		INFO (dev, "can't change configurations\n");
++		return -ESPIPE;
++	}
++	ftst_reset_config (dev);
++
++	switch (number) {
++	case CONFIG_SOURCE_SINK:
++		result = set_source_sink_config (dev, gfp_flags);
++		vUsb_APInit();
++		vUsb_queue_reqest(dev,eUsbMassStorageState);
++		vUsb_Interrupt_Initial(dev);
++		mUsbFIFOReset(ftc_dev->va_base,2);
++		break;
++	default:
++		result = -EINVAL;
++		/* FALL THROUGH */
++	case 0:
++		return result;
++	}
++
++	if (!result && (!dev->bulkin_ep || !dev->bulkout_ep))
++		result = -ENODEV;
++	if (result)
++		ftst_reset_config (dev);
++	else {
++		char *speed;
++
++		switch (gadget->speed) {
++		case USB_SPEED_LOW:	speed = "low"; break;
++		case USB_SPEED_FULL:	speed = "full"; break;
++		case USB_SPEED_HIGH:	speed = "high"; break;
++		default: 		speed = "?"; break;
++		}
++
++		dev->config = number;
++		INFO (dev, "%s speed config #%d: %s\n", speed, number,
++					 source_sink );
++	}
++	return result;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void ftst_setup_complete (struct usb_ep *ep, struct usb_request *req)
++{
++	if (req->status || req->actual != req->length)
++		DBG ((struct ftst_dev *) ep->driver_data,
++				"setup complete --> %d, %d/%d\n",
++				req->status, req->actual, req->length);
++}
++
++/*
++ * The setup() callback implements all the ep0 functionality that's
++ * not handled lower down, in hardware or the hardware driver (like
++ * device and endpoint feature flags, and their status).  It's all
++ * housekeeping for the gadget function we're implementing.  Most of
++ * the work is in config-specific setup.
++ */
++static int
++ftst_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
++{
++	struct ftst_dev		*dev = get_gadget_data (gadget);
++	struct usb_request	*req = dev->req;
++	int			value = -EOPNOTSUPP;
++	u16			w_index = le16_to_cpu(ctrl->wIndex);
++	u16			w_value = le16_to_cpu(ctrl->wValue);
++	u16			w_length = le16_to_cpu(ctrl->wLength);
++
++	/* usually this stores reply data in the pre-allocated ep0 buffer,
++	 * but config change events will reconfigure hardware.
++	 */
++
++	req->zero = 0;
++	switch (ctrl->bRequest) {
++
++	case USB_REQ_GET_DESCRIPTOR:
++		if (ctrl->bRequestType != USB_DIR_IN)
++			goto unknown;
++		switch (w_value >> 8) {
++
++		case USB_DT_DEVICE:
++			value = min (w_length, (u16) sizeof device_desc);
++			memcpy (req->buf, &device_desc, value);
++			break;
++		case USB_DT_DEVICE_QUALIFIER:
++			value = min (w_length, (u16) sizeof dev_qualifier);
++			memcpy (req->buf, &dev_qualifier, value);
++			break;
++
++		case USB_DT_OTHER_SPEED_CONFIG:
++		case USB_DT_CONFIG:
++			value = config_buf (gadget, req->buf,
++					w_value >> 8,
++					w_value & 0xff);
++			if (value >= 0)
++				value = min (w_length, (u16) value);
++			break;
++
++		case USB_DT_STRING:
++			/* wIndex == language code.
++			 * this driver only handles one language, you can
++			 * add string tables for other languages, using
++			 * any UTF-8 characters
++			 */
++			value = usb_gadget_get_string (&stringtab,
++					w_value & 0xff, req->buf);
++			if (value >= 0)
++				value = min (w_length, (u16) value);
++			break;
++		}
++		break;
++
++	/* currently two configs, two speeds */
++	case USB_REQ_SET_CONFIGURATION:
++		if (ctrl->bRequestType != 0)
++			goto unknown;
++		if (gadget->a_hnp_support)
++			DBG (dev, "HNP available\n");
++		else if (gadget->a_alt_hnp_support)
++			DBG (dev, "HNP needs a different root port\n");
++		else
++			VDBG (dev, "HNP inactive\n");
++		spin_lock (&dev->lock);
++		value = ftst_set_config (dev, w_value, GFP_ATOMIC);
++		spin_unlock (&dev->lock);
++		break;
++	case USB_REQ_GET_CONFIGURATION:
++		if (ctrl->bRequestType != USB_DIR_IN)
++			goto unknown;
++		*(u8 *)req->buf = dev->config;
++		value = min (w_length, (u16) 1);
++		break;
++
++	/* until we add altsetting support, or other interfaces,
++	 * only 0/0 are possible.  pxa2xx only supports 0/0 (poorly)
++	 * and already killed pending endpoint I/O.
++	 */
++	case USB_REQ_SET_INTERFACE:
++		if (ctrl->bRequestType != USB_RECIP_INTERFACE)
++			goto unknown;
++		spin_lock (&dev->lock);
++		if (dev->config && w_index == 0 && w_value == 0) {
++			u8		config = dev->config;
++
++			/* resets interface configuration, forgets about
++			 * previous transaction state (queued bufs, etc)
++			 * and re-inits endpoint state (toggle etc)
++			 * no response queued, just zero status == success.
++			 * if we had more than one interface we couldn't
++			 * use this "reset the config" shortcut.
++			 */
++			ftst_reset_config (dev);
++			ftst_set_config (dev, config, GFP_ATOMIC);
++			value = 0;
++		}
++		spin_unlock (&dev->lock);
++		break;
++	case USB_REQ_GET_INTERFACE:
++		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
++			goto unknown;
++		if (!dev->config)
++			break;
++		if (w_index != 0) {
++			value = -EDOM;
++			break;
++		}
++		*(u8 *)req->buf = 0;
++		value = min (w_length, (u16) 1);
++		break;
++
++	/*
++	 * These are the same vendor-specific requests supported by
++	 * Intel's USB 2.0 compliance test devices.  We exceed that
++	 * device spec by allowing multiple-packet requests.
++	 */
++	case 0x5b:	/* control WRITE test -- fill the buffer */
++		if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
++			goto unknown;
++		if (w_value || w_index)
++			break;
++		/* just read that many bytes into the buffer */
++		if (w_length > USB_BUFSIZ)
++			break;
++		value = w_length;
++		break;
++	case 0x5c:	/* control READ test -- return the buffer */
++		if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
++			goto unknown;
++		if (w_value || w_index)
++			break;
++		/* expect those bytes are still in the buffer; send back */
++		if (w_length > USB_BUFSIZ
++				|| w_length != req->length)
++			break;
++		value = w_length;
++		break;
++
++	default:
++unknown:
++		VDBG (dev,
++			"unknown control req%02x.%02x v%04x i%04x l%d\n",
++			ctrl->bRequestType, ctrl->bRequest,
++			w_value, w_index, w_length);
++	}
++
++	/* respond with data transfer before status phase? */
++	if (value >= 0) {
++		req->length = value;
++		req->zero = value < w_length;
++		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
++		if (value < 0) {
++			DBG (dev, "ep_queue --> %d\n", value);
++			req->status = 0;
++			ftst_setup_complete (gadget->ep0, req);
++		}
++	}
++
++	/* device either stalls (value < 0) or reports success */
++	return value;
++}
++
++static void
++ftst_disconnect (struct usb_gadget *gadget)
++{
++	struct ftst_dev		*dev = get_gadget_data (gadget);
++	unsigned long		flags;
++
++
++	spin_lock_irqsave (&dev->lock, flags);
++	ftst_reset_config (dev);
++
++	/* a more significant application might have some non-usb
++	 * activities to quiesce here, saving resources like power
++	 * or pushing the notification up a network stack.
++	 */
++	spin_unlock_irqrestore (&dev->lock, flags);
++
++	/* next we may get setup() calls to enumerate new connections;
++	 * or an unbind() during shutdown (including removing module).
++	 */
++}
++
++static void
++ftst_autoresume (unsigned long _dev)
++{
++	struct ftst_dev	*dev = (struct ftst_dev *) _dev;
++	int		status;
++
++	/* normally the host would be woken up for something
++	 * more significant than just a timer firing...
++	 */
++	if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
++		status = usb_gadget_wakeup (dev->gadget);
++		DBG (dev, "wakeup --> %d\n", status);
++	}
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void
++ftst_unbind (struct usb_gadget *gadget)
++{
++	struct ftst_dev		*dev = get_gadget_data (gadget);
++
++	DBG (dev, "unbind\n");
++
++	/* we've already been disconnected ... no i/o is active */
++	if (dev->req) {
++	   //free_ep_req (gadget->ep0, dev->req);
++	   struct FTC_request	*my_req;
++	   struct FTC_ep	*my_ep;
++
++	   if (dev->req->buf) {
++	      my_ep = container_of(gadget->ep0, struct FTC_ep, ep);
++	      my_req = container_of(dev->req, struct FTC_request, req);
++	      kfree(my_req->req.buf);
++	      my_ep->dma=0;
++	   }
++
++	   usb_ep_free_request (gadget->ep0, dev->req);
++        }
++
++	del_timer_sync (&dev->resume);
++	kfree (dev);
++	set_gadget_data (gadget, NULL);
++}
++
++static int __devinit ftst_bind (struct usb_gadget *gadget)
++{
++	struct ftst_dev		*dev;
++	struct usb_ep		*ep;
++	int			gcnum;
++
++	/* FIXME this can't yet work right with SH ... it has only
++	 * one configuration, numbered one.
++	 */
++#define	gadget_is_sh(g)		(!strcmp("sh_udc", (g)->name))
++	if (gadget_is_sh(gadget))
++		return -ENODEV;
++
++	/* Bulk-only drivers like this one SHOULD be able to
++	 * autoconfigure on any sane usb controller driver,
++	 * but there may also be important quirks to address.
++	 */
++	usb_ep_autoconfig_reset (gadget);
++	ep = usb_ep_autoconfig (gadget, &fs_bulkin_desc);
++	if (!ep) {
++autoconf_fail:
++		printk (KERN_ERR "%s: can't autoconfigure on %s\n",
++			shortname, gadget->name);
++		return -ENODEV;
++	}
++	EP_BULK_IN_NAME = ep->name;
++	ep->driver_data = ep;	/* claim */
++	fotg2xx_dbg(" ftst_bind: %s %d\n",ep->name,ep->maxpacket);
++
++	ep = usb_ep_autoconfig (gadget, &fs_bulkout_desc);
++	if (!ep)
++		goto autoconf_fail;
++	EP_BULK_OUT_NAME = ep->name;
++	ep->driver_data = ep;	/* claim */
++	fotg2xx_dbg(" ftst_bind: %s %d\n",ep->name,ep->maxpacket);
++
++	ep = usb_ep_autoconfig (gadget, &fs_intrin_desc);
++	if (!ep)
++		goto autoconf_fail;
++	EP_INTR_IN_NAME = ep->name;
++	ep->driver_data = ep;	/* claim */
++	fotg2xx_dbg(" ftst_bind: %s %d\n",ep->name,ep->maxpacket);
++
++	ep = usb_ep_autoconfig (gadget, &fs_introut_desc);
++	if (!ep)
++		goto autoconf_fail;
++	EP_INTR_OUT_NAME = ep->name;
++	ep->driver_data = ep;	/* claim */
++	fotg2xx_dbg(" ftst_bind: %s %s %d\n",gadget->name, ep->name,ep->maxpacket);
++
++	gcnum = usb_gadget_controller_number (gadget);
++	if (gcnum >= 0)
++		device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
++	else {
++		/* gadget zero is so simple (for now, no altsettings) that
++		 * it SHOULD NOT have problems with bulk-capable hardware.
++		 * so warn about unrcognized controllers, don't panic.
++		 *
++		 * things like configuration and altsetting numbering
++		 * can need hardware-specific attention though.
++		 */
++		printk (KERN_WARNING "%s: controller '%s' not recognized\n",
++			shortname, gadget->name);
++		device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
++	}
++
++
++	/* ok, we made sense of the hardware ... */
++	dev = kzalloc (sizeof *dev, GFP_KERNEL);
++	if (!dev)
++		return -ENOMEM;
++	//memset (dev, 0, sizeof *dev);
++	spin_lock_init (&dev->lock);
++	dev->gadget = gadget;
++	set_gadget_data (gadget, dev);
++
++	/* preallocate control response and buffer */
++	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
++	if (!dev->req)
++		goto enomem;
++
++	//dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
++	//			&dev->req->dma, GFP_KERNEL);
++/*	dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
++	if (!dev->req->buf)
++		goto enomem;
++*/
++        {
++	   struct FTC_ep	*my_ep;
++	   struct FTC_request	*my_req;
++
++       	   my_ep = container_of(gadget->ep0, struct FTC_ep, ep);
++	   my_req = container_of(dev->req, struct FTC_request, req);
++	   //my_req->req.buf = dma_alloc_coherent(&my_ep->dev->gadget.dev,USB_BUFSIZ,&(my_req->req.dma),GFP_KERNEL);
++	   my_req->req.buf = kmalloc(USB_BUFSIZ,GFP_KERNEL);
++
++	   if (!my_req->req.buf) {
++              usb_ep_free_request(gadget->ep0,dev->req);
++              goto enomem;
++           }
++
++	   my_req->req.length = USB_BUFSIZ;
++	   my_ep->dma=1;
++	   printk("device %x== alloc buffer = 0x%x\n", (u32)&my_ep->dev->gadget.dev, (u32) my_req->req.buf);
++	}
++
++	dev->req->complete = ftst_setup_complete;
++	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
++
++	/* assume ep0 uses the same value for both speeds ... */
++	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
++
++	/* and that all endpoints are dual-speed */
++	hs_bulkin_desc.bEndpointAddress = fs_bulkin_desc.bEndpointAddress;
++	hs_bulkout_desc.bEndpointAddress = fs_bulkout_desc.bEndpointAddress;
++	hs_intrin_desc.bEndpointAddress = fs_intrin_desc.bEndpointAddress;
++	hs_introut_desc.bEndpointAddress = fs_introut_desc.bEndpointAddress;
++
++	if (gadget->is_otg) {
++		otg_descriptor.bmAttributes |= USB_OTG_HNP,
++		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++	}
++
++	if (gadget->is_otg) {
++		otg_descriptor.bmAttributes |= USB_OTG_HNP,
++		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++	}
++
++	usb_gadget_set_selfpowered (gadget);
++
++	init_timer (&dev->resume);
++	dev->resume.function = ftst_autoresume;
++	dev->resume.data = (unsigned long) dev;
++	if (autoresume) {
++		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
++	}
++
++	gadget->ep0->driver_data = dev;
++
++	INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
++	INFO (dev, "using %s, BULKIN %s BULKOUT %s \n INTRIN %s INTROUT %s\n", gadget->name,
++		EP_BULK_IN_NAME, EP_BULK_OUT_NAME,EP_INTR_IN_NAME,EP_INTR_OUT_NAME);
++
++	snprintf (manufacturer, sizeof manufacturer, " with %s",  //"%s %s with %s",
++		//system_utsname.sysname, system_utsname.release,
++		gadget->name);
++
++	return 0;
++
++enomem:
++	ftst_unbind (gadget);
++	return -ENOMEM;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void
++ftst_suspend (struct usb_gadget *gadget)
++{
++   struct ftst_dev		*dev = get_gadget_data (gadget);
++
++   if (gadget->speed == USB_SPEED_UNKNOWN)
++      return;
++
++   if (autoresume) {
++      mod_timer (&dev->resume, jiffies + (HZ * autoresume));
++      DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
++   }
++   else
++      DBG (dev, "suspend\n");
++}
++
++static void
++ftst_resume (struct usb_gadget *gadget)
++{
++   struct ftst_dev		*dev = get_gadget_data (gadget);
++
++   DBG (dev, "resume\n");
++   del_timer (&dev->resume);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_gadget_driver ftst_driver = {
++	.max_speed	= USB_SPEED_HIGH,
++	.function	= (char *) longname,
++	.unbind		= ftst_unbind,
++
++	.setup		= ftst_setup,
++	.disconnect	= ftst_disconnect,
++
++	.suspend	= ftst_suspend,
++	.resume		= ftst_resume,
++
++	.driver 	= {
++		.name		= (char *) shortname,
++		// .shutdown = ...
++		// .suspend = ...
++		// .resume = ...
++	},
++};
++
++MODULE_AUTHOR ("John/CTD");
++MODULE_LICENSE ("Dual BSD/GPL");
++
++static int __init init (void)
++{
++	/* a real value would likely come through some id prom
++	 * or module option.  this one takes at least two packets.
++	 */
++	strlcpy (serial, "0123456789012345678901234567890123", sizeof serial);
++
++	return usb_gadget_probe_driver (&ftst_driver, ftst_bind);
++}
++module_init (init);
++
++static void __exit cleanup (void)
++{
++	usb_gadget_unregister_driver (&ftst_driver);
++}
++module_exit (cleanup);
+diff --git a/drivers/usb/gadget/GM_test.h b/drivers/usb/gadget/GM_test.h
+new file mode 100644
+index 00000000..729934e5
+--- /dev/null
++++ b/drivers/usb/gadget/GM_test.h
+@@ -0,0 +1,114 @@
++#ifndef GM_TEST_H_CHK
++#define GM_TEST_H_CHK
++
++#define TST_RXT_ID   0x4e
++#define TST_BULK_IN  0x1
++#define TST_BULK_OUT 0x2
++#define TST_INT_IN   0x3
++#define TST_INT_OUT  0x4
++
++
++#ifdef USB_GLOBALS
++	#define  USB_EXT
++#else
++	#define  USB_EXT extern
++#endif
++
++//================ 2.Define for Bulk =====================================================================================
++	#define MAX_BUFFER_SIZE	0x1000
++	#define DBUS_RD				1
++	#define DBUS_WR				2
++	#define APB_RD				3
++	#define APB_WR				4
++	#define DBUS2APB			5
++	#define APB2DBUS			6
++
++	#define CBW_SIGNATE				0x43425355
++	#define CSW_SIGNATE				0x53425355
++	#define CSW_STATUS_CMD_PASS			0x00
++	#define CSW_STATUS_CMD_FAIL			0x01
++	#define CSW_STATUS_PHASE_ERROR		0x02
++
++	typedef enum 
++	{
++		IDLE,
++		STATE_CBW,
++		STATE_CB_DATA_IN,
++		STATE_CB_DATA_OUT,
++		STATE_CSW
++	} MassStorageState;
++
++	typedef struct CommandBlockWrapper
++	{
++		volatile u32 u32Signature;
++		volatile u32 u32Tag;
++		volatile u32 u32DataTransferLength;
++		volatile u8 u8Flags;
++		volatile u8 u8LUN;
++		volatile u8 u8CBLength;
++		volatile u8 u8CB[16];
++	} CBW;
++
++	typedef struct CommandStatusWrapper
++	{
++		volatile u32 u32Signature;
++		volatile u32 u32Tag;
++		volatile u32 u32DataResidue;
++		volatile u8 u8Status;
++	} CSW;
++#if 0
++	extern CBW tCBW;
++	extern CSW tCSW;
++	extern MassStorageState eUsbMassStorageState;
++	
++	extern u8   u8VirtMemory[MAX_BUFFER_SIZE];
++	extern u32*   u32VirtMemory;
++	extern u16   u16VirtMemoryIndex;
++#endif	
++	extern u32	 u32FIFOUseDMA;
++	extern u32	 u32UseDMAChannel;
++	extern u8   bDMARunning;
++//	extern BOOLEAN bDxDoneAlready;
++	
++	extern void vUsb_F2_Out(u16 u16FIFOByteCount);
++	extern void vUsb_F0_In(void);
++	// void vUsb_APInit(struct zero_dev *dev);
++	extern void vCheckDMA(u32 Channel, u32 FIFONum);
++
++//================ 3.Define for Interrupt =====================================================================================
++	#define IntTransSizeFix 		0
++#if 0	
++	extern u8 *u8InterruptArray;
++	extern u8 u8InterruptCount;
++	extern u8 u8Interrupt_TX_COUNT ;
++	
++	extern u8 u8InterruptOutCount ;
++	extern u8 u8Interrupt_RX_COUNT ;
++#endif
++	extern void vUsb_Interrupt_In(void);
++	extern void vUsb_Interrupt_Out(void);
++
++//================   Define for Isochronous =========================
++	#define ISO_Wrap 	254
++	
++	extern u32 *u32ISOArray;
++	extern u32 u32ISOInTransferCount;
++	extern u32 u32ISOOutTransferCount;
++	extern u32 u32ISOINTest[4096];
++	//extern fLib_DMA_CH_t DMAChannel_Iso;
++	extern u32 u32DMAStatus;
++	extern u32 *u32ISOOutArray;
++	extern u32 u8ISOOutCount ;
++
++	extern void vUsb_ISO_Initial(void);
++	extern void vUsb_ISO_In(void);
++	extern void vUsb_ISO_Out(void);
++	extern void vAHB_DMAInitial(u32 Channel, u32 SrcWidth,
++				u32 DstWidth, u32 SrcSize, u32 SrcCtrl, u32 DstCtrl, 
++				u32 Priority, u32 Mode);
++
++	extern void vAHB_DMA_WaitIntStatus(u32 Channel);
++	
++
++#endif /* GM_TEST_H_CHK */
++
+diff --git a/drivers/usb/gadget/GM_udc.c b/drivers/usb/gadget/GM_udc.c
+new file mode 100644
+index 00000000..7d5464bc
+--- /dev/null
++++ b/drivers/usb/gadget/GM_udc.c
+@@ -0,0 +1,1271 @@
++/*******************************************************************************
++ * Module name: fotg2xx_udc.c
++ *
++ * Copyright 2006 GM as an unpublished work.
++ * All Rights Reserved.
++ *
++ * The Information contained herein is confidential property of Company.
++ * The user, copying, transfer or disclosure of such Information is
++ * prohibited except by express written agreement with Company.
++ *
++ * Written on 2006/6 by Elliot Hou Au-ping.
++ *
++ * Module Description:
++ *  This OTG UDC dirver for GM FOTG220 controller
++ *
++ ******************************************************************************/
++#ifdef CONFIG_USB_DEBUG
++        #define DEBUG
++#else
++        #undef DEBUG
++#endif
++        #define DEBUG
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/usb/otg.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++#include <linux/moduleparam.h>
++#include <linux/dma-mapping.h>
++#include <linux/cdev.h>
++#include <linux/syscalls.h>
++#include <asm/uaccess.h>
++#include <mach/ftpmu010.h>
++
++#include "GM_udc.h"
++//#include "../host/fotg2xx_opt-macro.h"
++
++#if defined(CONFIG_PLATFORM_GM8210)
++#include <mach/ftpmu010_pcie.h>
++#endif
++#if defined(CONFIG_PLATFORM_GM8136)
++#include <mach/platform/board.h>
++#endif
++
++extern void fotg200_handle_irq(int irq);
++extern u32 get_fotg2xx_va(int num);
++extern u32 get_fotg2xx_irq(int num);
++extern int usb_get_pmu_fd(void);
++
++//#define CONFIG_GM_OTG_CHOOSE 0
++#define USB_USER_NAME "usb_gadget"
++
++
++#define	DRIVER_DESC	"FOTG2XX USB Device Controller"
++#define	DRIVER_VERSION	"04-Oct 2004"
++
++#define USB_NOTIFY
++#undef USB_NOTIFY
++/* Used for Signal to User Process */
++static dev_t dev_num;
++static struct cdev usb_cdev;
++static struct class *usb_class = NULL;
++static pid_t pid = 0;
++
++static const char driver_name [] = "fotg2xx_udc";
++static const char driver_desc [] = DRIVER_DESC;
++
++static char *names [] = {"ep0","ep1-bulkin","ep2-bulkout","ep3-intin","ep4-intout","ep5","ep6","ep7","ep8","ep9","ep10" };
++#define BULK_IN_EP_NUM		1
++#define BULK_OUT_EP_NUM		2
++#define INTR_IN_EP_NUM		3
++#define INTR_OUT_EP_NUM		4
++
++static struct FTC_udc *fotg210_udc = NULL;
++
++/*-------------------------------------------------------------------------*/
++
++static void nuke(struct FTC_ep *, int status);
++
++///////////////////////////////////////////////////////////////////////
++// Enable endpoint
++// EP0 : has been enabled while driver booting up
++// Need to give this EP's descriptor
++static int FTC_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
++{
++	struct FTC_udc	*dev;
++	struct FTC_ep	*ep;
++	u16	max;
++	unsigned long flags;
++
++	ep = container_of(_ep, struct FTC_ep, ep);
++
++	DBG_CTRLL("+FTC_ep_enable() : _ep = %x desc = %x ep->desc= %x\n",(u32) _ep, (u32) desc, (u32) ep->desc);
++
++	// check input variable, if there ia any variable undefined, return false
++	if (!_ep || !desc || ep->desc
++			 || desc->bDescriptorType != USB_DT_ENDPOINT) {
++		return -EINVAL;
++	}
++
++	// if this is used to enable ep0, return false
++	dev = ep->dev;
++	if (ep == &dev->ep[0]) {  //no EP0 need to be enabled
++		return -EINVAL;
++	}
++
++	// if upper level driver not ready or device speed unknown, return false
++	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
++		return -EINVAL;
++	}
++
++	if (ep->num != (desc->bEndpointAddress & 0x0f)) {
++		return -EINVAL;
++	}
++
++	// EP should be Bulk or intr
++	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
++		case USB_ENDPOINT_XFER_BULK:
++		case USB_ENDPOINT_XFER_INT:
++			break;
++		default:
++			return -EINVAL;
++	}
++
++	/* enabling the no-toggle interrupt mode would need an api hook */
++	// max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
++	 max = le16_to_cpu(desc->wMaxPacketSize);
++
++	// 11/2/05' AHB_DMA
++	// Only bulk use AHB_DMA, and not always use DMA, so change while running
++	//if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
++	//   ep->dma = 1;
++	//else
++	ep->dma = 0;		// right now we choice not to use dma
++
++	ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0;
++
++	spin_lock_irqsave(&ep->dev->lock, flags);
++
++	ep->ep.maxpacket = max;
++	ep->stopped = 0;
++	ep->dma_running= FALSE;
++	ep->desc = desc;
++	spin_unlock_irqrestore(&ep->dev->lock, flags);
++
++	printk("enable %s %s maxpacket %u\n", ep->ep.name,
++		   ep->is_in ? "IN" : "OUT",
++		   // ep->dma ? "dma" : "pio",
++		   max);
++
++#if defined(USB_NOTIFY)
++	sys_kill(pid, SIGUSR1);
++#endif
++
++	return 0;
++}
++
++static void ep_reset(struct FTC_ep *ep)
++{
++	//struct FTC_udc		*dev = ep->dev;
++	DBG_FUNCC("+ep_reset\n");
++
++	ep->ep.maxpacket = MAX_FIFO_SIZE;
++	ep->desc = 0;
++	ep->stopped = 1;
++	ep->irqs = 0;
++	ep->dma = 0;
++}
++
++static int FTC_ep_disable(struct usb_ep *_ep)
++{
++	struct FTC_ep	*ep;
++	struct FTC_udc	*dev;
++	unsigned long	flags;
++
++	DBG_FUNCC("+FTC_ep_disable()\n");
++
++	ep = container_of(_ep, struct FTC_ep, ep);
++	if (!_ep || !ep->desc)
++		return -ENODEV;
++
++	//printk("+FTC_ep_disable() : _ep = 0x%x ep->desc = 0x%x\n", _ep , ep->desc);
++	dev = ep->dev;
++
++	//John mark for in suspend will reset system
++	//john if (dev->ep0state == EP0_SUSPEND)
++	//john 	return -EBUSY;
++
++	if (ep == &dev->ep[0])  //john no EP0 need to be enabled
++		return -EINVAL;
++
++	Vdbg(dev, "disable %s\n", _ep->name);
++
++	spin_lock_irqsave(&dev->lock, flags);
++	nuke(ep, -ESHUTDOWN);
++	ep_reset(ep);
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++
++	return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_request *FTC_alloc_request(struct usb_ep *_ep, unsigned gfp_flags)
++{
++    struct FTC_request	*req;
++
++    DBG_FUNCC("+FTC_alloc_request\n");
++    if (!_ep)
++        return 0;
++
++    req = kmalloc(sizeof *req, gfp_flags);
++    if (!req)
++        return 0;
++
++    memset(req, 0, sizeof *req);
++    req->req.dma = DMA_ADDR_INVALID;
++
++    INIT_LIST_HEAD(&req->queue);
++
++    DBG_FUNCC("-FTC_alloc_request\n");
++    return &req->req;
++}
++
++static void FTC_free_request(struct usb_ep *_ep, struct usb_request *_req)
++{
++	struct FTC_request	*req;
++
++	DBG_FUNCC("+FTC_free_request()\n");
++
++	if (!_ep || !_req)
++		return;
++
++	req = container_of(_req, struct FTC_request, req);
++	WARN_ON(!list_empty(&req->queue));
++	kfree(req);
++}
++
++/*-------------------------------------------------------------------------*/
++// finish/abort one request
++static void done(struct FTC_ep *ep, struct FTC_request *req, int status)
++{
++    struct FTC_udc		*dev;
++    unsigned stopped = ep->stopped;
++
++    DBG_FUNCC("+done()\n");
++
++    list_del_init(&req->queue);
++
++    if (likely(req->req.status == -EINPROGRESS))   // still ongoing
++        req->req.status = status;
++    else // has finished
++        status = req->req.status;
++
++    dev = ep->dev;
++
++    if (req->mapped)  // DMA mapped
++    {
++        u32 temp;
++        DBG_CTRLL("....dma_unmap_single len = %x dma =%x, dir=%x dev=%x\n",
++                req->req.length,req->req.dma,ep->is_in,dev);
++
++        // important : DMA length will set as 16*n bytes
++        temp = (req->req.length + 15) / 16;
++        temp = temp *16;
++        dma_unmap_single((void *)dev, req->req.dma, temp,  //USB_EPX_BUFSIZ,
++                ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
++        req->req.dma = DMA_ADDR_INVALID;
++        req->mapped = 0;
++    }
++
++#ifndef USB_TRACE
++    if (status && status != -ESHUTDOWN)
++#endif
++        Vdbg(dev, "complete %s req %p stat %d len %u/%u\n",
++                ep->ep.name, &req->req, status,
++                req->req.actual, req->req.length);
++
++    /* don't modify queue heads during completion callback */
++    if (status == -ESHUTDOWN)
++        ep->stopped = 0;
++    else
++        ep->stopped = 1;
++
++    spin_unlock(&dev->lock);
++
++    req->req.complete(&ep->ep, &req->req);
++    spin_lock(&dev->lock);
++
++    if (ep->num==0)
++        mUsbEP0DoneSet(ep->dev->va_base);
++
++    ep->stopped = stopped;  //recover
++
++    DBG_FUNCC("-done() stopped=%d\n",stopped);
++}
++
++
++/* dequeue ALL requests */
++static void nuke(struct FTC_ep *ep, int status)
++{
++	struct FTC_request	*req;
++	DBG_FUNCC("+nuke() ep addr= 0x%x\n", (u32) ep);
++
++	ep->stopped = 1;
++	if (list_empty(&ep->queue))
++		return;
++	while (!list_empty(&ep->queue))
++	{
++		req = list_entry(ep->queue.next, struct FTC_request, queue);
++		done(ep, req, status);
++	}
++}
++
++
++static int FTC_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags);
++
++/* dequeue JUST ONE request */
++static int FTC_dequeue(struct usb_ep *_ep, struct usb_request *_req)
++{
++    struct FTC_request	*req;
++    struct FTC_ep		*ep;
++    struct FTC_udc		*dev;
++    unsigned long		flags;
++
++    DBG_FUNCC("+FTC_dequeue()\n");
++
++    ep = container_of(_ep, struct FTC_ep, ep);
++    if (!_ep || !_req || (!ep->desc && ep->num != 0))
++        return -EINVAL;
++    dev = ep->dev;
++    if (!dev->driver)
++        return -ESHUTDOWN;
++
++    /* we can't touch (dma) registers when suspended */
++    if (dev->ep0state == EP0_SUSPEND)
++        return -EBUSY;
++
++    Vdbg(dev, "%s %s %s %s %p\n", __FUNCTION__, _ep->name,
++            ep->is_in ? "IN" : "OUT",
++            ep->dma ? "dma" : "pio",
++            _req);
++
++    spin_lock_irqsave(&dev->lock, flags);
++
++    /* make sure it's actually queued on this endpoint */
++    list_for_each_entry (req, &ep->queue, queue)
++    {
++        if (&req->req == _req)
++            break;
++    }
++    if (&req->req != _req)
++    {
++        spin_unlock_irqrestore (&dev->lock, flags);
++        return -EINVAL;
++    }
++
++    if (!list_empty(&req->queue))
++    {
++        done(ep, req, -ECONNRESET);
++    }
++    else
++        req = 0;
++
++    spin_unlock_irqrestore(&dev->lock, flags);
++
++    return req ? 0 : -EOPNOTSUPP;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void FTC_clear_halt(struct FTC_ep *ep)
++{
++    DBG_FUNCC("+FTC_clear_halt()(ep->num=%d)\n",ep->num);
++
++    // assert (ep->num !=0)
++    Vdbg(ep->dev, "%s clear halt\n", ep->ep.name);
++    if (ep->num == 0)
++    {
++        ep->dev->ep0state = EP0_IDLE;
++        ep->dev->ep[0].stopped = 0;
++    }
++    else
++    {
++        if (ep->is_in)	// IN direction ?
++        {
++            DBG_CTRLL("FTC_udc==>FTC_clear_halt()==>IN direction, EP%d \n",ep->num);
++            mUsbEPinRsTgSet(ep->dev->va_base,ep->num);	// Set Rst_Toggle Bit
++            mUsbEPinRsTgClr(ep->dev->va_base,ep->num);	// Clear Rst_Toggle Bit
++            mUsbEPinStallClr(ep->dev->va_base,ep->num);	// Clear Stall Bit
++        }
++        else
++        {
++            DBG_CTRLL("FTC_udc==>FTC_clear_halt()==>OUT direction, EP%d \n",ep->num);
++            mUsbEPoutRsTgSet(ep->dev->va_base,ep->num);	// Set Rst_Toggle Bit
++            mUsbEPoutRsTgClr(ep->dev->va_base,ep->num);	// Clear Rst_Toggle Bit
++            mUsbEPoutStallClr(ep->dev->va_base,ep->num);	// Clear Stall Bit
++        }
++    }
++    DBG_CTRLL("FTC_udc==>FTC_clear_halt()==>ep->stopped = %d\n",ep->stopped);
++
++    if (ep->stopped)
++    {
++        ep->stopped = 0;
++    }
++}
++
++static int FTC_set_halt(struct usb_ep *_ep, int value)
++{
++    struct FTC_ep	*ep;
++    unsigned long	flags;
++    int		retval = 0;
++
++    DBG_FUNCC("+FTC_set_halt()\n");
++    if (!_ep)
++        return -ENODEV;
++    ep = container_of (_ep, struct FTC_ep, ep);
++
++    DBG_BULKK("FTC_set_halt()===> (ep->num=%d)(Value=%d)\n",ep->num,value);
++
++    //*********** Process the EP-0 SetHalt *******************
++    if (ep->num == 0) {
++        if (value == PROTO_STALL) {    // protocol stall, need H/W to reset
++            mUsbEP0StallSet(ep->dev->va_base);
++        } else if (value == FUNC_STALL) {   // function stall, SW to set/clear, nad EP0 work normally
++            ep->dev->ep0state = EP0_STALL;
++            ep->dev->ep[0].stopped = 1;
++        } else if (value == CLEAR_STALL) {    // clear function stall, SW to set/clear, nad EP0 work normally
++            ep->dev->ep0state = EP0_IDLE;
++            ep->dev->ep[0].stopped = 0;
++        }
++        return retval; //EP0 Set Halt will return here
++
++    } else if (!ep->desc) { /* don't change EPxSTATUS_EP_INVALID to READY */
++        Info(ep->dev, "%s %s inactive?\n", __FUNCTION__, ep->ep.name);
++        return -EINVAL;
++    }
++
++    //*********** Process the EP-X SetHalt *******************
++    spin_lock_irqsave(&ep->dev->lock, flags);
++
++    if (!list_empty(&ep->queue)) {   // something in queue
++        retval = -EAGAIN;
++    } else if (!value) {
++        FTC_clear_halt(ep);
++    } else {
++        ep->stopped = 1;
++        Vdbg(ep->dev, "%s set halt\n", ep->ep.name);
++
++        if (ep->is_in) { // IN direction ?
++            printk("set in stall bit\n");
++            mUsbEPinStallSet(ep->dev->va_base,ep->num); // Set in Stall Bit
++        } else {
++            printk("set out stall bit\n");
++            mUsbEPoutStallSet(ep->dev->va_base,ep->num); // Set out Stall Bit
++        }
++    }
++    spin_unlock_irqrestore(&ep->dev->lock, flags);
++    return retval;
++}
++
++
++
++//********************************************************
++//Name: FTC_fifo_status
++//Description:
++//
++//********************************************************
++static int FTC_fifo_status(struct usb_ep *_ep)
++{
++	struct FTC_ep *ep;
++	u8     u8fifo_n;   //john
++	u32	   size;
++
++	DBG_FUNCC("+FTC_fifo_status()\n");
++
++	if (!_ep)
++		return -ENODEV;
++	ep = container_of(_ep, struct FTC_ep, ep);
++
++	DBG_BULKK("FTC_udc-->FTC_fifo_status-->Check (size is only reported sanely for OUT)");
++	/* size is only reported sanely for OUT */
++	if (ep->is_in)
++	{
++		DBG_BULKK("FTC_udc-->FTC_fifo_status-->return -EOPNOTSUPP (ep->is_in)");
++		return -EOPNOTSUPP;
++	}
++
++	//John for FUSB220
++	if (ep->num ==0)
++	{   	//EP0
++		// note : for EP0, only know empty or not
++		size = !mUsbEP0EMPFIFO(ep->dev->va_base);
++	}
++	else
++	{
++		DBG_BULKK("FTC_udc-->FTC_fifo_status-->ep->num >0 ");
++
++		u8fifo_n = mUsbEPMapRd(ep->dev->va_base,ep->num); // get the relatived FIFO number
++		if (ep->is_in)
++			u8fifo_n &= 0x0F;
++		else
++			u8fifo_n >>= 4;
++		if (u8fifo_n >= FUSB220_MAX_FIFO) // over the Max. fifo count ?
++			return -ENOBUFS;
++
++		// Check the FIFO had been enable ?
++		if ((mUsbFIFOConfigRd(ep->dev->va_base,u8fifo_n) & 0x80) == 0)
++			return -ENOBUFS;
++
++		size = mUsbFIFOOutByteCount(ep->dev->va_base,u8fifo_n);
++		Vdbg(ep->dev, "%s %s %u\n", __FUNCTION__, ep->ep.name, size);
++	}
++	return size;
++}
++
++static void FTC_fifo_flush(struct usb_ep *_ep)
++{
++    struct FTC_ep *ep;
++    u8     u8fifo_n;   //john
++
++    DBG_FUNCC("+FTC_fifo_flush()\n");
++
++    if (!_ep)
++        return;
++    ep = container_of(_ep, struct FTC_ep, ep);
++    Vdbg(ep->dev, "%s %s\n", __FUNCTION__, ep->ep.name);
++
++    /* don't change EPxSTATUS_EP_INVALID to READY */
++    if (!ep->desc && ep->num != 0)
++    {
++        udc_dbg(ep->dev, "%s %s inactive?\n", __FUNCTION__, ep->ep.name);
++        return;
++    }
++
++    //John for FUSB220
++    if (ep->num ==0)
++    {   //EP0
++        mUsbEP0ClearFIFO(ep->dev->va_base);
++    }
++    else
++    {
++        u8fifo_n = mUsbEPMapRd(ep->dev->va_base,ep->num); // get the relatived FIFO number
++        if (ep->is_in)
++            u8fifo_n &= 0x0F;
++        else
++            u8fifo_n >>= 4;
++        if (u8fifo_n >= FUSB220_MAX_FIFO) // over the Max. fifo count ?
++            return;
++
++        // Check the FIFO had been enable ?
++        if ((mUsbFIFOConfigRd(ep->dev->va_base,u8fifo_n) & 0x80) == 0)
++            return;
++
++        mUsbFIFOReset(ep->dev->va_base,u8fifo_n); //reset FIFO
++        udelay(10);
++        mUsbFIFOResetOK(ep->dev->va_base,u8fifo_n); //reset FIFO finish
++    }
++    return;
++}
++
++static struct usb_ep_ops FTC_ep_ops =
++{
++	.enable	        = FTC_ep_enable,
++	.disable	    = FTC_ep_disable,
++
++	.alloc_request	= FTC_alloc_request,
++	.free_request	= FTC_free_request,
++
++	.queue	        = FTC_queue,
++	.dequeue	    = FTC_dequeue,
++
++	.set_halt	    = FTC_set_halt,
++
++	.fifo_status    = FTC_fifo_status,
++	.fifo_flush	    = FTC_fifo_flush,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int FTC_get_frame(struct usb_gadget *_gadget)
++{
++	struct FTC_udc	*dev;
++	u16 retval;
++	unsigned long	flags;
++
++	DBG_FUNCC("+FTC_get_frame()\n");
++
++	if (!_gadget)
++		return -ENODEV;
++	dev = container_of (_gadget, struct FTC_udc, gadget);
++	spin_lock_irqsave (&dev->lock, flags);
++	retval = ( (mUsbFrameNoHigh(dev->va_base) & 0x07) <<8) | mUsbFrameNoLow(dev->va_base);
++	spin_unlock_irqrestore (&dev->lock, flags);
++
++	return retval;
++}
++
++static int FTC_wakeup(struct usb_gadget *_gadget)
++{
++	struct FTC_udc	*dev;
++	unsigned long	flags;
++	DBG_FUNCC("+FTC_wakeup()\n");
++
++	if (!_gadget)
++		return -ENODEV;
++	dev = container_of (_gadget, struct FTC_udc, gadget);
++	spin_lock_irqsave (&dev->lock, flags);
++
++	// Set "Device_Remote_Wakeup", Turn on the"RMWKUP" bit in Mode Register
++	mUsbRmWkupSet(dev->va_base);
++	spin_unlock_irqrestore (&dev->lock, flags);
++	return 0;
++}
++
++static int FTC_set_selfpowered(struct usb_gadget *_gadget, int value)
++{
++	DBG_FUNCC("+FTC_set_selfpowered()\n");
++	return -EOPNOTSUPP;
++}
++
++#define USB_ENABLE_DMA 1
++#define USB_DISABLE_DMA 2
++static int FTC_ioctl(struct usb_gadget *_gadget, unsigned code, unsigned long param)
++{
++	unsigned long	flags;
++	struct FTC_udc	*dev;
++	struct FTC_ep	*ep;
++	struct usb_ep   *_ep;
++
++	DBG_FUNCC("+FTC_ioctl()\n");
++
++	if (!_gadget)
++		return -ENODEV;
++	dev = container_of (_gadget, struct FTC_udc, gadget);
++	spin_lock_irqsave (&dev->lock, flags);
++
++	switch (code)
++	{
++		case USB_ENABLE_DMA:   //DMA enable from others
++			_ep = (struct usb_ep *)param;
++			ep = container_of(_ep, struct FTC_ep, ep);
++			ep->dma=1;
++			break;
++		case USB_DISABLE_DMA:   //DMA disable from others
++			_ep = (struct usb_ep *)param;
++			ep = container_of(_ep, struct FTC_ep, ep);
++			ep->dma=0;
++			break;
++		default:
++			break;
++	}
++
++	spin_unlock_irqrestore (&dev->lock, flags);
++	return -EOPNOTSUPP;
++}
++
++#include "fotg2xx_udc.c"
++
++static void udc_enable(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+udc_enable()\n");
++
++	// Enable usb200 global interrupt
++	mUsbGlobIntEnSet(dev->va_base);
++	mUsbChipEnSet(dev->va_base);
++}
++
++static int FTC_start(struct usb_gadget_driver *driver,
++		int (*bind)(struct usb_gadget *))
++{
++    int retval = 0;
++
++    if (!fotg210_udc)
++        return -ENODEV;
++
++    if (!driver
++            || driver->max_speed < USB_SPEED_FULL
++            || !bind
++            || !driver->setup)
++        return -EINVAL;
++
++    if (fotg210_udc->driver)
++        return -EBUSY;
++
++    /* Disable Global Interrupt to prevent useless irq */
++    mUsbGlobIntDis(fotg210_udc->va_base);
++
++    /* hook up the driver */
++    fotg210_udc->driver = driver;
++    fotg210_udc->gadget.dev.driver = &driver->driver;
++
++    retval = bind(&fotg210_udc->gadget);
++
++    if (retval) {
++        printk("bind to driver %s --> error %d\n", driver->driver.name, retval);
++        fotg210_udc->driver = 0;
++        return retval;
++    }
++
++    /* then enable host detection and ep0; and we're ready
++     * for set_configuration as well as eventual disconnect.
++     */
++    mUsbUnPLGClr(fotg210_udc->va_base);
++#ifndef CONFIG_USB_GADGET
++    *((volatile u32 *) (fotg210_udc->va_base | 0x134)) = 0;
++    *((volatile u32 *) (fotg210_udc->va_base | 0x138)) = 0;
++    *((volatile u32 *) (fotg210_udc->va_base | 0x13C)) = 0;
++#endif
++    vUsbInit(fotg210_udc);
++    udc_enable(fotg210_udc);
++
++    DBG_FUNCC("%s\n", __func__);
++    return 0;
++}
++
++static void stop_activity(struct FTC_udc *dev, struct usb_gadget_driver *driver)
++{
++	unsigned	i;
++
++	udc_dbg(dev, "%s\n", __FUNCTION__);
++
++	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
++		driver = 0;
++
++	// disconnect gadget driver after quiesceing hw and the driver
++	/*
++	 * When connecting to PC and then reboot, udc_reset here will cause kernel panic
++	 * eason@2011/10/04
++	 */
++	//udc_reset (dev);
++	for (i = 0; i < FUSB220_CURRENT_SUPPORT_EP; i++)
++		nuke(&dev->ep [i], -ESHUTDOWN);
++	if (driver) {
++		spin_unlock(&dev->lock);
++		driver->disconnect(&dev->gadget);
++		spin_lock(&dev->lock);
++	}
++
++	if (dev->driver)
++		udc_enable(dev);
++}
++
++static int FTC_stop(struct usb_gadget_driver *driver)
++{
++	unsigned long flags;
++
++	DBG_FUNCC("+usb_gadget_unregister_driver()\n");
++
++	if (!fotg210_udc)
++		return -ENODEV;
++	if (!driver || driver != fotg210_udc->driver)
++		return -EINVAL;
++
++	spin_lock_irqsave(&fotg210_udc->lock, flags);
++	stop_activity(fotg210_udc, driver);
++	spin_unlock_irqrestore(&fotg210_udc->lock, flags);
++	driver->unbind(&fotg210_udc->gadget);
++	fotg210_udc->gadget.dev.driver = NULL;
++	fotg210_udc->driver = NULL;
++
++	return 0;
++}
++
++static const struct usb_gadget_ops FTC_ops =
++{
++	.get_frame	     	= FTC_get_frame,
++	.wakeup		     	= FTC_wakeup,
++	.set_selfpowered 	= FTC_set_selfpowered,
++	.ioctl          	= FTC_ioctl,
++    .start              = FTC_start,
++    .stop               = FTC_stop,
++};
++
++/* USB notify user process method */
++static int usb_notify_open(struct inode *inode, struct file *filp)
++{
++	return 0;
++}
++
++static int usb_noify_release(struct inode *inode, struct file *filp)
++{
++	return 0;
++}
++
++#define USB_SET_PID 7788
++static long usb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
++{
++	int ret = 0;
++
++	switch (cmd) {
++		case USB_SET_PID:
++			if (copy_from_user(&pid, (void __user *)arg, sizeof(pid))) {
++				ret = -EFAULT;
++				break;
++			}
++			printk("pid = %d\n", pid);
++			break;
++		default:
++			break;
++	}
++	return ret;
++}
++
++struct file_operations usb_fops = {
++	.owner = THIS_MODULE,
++	.open = usb_notify_open,
++	.release = usb_noify_release,
++	.unlocked_ioctl = usb_ioctl,
++};
++/**********************************/
++
++
++/*-------------------------------------------------------------------------*/
++static void udc_reinit (struct FTC_udc *dev)
++{
++	unsigned i;
++
++	DBG_FUNCC("+udc_reinit()\n");
++
++	INIT_LIST_HEAD (&dev->gadget.ep_list);
++	dev->gadget.ep0 = &dev->ep[0].ep;
++	dev->gadget.speed = USB_SPEED_UNKNOWN;
++	dev->ep0state = EP0_DISCONNECT;
++	dev->irqs = 0;
++
++	for (i = 0; i < FUSB220_CURRENT_SUPPORT_EP; i++)
++	{
++		struct FTC_ep	*ep = &dev->ep[i];
++
++		ep->num = i;
++		ep->ep.name = names[i];
++		DBG_CTRLL("EP%d Name = %s \n",i, ep->ep.name);
++
++		ep->ep.ops = &FTC_ep_ops;
++		list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
++		ep->dev = dev;
++		INIT_LIST_HEAD (&ep->queue);
++		ep_reset(ep);
++	}
++	for (i = 0; i < FUSB220_CURRENT_SUPPORT_EP; i++)
++		dev->ep[i].irqs = 0;
++
++	dev->ep[0].ep.maxpacket = MAX_EP0_SIZE;
++	list_del_init (&dev->ep[0].ep.ep_list);
++	//Info(dev,"L%x: GM UDC reinit finish...\n", dev->u8LineCount ++);
++}
++
++static void udc_reset(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+udc_reset()\n");
++
++	//default value
++	dev->Dma_Status = PIO_Mode;
++	dev->u8LineCount = 0;
++	//Info(dev,"***** FTC OTG controller Device Linux Lower Driver *****\n");
++	//Info(dev,"L%x: System initial, Please wait...\n", dev->u8LineCount ++);
++
++	// initial Reg setup
++	mUsbTstHalfSpeedDis(dev->va_base);		// Set for FPGA Testing 0x02 BIT7
++	mUsbUnPLGClr(dev->va_base);				// 0x08 BIT0
++ 	vUsbInit(dev);
++
++	//Info(dev,"L%x: System reset finish...\n", dev->u8LineCount ++);
++	//Info(dev,"\nInterrupt Mask:0x%x\n",bFUSBPort(0x10));
++}
++
++static irqreturn_t FUSBD_irq(int irq, void *_dev)
++{
++	struct FTC_udc *dev = _dev;
++	u32 status = wFOTGPeri_Port(dev->va_base, 0x84);
++
++    /* status & (OTGC_INT_A_TYPE | OTGC_INT_B_TYPE) */
++	if (status & (BIT0|BIT4|BIT5|BIT8|BIT9|BIT10|BIT11|BIT12)) {
++		fotg200_handle_irq(irq);
++	}
++
++	spin_lock(&dev->lock);
++	dev->usb_interrupt_level1_Save = mUsbIntGroupRegRd(dev->va_base);
++	dev->usb_interrupt_level1_Mask = mUsbIntGroupMaskRd(dev->va_base);
++	dev->usb_interrupt_level1 = dev->usb_interrupt_level1_Save & ~dev->usb_interrupt_level1_Mask;
++
++    /* check Interrupt Group Register(0x140) and Current Role */
++	if (dev->usb_interrupt_level1 != 0 && (wFOTGPeri_Port(dev->va_base, 0x80) & BIT20)){
++		/* fotg2xx_dbg("FTC_irq %x \n",dev->usb_interrupt_level1);*/
++		dev->irqs++;
++
++		//Info(dev,"\nInterrupt Source:0x%x\n",bFUSBPort(0x20));
++		vUsbHandler(dev);
++		// Clear usb interrupt flags
++		dev->usb_interrupt_level1 = 0;
++	}
++
++	spin_unlock(&dev->lock);
++	return IRQ_RETVAL(1);
++}
++
++static void FTC_usb_remove(void)
++{
++    DBG_FUNCC("+FTC_usb_remove()\n");
++
++    /* start with the driver above us */
++    if (fotg210_udc->driver) {
++        /* should have been done already by driver model core */
++        uwarn(dev,"remove driver '%s' is still registered\n",
++                fotg210_udc->driver->driver.name);
++        usb_gadget_unregister_driver(fotg210_udc->driver);
++    }
++
++    udc_reset(fotg210_udc);
++
++    if (fotg210_udc->got_irq) {
++        unsigned irq_no;
++
++#if !defined(CONFIG_PLATFORM_GM8136)
++        irq_no = get_fotg2xx_irq(CONFIG_GM_OTG_CHOOSE);
++#else
++        switch (CONFIG_GM_OTG_CHOOSE) {
++            case 0:
++                irq_no = get_fotg2xx_irq(CONFIG_GM_OTG_CHOOSE);
++                break;
++            case 1:
++                irq_no = USB_FOTG2XX_1_IRQ;
++                break;
++            default:
++                panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++                break;
++        }
++#endif
++        free_irq(irq_no, fotg210_udc);
++        fotg210_udc->got_irq = 0;
++    }
++
++#if defined(CONFIG_PLATFORM_GM8136)
++    if (CONFIG_GM_OTG_CHOOSE == 1)
++        iounmap((void __iomem *) fotg210_udc->va_base);
++#endif
++
++    device_unregister(&(fotg210_udc->gadget.dev));
++
++    kfree(fotg210_udc);
++
++    fotg210_udc = NULL;
++
++#if defined(CONFIG_PLATFORM_GM8126)
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xA0, 0, BIT3);
++#elif defined(CONFIG_PLATFORM_GM8210)
++    switch (CONFIG_GM_OTG_CHOOSE) {
++        case 0:
++            /* Configure OTG0 in host mode */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, 0, BIT0);
++            break;
++        case 1:
++            /* Configure OTG1 in host mode */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, 0, BIT9);
++            break;
++        case 2:
++            /* Configure OTG2 in host mode */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, 0, BIT18);
++            break;
++        default:
++            panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++            break;
++    }
++#elif defined(CONFIG_PLATFORM_GM8287)
++    switch (CONFIG_GM_OTG_CHOOSE) {
++        case 0:
++            /* Configure OTG0 in host mode */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, 0, BIT2);
++            break;
++        case 1:
++            /* Configure OTG1 in host mode */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC8, 0, BIT2);
++            break;
++        default:
++            panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++            break;
++    }
++#elif defined(CONFIG_PLATFORM_GM8139)
++    /* Configure OTG0 in host mode */
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, 0, BIT2);
++#elif defined(CONFIG_PLATFORM_GM8136)
++    switch (CONFIG_GM_OTG_CHOOSE) {
++        case 0:
++            /* Configure OTG0 in host mode */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, 0, BIT2);
++            break;
++        case 1:
++            /* Configure OTG1 in host mode */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, 0, BIT0);
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xB4, BIT16, BIT16);
++            break;
++        default:
++            panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++            break;
++    }
++#endif
++
++    //Info(dev,"USB device unbind\n");
++}
++
++void release_dummy(struct device *dev)
++{
++   return;
++}
++/* wrap this driver around the specified pci device, but
++ * don't respond over USB until a gadget driver binds to us.
++ */
++//Trace ok 12212004
++static int FTC_usb_probe(void)
++{
++    int	retval = 0;
++
++    DBG_FUNCC("+FTC_usb_probe()\n");
++    printk("CONFIG_GM_OTG_CHOOSE=%d\n", CONFIG_GM_OTG_CHOOSE);
++
++    //<1>.Init struct FTC_udc structure
++    /* alloc, and start init */
++    spin_lock_init(&fotg210_udc->lock);
++
++    /* the "gadget" abstracts/virtualizes the controller */
++    fotg210_udc->enabled = 1;
++    fotg210_udc->EPUseDMA = DMA_CHANEL_FREE;
++    fotg210_udc->ReqForDMA = 0;
++#if !defined(CONFIG_PLATFORM_GM8136)
++    fotg210_udc->va_base = get_fotg2xx_va(CONFIG_GM_OTG_CHOOSE);
++#else
++    switch (CONFIG_GM_OTG_CHOOSE) {
++        case 0:
++            fotg210_udc->va_base = get_fotg2xx_va(CONFIG_GM_OTG_CHOOSE);
++            break;
++        case 1:
++            fotg210_udc->va_base = (u32) ioremap_nocache(USB_FOTG2XX_1_PA_BASE, USB_FOTG2XX_1_PA_SIZE);
++            break;
++        default:
++            panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++            break;
++    }
++#endif
++    fotg210_udc->gadget.ops = &FTC_ops;
++    fotg210_udc->gadget.name = driver_name;
++#if !defined(CONFIG_PLATFORM_GM8136)
++	fotg210_udc->gadget.max_speed = USB_SPEED_HIGH;
++#else
++    switch (CONFIG_GM_OTG_CHOOSE) {
++        case 0:
++            fotg210_udc->gadget.max_speed = USB_SPEED_HIGH;
++            break;
++        case 1:
++            fotg210_udc->gadget.max_speed = USB_SPEED_FULL;
++            break;
++        default:
++            panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++            break;
++    }
++#endif
++
++    fotg210_udc->gadget.dev.parent = NULL;
++    fotg210_udc->gadget.dev.dma_mask = (void *)0xffffffff;
++    fotg210_udc->gadget.dev.coherent_dma_mask = 0xffffffff;
++    fotg210_udc->gadget.dev.release = &release_dummy;
++
++	dev_set_drvdata(&fotg210_udc->gadget.dev, fotg210_udc);
++    dev_set_name(&fotg210_udc->gadget.dev, driver_name);
++
++    retval = device_register (&(fotg210_udc->gadget.dev));
++    if (retval < 0) {
++        printk("%s: device_register() failed\n", __func__);
++        goto done;
++    }
++
++#if defined(CONFIG_PLATFORM_GM8126)
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xA0, 0, (BIT0|BIT1|BIT2)<<17);
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xA0, BIT1<<17, BIT1<<17); // config reference voltage to 120mV
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xA0, BIT0, BIT0); // enable VBUS input
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xA0, BIT3, BIT3); // set to device mode
++#elif defined(CONFIG_PLATFORM_GM8210)
++    switch (CONFIG_GM_OTG_CHOOSE) {
++        case 0:
++            /* Configure OTG0 in device mode */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, BIT0, BIT0);
++            /* Enable OTG0 VBUS input */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, BIT1, BIT1);
++            break;
++        case 1:
++            /* Configure OTG1 in device mode */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, BIT0, BIT9);
++            /* Enable OTG1 VBUS input */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, BIT10, BIT10);
++            break;
++        case 2:
++            /* Configure OTG2 in device mode */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, BIT0, BIT18);
++            /* Enable OTG2 VBUS input */
++            ftpmu010_pcie_write_reg(usb_get_pmu_fd(), 0x84, BIT19, BIT19);
++            break;
++        default:
++            panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++            break;
++    }
++#elif defined(CONFIG_PLATFORM_GM8287)
++    switch (CONFIG_GM_OTG_CHOOSE) {
++        case 0:
++            /* Configure OTG0 in device mode */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT2, BIT2);
++            /* Enable OTG0 VBUS input */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT3, BIT3);
++            break;
++        case 1:
++            /* Configure OTG1 in device mode */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC8, BIT2, BIT2);
++            /* Enable OTG1 VBUS input */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC8, BIT3, BIT3);
++            break;
++        default:
++            panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++            break;
++    }
++#elif defined(CONFIG_PLATFORM_GM8139)
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT24|BIT25|BIT26, BIT24|BIT25|BIT26);
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT4|BIT5|BIT19, BIT4|BIT5|BIT19);
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xAC, 0, BIT0);
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT6, BIT6);
++    /* Configure OTG0 in device mode */
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT2, BIT2);
++    /* Enable OTG0 VBUS input */
++    ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT3, BIT3);
++#elif defined(CONFIG_PLATFORM_GM8136)
++    switch (CONFIG_GM_OTG_CHOOSE) {
++        case 0:
++            /* Configure OTG0 in device mode */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT2, BIT2);
++            /* Enable OTG0 VBUS input */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT3, BIT3);
++            break;
++        case 1:
++            {
++                /* set pinmux of DP/DM */
++                u32 val;
++
++                val = * (volatile u32 *) (PMU_FTPMU010_VA_BASE + 0x64);
++                val &= ~((0x3 << 16) | (0x3 << 18));
++                val |= (0x1 << 16) | (0x1 << 18);
++                * (volatile u32 *) (PMU_FTPMU010_VA_BASE + 0x64) = val;
++            }
++            /* Configure OTG1 in device mode */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT0, BIT0);
++            /* Enable OTG1 VBUS input */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xC0, BIT1, BIT1);
++            /* Turn on OTG1 gating clock */
++            ftpmu010_write_reg(usb_get_pmu_fd(), 0xB4, 0, BIT16);
++            break;
++        default:
++            panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++            break;
++    }
++#endif
++
++    //<2>. udc Reset/udc reinit
++    /* init to known state, then setup irqs */
++    udc_reset(fotg210_udc);
++    udc_reinit(fotg210_udc);
++
++    //<3>.Init USB DEV ISR
++    if (!fotg210_udc->got_irq) {
++        unsigned irq_no;
++
++#if !defined(CONFIG_PLATFORM_GM8136)
++        irq_no = get_fotg2xx_irq(CONFIG_GM_OTG_CHOOSE);
++#else
++        switch (CONFIG_GM_OTG_CHOOSE) {
++            case 0:
++                irq_no = get_fotg2xx_irq(CONFIG_GM_OTG_CHOOSE);
++                break;
++            case 1:
++                irq_no = USB_FOTG2XX_1_IRQ;
++                break;
++            default:
++                panic("%s: No such UDC id: %d\n", __func__, CONFIG_GM_OTG_CHOOSE);
++                break;
++        }
++#endif
++        if (request_irq(irq_no, FUSBD_irq, IRQF_SHARED, driver_name, fotg210_udc) < 0) {
++            uwarn(dev, "request interrupt failed\n");
++            retval = -EBUSY;
++            goto done;
++        }
++        fotg210_udc->got_irq = 1;
++    }
++    mUsbUnPLGSet(fotg210_udc->va_base);
++
++    retval = usb_add_gadget_udc(&(fotg210_udc->gadget.dev), &fotg210_udc->gadget);
++    if (retval)
++        goto done;
++    printk("Init GM UDC ISR finished\n");
++
++    /* Generate device node */
++    retval = alloc_chrdev_region(&dev_num, 0, 1, USB_USER_NAME);
++    if (unlikely(retval < 0)) {
++        printk(KERN_ERR "%s:alloc_chrdev_region failed\n", __func__);
++        goto done;
++    }
++    cdev_init(&usb_cdev, &usb_fops);
++    usb_cdev.owner = THIS_MODULE;
++    usb_cdev.ops = &usb_fops;
++    retval = cdev_add(&usb_cdev, dev_num, 1);
++    if (unlikely(retval < 0)) {
++        printk(KERN_ERR "%s:cdev_add failed\n", __func__);
++        goto err3;
++    }
++    usb_class = class_create(THIS_MODULE, USB_USER_NAME);
++    if (IS_ERR(usb_class)) {
++        printk(KERN_ERR "%s:class_create failed\n", __func__);
++        goto err2;
++    }
++    device_create(usb_class, NULL, usb_cdev.dev, NULL, USB_USER_NAME);
++
++    /* done */
++    return 0;
++err2:
++    cdev_del(&usb_cdev);
++err3:
++    unregister_chrdev_region(dev_num, 1);
++
++done:
++    DBG_TEMP("FTC_usb_probe() failed\n");
++    if (fotg210_udc)
++        FTC_usb_remove();
++    return retval;
++}
++
++/*-------------------------------------------------------------------------*/
++//Trace ok 12212004
++static int __init init (void)
++{
++	//Info(dev,"device init ... %x\n",0);
++
++    fotg210_udc = kzalloc (sizeof(struct FTC_udc), GFP_KERNEL);
++    if (fotg210_udc == NULL) {
++        printk("Error ==> FOTG2XX Device part Initiation.\n");
++        return -ENOMEM;
++    }
++
++	return FTC_usb_probe();
++}
++
++module_init (init);
++
++//Trace ok 12212004
++static void __exit cleanup (void)
++{
++	//Info(dev,"remove USB device Lower driver\n");
++	unregister_chrdev_region(dev_num, 1);
++	cdev_del(&usb_cdev);
++	device_destroy(usb_class, dev_num);
++	class_destroy(usb_class);
++	return FTC_usb_remove();
++}
++
++module_exit (cleanup);
++
++MODULE_AUTHOR("<GM-tech.com>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("USB device mode Driver");
+diff --git a/drivers/usb/gadget/GM_udc.h b/drivers/usb/gadget/GM_udc.h
+new file mode 100644
+index 00000000..327cbec6
+--- /dev/null
++++ b/drivers/usb/gadget/GM_udc.h
+@@ -0,0 +1,519 @@
++/*
++ * GM USB220 ("FTUSB220") USB Device Controller driver
++ *
++ * Copyright (C) 2004-2005 John
++ *      by John Chiang
++ * Copyright (C) 2004 GM corp.
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2.  This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++//*************************************************************************
++//****************************** 1.Name Define ****************************
++//*************************************************************************
++
++//////////////////////////////////////////////
++
++
++//#define MESS_ERROR	(0x01 << 0)
++//#define MESS_WARNING	(0x01 << 1)
++//#define MESS_INFO		(0x01 << 2)
++//#define MESS_DEBUG	(0x01 << 7)
++////////////////////////////////////////////
++
++#define TRUE			1
++#define FALSE			0
++
++#define MASK_F0			0xF0
++
++// Block Size define
++#define BLK512BYTE		1
++#define BLK1024BYTE		2
++
++#define BLK64BYTE		1
++#define BLK128BYTE		2
++
++// Block toggle number define
++#define SINGLE_BLK		1
++#define DOUBLE_BLK		2
++#define TRIBLE_BLK		3
++
++// Endpoint transfer type
++#define TF_TYPE_CONTROL		0
++#define TF_TYPE_ISOCHRONOUS	1
++#define TF_TYPE_BULK		2
++#define TF_TYPE_INTERRUPT	3
++
++// ***********Caution***************
++// Endpoint or FIFO direction define
++// Please don't change this define, this will cause very serious problems.
++// Because someone change this define form my original code(FUSB220 firmware on cpe),
++// and didn't check where this register use. And let i waste 2 days to debug. Damn!!
++// IN = 0, OUT = 1....please don't change this define anymore. (YPING left his message.)
++#define DIRECTION_IN	1
++#define DIRECTION_OUT	0
++
++// FIFO number define
++#define FIFO0	0x0
++#define FIFO1	0x1
++#define FIFO2	0x2
++#define FIFO3	0x3
++#define FIFO4	0x4
++#define FIFO5	0x5
++#define FIFO6	0x6
++#define FIFO7	0x7
++#define FIFO8	0x8
++#define FIFO9	0x9
++
++// Endpoint number define
++#define EP0         0x00
++#define EP1         0x01
++#define EP2         0x02
++#define EP3         0x03
++#define EP4         0x04
++#define EP5         0x05
++#define EP6         0x06
++#define EP7         0x07
++#define EP8         0x08
++#define EP9         0x09
++#define EP10        0x10
++#define EP11        0x11
++#define EP12        0x12
++#define EP13        0x13
++#define EP14        0x14
++#define EP15        0x15
++
++#define BIT0		0x00000001
++#define BIT1		0x00000002
++#define BIT2		0x00000004
++#define BIT3		0x00000008
++#define BIT4		0x00000010
++#define BIT5		0x00000020
++#define BIT6		0x00000040
++#define BIT7		0x00000080
++
++#define BIT8		0x00000100
++#define BIT9		0x00000200
++#define BIT10		0x00000400
++#define BIT11		0x00000800
++#define BIT12		0x00001000
++#define BIT13		0x00002000
++#define BIT14		0x00004000
++#define BIT15		0x00008000
++
++#define BIT16		0x00010000
++#define BIT17		0x00020000
++#define BIT18		0x00040000
++#define BIT19		0x00080000
++#define BIT20		0x00100000
++#define BIT21		0x00200000
++#define BIT22		0x00400000
++#define BIT23		0x00800000
++
++#define BIT24		0x01000000
++#define BIT25		0x02000000
++#define BIT26		0x04000000
++#define BIT27		0x08000000
++#define BIT28		0x10000000
++#define BIT29		0x20000000
++#define BIT30		0x40000000
++#define BIT31		0x80000000
++
++
++#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
++#define  AHB_DMA_MAX_LEN	8192
++
++// Buffer allocation for each EP
++#define USB_EPX_BUFSIZ	4096
++
++#define	MAX_FIFO_SIZE	64    // reset value for EP
++#define	MAX_EP0_SIZE	0x40  // ep0 fifo size
++
++#define USB_EP0_BUFSIZ	256
++
++// Used for test pattern traffic
++#if 0
++#define TEST_J		0x02
++#define TEST_K		0x04
++#define TEST_SE0_NAK	0x08
++#define TEST_PKY	0x10
++#endif
++
++#define FUSB220_CURRENT_SUPPORT_EP	5	//ep0~ep4
++
++#define FUSB220_MAX_EP				10	// 1..10
++#define FUSB220_MAX_FIFO			10	// 0.. 9
++//#define USB_AHBDAC 3
++
++/*-------------------------------------------------------------------------*/
++//*************************************************************************
++//****************************** 2.Structure Define************************
++//*************************************************************************
++
++/* DRIVER DATA STRUCTURES and UTILITIES */
++
++struct FTC_ep
++{
++	struct usb_ep	 ep;
++	struct FTC_udc	*dev;
++	unsigned long 	 irqs;
++	u32              wDMA_Set_Length;
++
++	unsigned num:8,
++		 dma:1,
++		 is_in:1,
++		 stopped:1,
++		 dma_running:1;
++
++	/* analogous to a host-side qh */
++	struct list_head			queue;
++	const struct usb_endpoint_descriptor	*desc;
++};
++
++struct FTC_request
++{
++	struct usb_request	req;
++	struct list_head	queue;
++	u32 			u32DMACurrTxLen;
++	dma_addr_t		CurDmaStartAddr;
++	unsigned		mapped:1;
++};
++
++enum ep0state
++{
++	EP0_DISCONNECT,	 /* no host */
++	EP0_IDLE,		 /* between STATUS ack and SETUP report */
++	EP0_IN, EP0_OUT, /* data stage */
++	EP0_STATUS,		 /* status stage */
++	EP0_STALL,		 /* data or status stages */
++	EP0_SUSPEND,	 /* usb suspend */
++};
++
++typedef enum
++{
++	CMD_VOID,				// No command
++	CMD_GET_DESCRIPTOR,		// Get_Descriptor command
++	CMD_SET_DESCRIPTOR,		// Set_Descriptor command
++	CMD_TEST_MODE           // Test_Mode command
++} CommandType;
++
++typedef enum
++{
++	PIO_Mode,
++	AHB_DMA,
++	APB_DMA
++} DMA_mode;
++
++typedef enum
++{
++	CLEAR_STALL = 0,
++	PROTO_STALL,
++	FUNC_STALL,
++} Stall_state;
++
++
++struct FTC_udc
++{
++	/* each pci device provides one gadget, several endpoints */
++	struct usb_gadget		gadget;
++	spinlock_t			lock;
++	struct FTC_ep			ep[FUSB220_MAX_EP];
++	struct usb_gadget_driver	*driver;
++
++	struct usb_request		*EP0req;
++
++	enum ep0state			ep0state;
++	unsigned			got_irq:1,
++					got_region:1,
++					req_config:1,
++					configured:1,
++					enabled:1;
++
++	struct usb_ctrlrequest		ControlCmd;
++
++	u8 u8UsbConfigValue;
++	u8 u8UsbInterfaceValue;
++	u8 u8UsbInterfaceAlternateSetting;
++
++	CommandType eUsbCxCommand;
++	DMA_mode Dma_Status;
++
++	u8 bUsbBufferEmpty;
++
++	u8 u16TxRxCounter;
++
++	u8 usb_interrupt_level1;
++	u8 usb_interrupt_level1_Save;
++	u8 usb_interrupt_level1_Mask;
++
++	u8 *pu8DescriptorEX;
++
++	//11/2/05' AHB_DMA
++	//ahb_dma_data_t  *ahb_dma;
++	u8 EPUseDMA;   //EP for DMA
++	struct  FTC_request *ReqForDMA;
++
++	/* statistics... */
++	unsigned long irqs;
++	u8 u8LineCount;
++	int chForDMA;
++	u32 va_base;
++};
++
++/*-------------------------------------------------------------------------*/
++//*************************************************************************
++//****************************** 3.Debug Info and hardware feature Define************
++//*************************************************************************
++#define NoFixPort			0
++#define FixPort			1
++#define USB_DataPort		NoFixPort
++
++#define DBG_OFF 	0x00
++#define DBG_CTRL 	0x01
++#define DBG_BULK 	0x02
++#define DBG_ISO		0x04
++#define DBG_INT		0x08
++#define DBG_FUNC	0x10
++#define DBG_TMP		0x20
++
++#ifdef CONFIG_GM_FUSB220
++#define DBG_BRAD_BULK   0x40
++#endif
++
++#define USB_DBG 	(DBG_OFF)
++//#define USB_DBG 	(DBG_OFF|DBG_TMP|DBG_FUNC|DBG_CTRL)
++//#define USB_DBG 	(DBG_FUNC |DBG_BULK|DBG_CTRL|DBG_BRAD_BULK|DBG_TMP) //( DBG_FUNC |DBG_BULK)//|DBG_TMP|DBG_FUNC)//|DBG_CTRL)
++
++#define xprintk(dev,level,fmt,args...) printk(level "%s : " fmt , __func__ , ## args)
++#define wprintk(level,fmt,args...) printk(level "%s : " fmt , __func__ , ## args)
++
++#ifdef DEBUG
++#define udc_dbg(dev,fmt,args...) xprintk(dev , KERN_DEBUG , fmt , ## args)
++#else
++#define udc_dbg(dev,fmt,args...) do { } while (0)
++#endif /* DEBUG */
++
++#define VERBOSE
++
++#ifdef VERBOSE
++#define Vdbg udc_dbg
++#else
++#define Vdbg(dev,fmt,args...) do { } while (0)
++#endif	/* VERBOSE */
++
++#define error(dev,fmt,args...) xprintk(dev , KERN_ERR , fmt , ## args)
++#define uwarn(dev,fmt,args...) xprintk(dev , KERN_WARNING , fmt , ## args)
++#define Info(dev,fmt,args...) xprintk(dev , KERN_INFO , fmt , ## args)
++
++#if (USB_DBG & DBG_TMP)
++#define DBG_TEMP(fmt,args...) wprintk(KERN_INFO , fmt , ## args)
++#else
++#define DBG_TEMP(fmt,args...)
++#endif
++
++#if (USB_DBG & DBG_FUNC)
++#define DBG_FUNCC(fmt,args...) wprintk(KERN_INFO , fmt , ## args)
++#else
++#define DBG_FUNCC(fmt,args...)
++#endif
++
++#if (USB_DBG & DBG_CTRL)
++#define DBG_CTRLL(fmt,args...) wprintk(KERN_INFO , fmt , ## args)
++#else
++#define DBG_CTRLL(fmt,args...)
++#endif
++
++#if (USB_DBG & DBG_BULK)
++#define DBG_BULKK(fmt,args...) wprintk(KERN_INFO , fmt , ## args)
++#else
++#define DBG_BULKK(fmt,args...)
++#endif
++
++
++#ifdef CONFIG_GM_FUSB220
++#if (USB_DBG & DBG_BRAD_BULK)
++#define DBG_BRAD(dev,fmt,args...) xprintk(dev , KERN_DEBUG , fmt , ## args)
++#define DBG_BRAD_FUNCC(fmt,args...) wprintk(KERN_INFO , fmt , ## args)
++#define DBG_BRAD_CTRLL(fmt,args...) wprintk(KERN_INFO , fmt , ## args)
++#define ERROR_BRAD(dev,fmt,args...) xprintk(dev , KERN_ERR , fmt , ## args)
++#else
++#define DBG_BRAD_BULKK(fmt, args...)
++#define DBG_BRAD(dev,fmt,args...)
++#define DBG_BRAD_FUNCC(fmt,args...)
++#define DBG_BRAD_CTRLL(fmt,args...)
++#define ERROR_BRAD(dev,fmt,args...)
++#endif
++#endif
++
++/*-------------------------------------------------------------------------*/
++//*************************************************************************
++//****************************** 4.Others Define************************
++//*************************************************************************
++
++/* 2.5 stuff that's sometimes missing in 2.4 */
++
++#ifndef container_of
++#define	container_of	list_entry
++#endif
++
++#ifndef likely
++#define likely(x)	(x)
++#define unlikely(x)	(x)
++#endif
++
++#ifndef BUG_ON
++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
++#endif
++
++#ifndef WARN_ON
++#define	WARN_ON(x)	do { } while (0)
++#endif
++
++#if 0//ndef	IRQ_NONE
++typedef void irqreturn_t;
++#define IRQ_NONE
++#define IRQ_HANDLED
++#define IRQ_RETVAL(x)
++#endif
++
++#define Cmd_Service_Fail	 			0
++#define Cmd_Already_Service 			1
++#define Cmd_Let_Gadget_To_Service 	2
++
++//*************************************************************************
++//****************************** 5.Function Export Define************************
++//*************************************************************************
++//static void vUsbFIFO_EPxCfg_FS(void);
++//static void vUsbFIFO_EPxCfg_HS(void);
++
++#ifdef CONFIG_GM_FUSB220
++static int FTC_fifo_status(struct usb_ep *_ep);
++#endif
++
++//static u8 bClear_feature(struct FTC_udc *dev);
++//static u8 bGet_status(struct FTC_udc *dev);
++//static u8 bSet_address(struct FTC_udc *dev);
++//static u8 bSet_descriptor(struct FTC_udc *dev);
++//static u8 bSet_feature(struct FTC_udc *dev);
++//static u8 bGet_descriptor(struct FTC_udc *dev);
++//static void vGet_configuration(struct FTC_udc *dev);
++//static u8 bSet_configuration(struct FTC_udc *dev);
++//static u8 bGet_interface(struct FTC_udc *dev);
++//static u8 bSet_interface(struct FTC_udc *dev);
++//static u8 bSynch_frame(struct FTC_udc *dev);
++//static u8 bStandardCommand(struct FTC_udc *dev);
++
++//*************************************************************************
++//****************************** 6.ED/FIFO Config Define************************
++//*************************************************************************
++
++//**************************************
++//*** Full Speed HW ED/FIFO Configuration Area ***
++#define FULL_ED1_bBLKSIZE	 BLK64BYTE
++#define FULL_ED1_bBLKNO      SINGLE_BLK
++#define FULL_ED1_bDIRECTION  DIRECTION_IN
++#define FULL_ED1_bTYPE       TF_TYPE_BULK
++#define FULL_ED1_MAXPACKET   64
++
++#define FULL_ED2_bBLKSIZE	BLK64BYTE
++#define FULL_ED2_bBLKNO      SINGLE_BLK
++#define FULL_ED2_bDIRECTION  DIRECTION_OUT
++#define FULL_ED2_bTYPE       TF_TYPE_BULK
++#define FULL_ED2_MAXPACKET   64
++
++#define FULL_ED3_bBLKSIZE	BLK64BYTE
++#define FULL_ED3_bBLKNO      SINGLE_BLK
++#define FULL_ED3_bDIRECTION  DIRECTION_IN
++#define FULL_ED3_bTYPE       TF_TYPE_INTERRUPT
++#define FULL_ED3_MAXPACKET   64
++
++#define FULL_ED4_bBLKSIZE	BLK64BYTE
++#define FULL_ED4_bBLKNO      SINGLE_BLK
++#define FULL_ED4_bDIRECTION  DIRECTION_OUT
++#define FULL_ED4_bTYPE       TF_TYPE_INTERRUPT
++#define FULL_ED4_MAXPACKET   64
++//**************************************************
++
++//**************************************
++//*** High Speed HW ED/FIFO Configuration Area ***
++#define HIGH_ED1_bBLKSIZE	BLK512BYTE
++#define HIGH_ED1_bDIRECTION  DIRECTION_IN
++#define HIGH_ED1_bTYPE       TF_TYPE_BULK
++#define HIGH_ED1_MAXPACKET   512
++
++#define HIGH_ED2_bBLKSIZE	BLK512BYTE
++#define HIGH_ED2_bDIRECTION  DIRECTION_OUT
++#define HIGH_ED2_bTYPE       TF_TYPE_BULK
++#define HIGH_ED2_MAXPACKET   512
++
++#define HIGH_ED3_bBLKSIZE	BLK64BYTE
++#define HIGH_ED3_bBLKNO      SINGLE_BLK
++#define HIGH_ED3_bDIRECTION  DIRECTION_IN
++#define HIGH_ED3_bTYPE       TF_TYPE_INTERRUPT
++#define HIGH_ED3_MAXPACKET   64
++
++#define HIGH_ED4_bBLKSIZE	BLK64BYTE
++#define HIGH_ED4_bBLKNO      SINGLE_BLK
++#define HIGH_ED4_bDIRECTION  DIRECTION_OUT
++#define HIGH_ED4_bTYPE       TF_TYPE_INTERRUPT
++#define HIGH_ED4_MAXPACKET   64
++//**************************************************
++
++#ifdef CONFIG_GM_FUSB220
++#define FIFOEnBit 0x80
++#define HIGH_ED1_bBLKNO      DOUBLE_BLK
++#define HIGH_ED2_bBLKNO      DOUBLE_BLK
++#else
++#define FIFOEnBit 0x20
++#define HIGH_ED1_bBLKNO      SINGLE_BLK
++#define HIGH_ED2_bBLKNO      SINGLE_BLK
++#endif
++
++#define FULL_ED1_FIFO_START  	FIFO0
++#define FULL_ED2_FIFO_START  	(FULL_ED1_FIFO_START+(FULL_ED1_bBLKNO *FULL_ED1_bBLKSIZE))
++#define FULL_ED3_FIFO_START  	(FULL_ED2_FIFO_START+(FULL_ED2_bBLKNO *FULL_ED2_bBLKSIZE))
++#define FULL_ED4_FIFO_START  	(FULL_ED3_FIFO_START+(FULL_ED3_bBLKNO *FULL_ED3_bBLKSIZE))
++
++#define FULL_EP1_Map			(FULL_ED1_FIFO_START |(FULL_ED1_FIFO_START << 4)|(0xF0 >> (4*(1-FULL_ED1_bDIRECTION))))
++#define FULL_EP1_FIFO_Map    	((FULL_ED1_bDIRECTION << 4) | EP1)
++#define FULL_EP1_FIFO_Config 	(FIFOEnBit | ((FULL_ED1_bBLKSIZE - 1) << 4) | ((FULL_ED1_bBLKNO - 1) << 2) | FULL_ED1_bTYPE)
++#define FULL_EP2_Map        		(FULL_ED2_FIFO_START |(FULL_ED2_FIFO_START << 4)|(0xF0 >> (4*(1-FULL_ED2_bDIRECTION))))
++#define FULL_EP2_FIFO_Map    	((FULL_ED2_bDIRECTION << 4) | EP2)
++#define FULL_EP2_FIFO_Config 	(FIFOEnBit | ((FULL_ED2_bBLKSIZE - 1) << 4) | ((FULL_ED2_bBLKNO - 1) << 2) | FULL_ED2_bTYPE)
++#define FULL_EP3_Map        		(FULL_ED3_FIFO_START |(FULL_ED3_FIFO_START << 4)|(0xF0 >> (4*(1-FULL_ED3_bDIRECTION))))
++#define FULL_EP3_FIFO_Map    	((FULL_ED3_bDIRECTION << 4) | EP3)
++#define FULL_EP3_FIFO_Config 	(FIFOEnBit | ((FULL_ED3_bBLKSIZE - 1) << 4) | ((FULL_ED3_bBLKNO - 1) << 2) | FULL_ED3_bTYPE)
++#define FULL_EP4_Map        		(FULL_ED4_FIFO_START |(FULL_ED4_FIFO_START << 4)|(0xF0 >> (4*(1-FULL_ED4_bDIRECTION))))
++#define FULL_EP4_FIFO_Map    	((FULL_ED4_bDIRECTION << 4) | EP4)
++#define FULL_EP4_FIFO_Config 	(FIFOEnBit | ((FULL_ED4_bBLKSIZE - 1) << 4) | ((FULL_ED4_bBLKNO - 1) << 2) | FULL_ED4_bTYPE)
++
++
++#define HIGH_ED1_FIFO_START  	FIFO0
++#define HIGH_ED2_FIFO_START  	(HIGH_ED1_FIFO_START+(HIGH_ED1_bBLKNO *HIGH_ED1_bBLKSIZE))
++#define HIGH_ED3_FIFO_START  	(HIGH_ED2_FIFO_START+(HIGH_ED2_bBLKNO *HIGH_ED2_bBLKSIZE))
++#define HIGH_ED4_FIFO_START  	(HIGH_ED3_FIFO_START+(HIGH_ED3_bBLKNO *HIGH_ED3_bBLKSIZE))
++
++#define HIGH_EP1_Map        		(HIGH_ED1_FIFO_START |(HIGH_ED1_FIFO_START << 4)|(0xF0 >> (4*(1-HIGH_ED1_bDIRECTION))))
++#define HIGH_EP1_FIFO_Map    	((HIGH_ED1_bDIRECTION << 4) | EP1)
++#define HIGH_EP1_FIFO_Config 	(FIFOEnBit | ((HIGH_ED1_bBLKSIZE - 1) << 4) | ((HIGH_ED1_bBLKNO - 1) << 2) | HIGH_ED1_bTYPE)
++#define HIGH_EP2_Map        		(HIGH_ED2_FIFO_START |(HIGH_ED2_FIFO_START << 4)|(0xF0 >> (4*(1-HIGH_ED2_bDIRECTION))))
++#define HIGH_EP2_FIFO_Map    	((HIGH_ED2_bDIRECTION << 4) | EP2)
++#define HIGH_EP2_FIFO_Config 	(FIFOEnBit | ((HIGH_ED2_bBLKSIZE - 1) << 4) | ((HIGH_ED2_bBLKNO - 1) << 2) | HIGH_ED2_bTYPE)
++#define HIGH_EP3_Map        		(HIGH_ED3_FIFO_START |(HIGH_ED3_FIFO_START << 4)|(0xF0 >> (4*(1-HIGH_ED3_bDIRECTION))))
++#define HIGH_EP3_FIFO_Map    	((HIGH_ED3_bDIRECTION << 4) | EP3)
++#define HIGH_EP3_FIFO_Config 	(FIFOEnBit | ((HIGH_ED3_bBLKSIZE - 1) << 4) | ((HIGH_ED3_bBLKNO - 1) << 2) | HIGH_ED3_bTYPE)
++#define HIGH_EP4_Map        		(HIGH_ED4_FIFO_START |(HIGH_ED4_FIFO_START << 4)|(0xF0 >> (4*(1-HIGH_ED4_bDIRECTION))))
++#define HIGH_EP4_FIFO_Map    	((HIGH_ED4_bDIRECTION << 4) | EP4)
++#define HIGH_EP4_FIFO_Config 	(FIFOEnBit | ((HIGH_ED4_bBLKSIZE - 1) << 4) | ((HIGH_ED4_bBLKNO - 1) << 2) | HIGH_ED4_bTYPE)
++
++
++//*************************************************************************
++//****************************** 7.HW Macro Define************************
++//*************************************************************************
++
++#ifdef CONFIG_GM_FUSB220
++#include "fusb220-macro.h"
++#else
++#include "fotg2xx-peri-macro.h"
++#endif
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 7ecb68a6..dec8bc9b 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -131,6 +131,28 @@ choice
+ 	   Many controller drivers are platform-specific; these
+ 	   often need board-specific hooks.
+ 
++config GM_USB_DEVICE
++	boolean "GM USB FOTG210"
++	depends on !PHYS_ADDR_T_64BIT
++	select USB_GADGET_DUALSPEED
++	help
++	   The USB device driver of GM FOTG210,
++	   modified to aim compatibility of USB 2.0. for more see
++	   FOTG210 data sheet
++
++config GM_OTG_CHOOSE
++	int "Choose which FOTG210 for UDC (platform device id)"
++	depends on GM_USB_DEVICE
++	default "0"
++	help
++	   GM SoC may have serveral OTGs, choose one as your UDC
++
++config GM_USB_UDC
++	tristate
++	depends on GM_USB_DEVICE
++	default USB_GADGET
++	select USB_GADGET_SELECTED
++
+ #
+ # Integrated controllers
+ #
+@@ -560,6 +582,13 @@ choice
+ 
+ # this first set of drivers all depend on bulk-capable hardware.
+ 
++config GM_PATH_TEST
++        tristate "GM Path test for USB device driver"
++        depends on GM_USB_DEVICE
++	help
++          This USB device driver is designed to test OTG's device part.
++          You must have the application program on PC for path test.
++
+ config USB_ZERO
+ 	tristate "Gadget Zero (DEVELOPMENT)"
+ 	help
+@@ -616,7 +645,7 @@ config USB_ETH
+ 	help
+ 	  This driver implements Ethernet style communication, in one of
+ 	  several ways:
+-	  
++
+ 	   - The "Communication Device Class" (CDC) Ethernet Control Model.
+ 	     That protocol is often avoided with pure Ethernet adapters, in
+ 	     favor of simpler vendor-specific hardware, but is widely
+@@ -656,7 +685,7 @@ config USB_ETH_RNDIS
+ 	   If you say "y" here, the Ethernet gadget driver will try to provide
+ 	   a second device configuration, supporting RNDIS to talk to such
+ 	   Microsoft USB hosts.
+-	   
++
+ 	   To make MS-Windows work with this, use Documentation/usb/linux.inf
+ 	   as the "driver info file".  For versions of MS-Windows older than
+ 	   XP, you'll need to download drivers from Microsoft's website; a URL
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index b7f6eefc..96437b17 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -4,6 +4,7 @@
+ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
+ 
+ obj-$(CONFIG_USB_GADGET)	+= udc-core.o
++obj-$(CONFIG_GM_USB_UDC)        += g_GM_udc.o
+ obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
+ obj-$(CONFIG_USB_NET2272)	+= net2272.o
+ obj-$(CONFIG_USB_NET2280)	+= net2280.o
+@@ -35,6 +36,9 @@ obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o
+ #
+ # USB gadget drivers
+ #
++g_GM_udc-y			:= GM_udc.o
++#g_GM_udc-y			:= fotg210-udc.o
++g_GM_zero-objs		:= GM_test.o usbstring.o config.o epautoconf.o
+ g_zero-y			:= zero.o
+ g_audio-y			:= audio.o
+ g_ether-y			:= ether.o
+@@ -53,6 +57,7 @@ g_webcam-y			:= webcam.o
+ g_ncm-y				:= ncm.o
+ g_acm_ms-y			:= acm_ms.o
+ 
++obj-$(CONFIG_GM_PATH_TEST)	+= g_GM_zero.o
+ obj-$(CONFIG_USB_ZERO)		+= g_zero.o
+ obj-$(CONFIG_USB_AUDIO)		+= g_audio.o
+ obj-$(CONFIG_USB_ETH)		+= g_ether.o
+diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
+index 47766f0e..75deb2e9 100644
+--- a/drivers/usb/gadget/file_storage.c
++++ b/drivers/usb/gadget/file_storage.c
+@@ -256,6 +256,11 @@
+ 
+ #include "gadget_chips.h"
+ 
++#if defined(CONFIG_GM_FOTG2XX)
++#include "fotg2xx-peri-macro.h"
++#include "GM_udc.h"
++#endif
++
+ 
+ 
+ /*
+@@ -326,7 +331,23 @@ static struct {
+ 	int		protocol_type;
+ 	char		*protocol_name;
+ 
+-} mod_data = {					// Default values
++}
++#ifdef CONFIG_GM_FOTG2XX
++ mod_data = {					// Default values
++	.file[0]		= "/dev/mmcblk0p1", //"/ram.img",
++	.serial			= "0123456789ABCD",
++	.transport_parm		= "BBB",
++	.protocol_parm		= "SCSI",
++	.removable		= 1,
++	.can_stall		= 1,
++	.cdrom			= 0,
++	.vendor			= FSG_VENDOR_ID,
++	.product		= FSG_PRODUCT_ID,
++	.release		= 0xffff,	// Use controller chip type
++	.buflen			= 16384,
++	};
++#else
++ mod_data = {					// Default values
+ 	.transport_parm		= "BBB",
+ 	.protocol_parm		= "SCSI",
+ 	.removable		= 0,
+@@ -337,7 +358,7 @@ static struct {
+ 	.release		= 0xffff,	// Use controller chip type
+ 	.buflen			= 16384,
+ 	};
+-
++#endif
+ 
+ module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
+ 		S_IRUGO);
+@@ -2079,8 +2100,10 @@ static int finish_reply(struct fsg_dev *fsg)
+ 			start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ 					&bh->inreq_busy, &bh->state);
+ 			fsg->next_buffhd_to_fill = bh->next;
++#if !defined(CONFIG_GM_USB_DEVICE)
+ 			if (mod_data.can_stall)
+ 				rc = halt_bulk_in_endpoint(fsg);
++#endif
+ 		}
+ 		break;
+ 
+@@ -3663,6 +3686,9 @@ module_init(fsg_init);
+ static void __exit fsg_cleanup(void)
+ {
+ 	struct fsg_dev	*fsg = the_fsg;
++#if defined(CONFIG_GM_FOTG2XX)
++	struct FTC_udc	*ftc_dev = container_of(fsg->gadget, struct FTC_udc, gadget);
++#endif
+ 
+ 	/* Unregister the driver iff the thread hasn't already done so */
+ 	if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags))
+@@ -3672,5 +3698,8 @@ static void __exit fsg_cleanup(void)
+ 	wait_for_completion(&fsg->thread_notifier);
+ 
+ 	kref_put(&fsg->ref, fsg_release);
++#if defined(CONFIG_GM_FOTG2XX)
++	mUsbUnPLGSet(ftc_dev->va_base);
++#endif
+ }
+ module_exit(fsg_cleanup);
+diff --git a/drivers/usb/gadget/fotg2xx-peri-macro.h b/drivers/usb/gadget/fotg2xx-peri-macro.h
+new file mode 100644
+index 00000000..11f21dfe
+--- /dev/null
++++ b/drivers/usb/gadget/fotg2xx-peri-macro.h
+@@ -0,0 +1,328 @@
++
++#ifndef __FOTG200_M_H
++#define __FOTG200_M_H
++
++#define FIFOCX	         0xFF
++#define DMA_CHANEL_FREE  0XFF
++
++#define MAX_EP_NUM	8
++#define MAX_FIFO_NUM	4
++
++#define CPE_FOTG200_BASE(x) (x+0x100)
++#define IRQ_USBDEV 	USB_FOTG2XX_IRQ
++#define FUSB220_DMA_IS_IDLE_NOW DMA_CHANEL_FREE
++
++#define FUSB220_BASE_ADDRESS(s)		CPE_FOTG200_BASE(x)
++#define FOTG200_FIFO_BASE(bOffset)	((CPE_FOTG200_BASE(x))+0xC0+(bOffset<<2))
++
++#define bFOTGPeri_Port(x,bOffset)	*((volatile u8 *) ((u32)x|(u32)(bOffset)))
++#define hwFOTGPeri_Port(x,bOffset)	*((volatile u16 *) ((u32)x|(u32)(bOffset)))
++#define wFOTGPeri_Port(x,bOffset)	*((volatile u32 *) ((u32)x|(u32)(bOffset)))
++
++// Main control register(0x100)
++#define mUsbRmWkupST(x)			(wFOTGPeri_Port(x,0x100) & BIT0)
++#define mUsbRmWkupSet(x)		        (wFOTGPeri_Port(x,0x100) |= BIT0)
++#define mUsbRmWkupClr(x)			(wFOTGPeri_Port(x,0x100) &= ~BIT0)
++
++#define mUsbTstHalfSpeedEn(x)		(wFOTGPeri_Port(x,0x100) |= BIT1)
++#define mUsbTstHalfSpeedDis(x)	        (wFOTGPeri_Port(x,0x100) &= ~BIT1)
++
++#define mUsbGlobIntEnRd(x)		(wFOTGPeri_Port(x,0x100) & BIT2)
++#define mUsbGlobIntEnSet(x)		(wFOTGPeri_Port(x,0x100) |= BIT2)
++#define mUsbGlobIntDis(x)		(wFOTGPeri_Port(x,0x100) &= ~BIT2)
++
++#define mUsbGoSuspend(x)			(wFOTGPeri_Port(x,0x100) |=  BIT3)
++
++#define mUsbSoftRstSet(x)		(wFOTGPeri_Port(x,0x100) |=  BIT4)
++#define mUsbSoftRstClr(x)		(wFOTGPeri_Port(x,0x100) &= ~BIT4)
++
++#define mUsbChipEnSet(x)			(wFOTGPeri_Port(x,0x100) |= BIT5)
++#define mUsbHighSpeedST(x)		(wFOTGPeri_Port(x,0x100) & BIT6)
++#define mUsbDMAResetSet(x)		(wFOTGPeri_Port(x,0x100) |= BIT8)
++
++#define mUsbForceFSSet(x)		(wFOTGPeri_Port(x,0x100) |=  BIT9)
++#define mUsbForceFSClr(x)		(wFOTGPeri_Port(x,0x100) &= ~BIT9)
++
++// Device address register(0x104)
++#define mUsbDevAddrSet(x,Value)	        (wFOTGPeri_Port(x,0x104) = (u32)Value)
++#define mUsbCfgST(x)			(wFOTGPeri_Port(x,0x104) & BIT7)
++#define mUsbCfgSet(x)			(wFOTGPeri_Port(x,0x104) |= BIT7)
++#define mUsbCfgClr(x)			(wFOTGPeri_Port(x,0x104) &= ~BIT7)
++
++// Test register(0x108)
++#define mUsbClrAllFIFOSet(x)		(wFOTGPeri_Port(x,0x108) |= BIT0)
++#define mUsbClrAllFIFOClr(x)		(wFOTGPeri_Port(x,0x108) &= ~BIT0)
++
++// SOF Frame Number register(0x10C)
++#define mUsbFrameNo(x)			(u16)(wFOTGPeri_Port(x,0x10C) & 0x7FF)
++#define mUsbMicroFrameNo(x)		(u8)((wFOTGPeri_Port(x,0x10C) & 0x3800)>>11)
++#define mUsbFrameNoLow(x)		(mUsbFrameNo(x) & 0xff)
++#define mUsbFrameNoHigh(x)		(mUsbFrameNo(x) >> 8)
++
++// SOF Mask register(0x110)
++#define mUsbSOFMaskHS(x)		        (wFOTGPeri_Port(x,0x110) = 0x44c)
++#define mUsbSOFMaskFS(x)		        (wFOTGPeri_Port(x,0x110) = 0x2710)
++
++// PHY Test Mode Selector register(0x114)
++#define mUsbTsMdWr(x,item)		(wFOTGPeri_Port(x,0x114) = (u32)item)
++#define mUsbUnPLGClr(x)			(wFOTGPeri_Port(x,0x114) &= ~BIT0)
++#define mUsbUnPLGSet(x)			(wFOTGPeri_Port(x,0x114) |= BIT0)
++// Vendor Specific IO Control register(0x118)
++
++// Cx configuration and status register(0x11C)
++
++// Cx configuration and FIFO Empty Status register(0x120)
++#define mUsbEP0DoneSet(x)		(wFOTGPeri_Port(x,0x120) |= BIT0)
++#define mUsbTsPkDoneSet(x)		(wFOTGPeri_Port(x,0x120) |= BIT1)
++#define mUsbEP0StallSet(x)		(wFOTGPeri_Port(x,0x120) |= BIT2)
++#define mUsbCxFClr(x)			(wFOTGPeri_Port(x,0x120) |= BIT3)
++
++#define mUsbCxFFull(x)			(wFOTGPeri_Port(x,0x120) & BIT4)
++#define mUsbCxFEmpty(x)			(wFOTGPeri_Port(x,0x120) & BIT5)
++#define mUsbCxFByteCnt(x)		(u8)((wFOTGPeri_Port(x,0x120) & 0x7F000000)>>24)
++#define mUsbEP0ClearFIFO(x)              (bFOTGPeri_Port(x,0x0120) |= (u8)BIT3)  //john
++#define mUsbEP0EMPFIFO(x)                (bFOTGPeri_Port(x,0x0120) &= (u8)BIT5)  //john
++
++// IDLE Counter register(0x124)
++#define mUsbIdleCnt(x,time)		(wFOTGPeri_Port(x,0x124) = (u32)time)
++
++// Mask of interrupt group(0x130)
++#define mUsbIntGrp0Dis(x)		(wFOTGPeri_Port(x,0x130) |= BIT0)
++#define mUsbIntGrp1Dis(x)		(wFOTGPeri_Port(x,0x130) |= BIT1)
++#define mUsbIntGrp2Dis(x)		(wFOTGPeri_Port(x,0x130) |= BIT2)
++
++#define mUsbIntGroupMaskRd(x)	        (wFOTGPeri_Port(x,0x130))
++
++// Mask of interrupt source group 0(0x134)
++#define mUsbIntEP0SetupDis(x)		(wFOTGPeri_Port(x,0x134) |= BIT0)
++#define mUsbIntEP0InDis(x)		(wFOTGPeri_Port(x,0x134) |= BIT1)
++#define mUsbIntEP0OutDis(x)		(wFOTGPeri_Port(x,0x134) |= BIT2)
++#define mUsbIntEP0EndDis(x)		(wFOTGPeri_Port(x,0x134) |= BIT3)
++#define mUsbIntEP0FailDis(x)		(wFOTGPeri_Port(x,0x134) |= BIT4)
++
++#define mUsbIntEP0SetupEn(x)		(wFOTGPeri_Port(x,0x134) &= ~(BIT0))
++#define mUsbIntEP0InEn(x)		(wFOTGPeri_Port(x,0x134) &= ~(BIT1))
++#define mUsbIntEP0OutEn(x)		(wFOTGPeri_Port(x,0x134) &= ~(BIT2))
++#define mUsbIntEP0EndEn(x)		(wFOTGPeri_Port(x,0x134) &= ~(BIT3))
++#define mUsbIntEP0FailEn(x)		(wFOTGPeri_Port(x,0x134) &= ~(BIT4))
++
++#define mUsbIntSrc0MaskRd(x)		(wFOTGPeri_Port(x,0x134))
++
++// Mask of interrupt source group 1(0x138)
++#define mUsbIntFIFO0_3OUTDis(x)	        (wFOTGPeri_Port(x,0x138) |= 0xFF)
++#define mUsbIntFIFO0_3INDis(x)	        (wFOTGPeri_Port(x,0x138) |= 0xF0000)
++#define mUsbIntFIFO0_3Set(x,wTemp)	(wFOTGPeri_Port(x,0x138)|= wTemp)
++#define mUsbIntFIFO0_3Dis(x,wTemp)	(wFOTGPeri_Port(x,0x138)&= ~wTemp)
++
++#define mUsbIntF0OUTEn(x)		(wFOTGPeri_Port(x,0x138) &= ~(BIT1 | BIT0))
++#define mUsbIntF0OUTDis(x)		(wFOTGPeri_Port(x,0x138) |= (BIT1 | BIT0))
++#define mUsbIntF1OUTEn(x)		(wFOTGPeri_Port(x,0x138) &= ~(BIT3 | BIT2))
++#define mUsbIntF1OUTDis(x)		(wFOTGPeri_Port(x,0x138) |= (BIT3 | BIT2))
++#define mUsbIntF2OUTEn(x)		(wFOTGPeri_Port(x,0x138) &= ~(BIT5 | BIT4))
++#define mUsbIntF2OUTDis(x)		(wFOTGPeri_Port(x,0x138) |= (BIT5 | BIT4))
++#define mUsbIntF3OUTEn(x)		(wFOTGPeri_Port(x,0x138) &= ~(BIT7 | BIT6))
++#define mUsbIntF3OUTDis(x)		(wFOTGPeri_Port(x,0x138) |= (BIT7 | BIT6))
++
++#define mUsbIntFXOUTEn(x,bnum)	        (wFOTGPeri_Port(x,0x138) &= ~((BIT0<<((bnum)*2+1)) | (BIT0<<((bnum)*2))))
++#define mUsbIntFXOUTDis(x,bnum)     	(wFOTGPeri_Port(x,0x138) |= ((BIT0<<((bnum)*2+1)) | (BIT0<<((bnum)*2))))
++
++#define mUsbIntF0INEn(x)			(wFOTGPeri_Port(x,0x138) &= ~BIT16)
++#define mUsbIntF0INDis(x)		(wFOTGPeri_Port(x,0x138) |= BIT16)
++#define mUsbIntF1INEn(x)			(wFOTGPeri_Port(x,0x138) &= ~BIT17)
++#define mUsbIntF1INDis(x)		(wFOTGPeri_Port(x,0x138) |= BIT17)
++#define mUsbIntF2INEn(x)			(wFOTGPeri_Port(x,0x138) &= ~BIT18)
++#define mUsbIntF2INDis(x)		(wFOTGPeri_Port(x,0x138) |= BIT18)
++#define mUsbIntF3INEn(x)			(wFOTGPeri_Port(x,0x138) &= ~BIT19)
++#define mUsbIntF3INDis(x)		(wFOTGPeri_Port(x,0x138) |= BIT19)
++
++#define mUsbIntFXINEn(x,bnum)		(wFOTGPeri_Port(x,0x138) &= ~(BIT0<<(bnum+16)))
++#define mUsbIntFXINDis(x,bnum)	        (wFOTGPeri_Port(x,0x138) |= (BIT0<<(bnum+16)))
++
++#define mUsbIntSrc1MaskRd(x)		(wFOTGPeri_Port(x,0x138))
++
++// Mask of interrupt source group 2(DMA int mask)(0x13C)
++#define mUsbIntSuspDis(x)		(wFOTGPeri_Port(x,0x13C) |= BIT1)
++#define mUsbIntDmaErrDis(x)		(wFOTGPeri_Port(x,0x13C) |= BIT8)
++#define mUsbIntDmaFinishDis(x)	        (wFOTGPeri_Port(x,0x13C) |= BIT7)
++
++#define mUsbIntSuspEn(x)			(wFOTGPeri_Port(x,0x13C) &= ~(BIT1))
++#define mUsbIntDmaErrEn(x)		(wFOTGPeri_Port(x,0x13C) &= ~(BIT8))
++#define mUsbIntDmaFinishEn(x)	        (wFOTGPeri_Port(x,0x13C) &= ~(BIT7))
++
++#define mUsbIntSrc2MaskRd(x)		(wFOTGPeri_Port(x,0x13C))
++
++// Interrupt group (0x140)
++#define mUsbIntGroupRegRd(x)		(wFOTGPeri_Port(x,0x140))
++#define mUsbIntGroupRegSet(x,wValue)	(wFOTGPeri_Port(x,0x140) |= wValue)
++
++// Interrupt source group 0(0x144)
++#define mUsbIntSrc0Rd(x)			(wFOTGPeri_Port(x,0x144))
++#if !defined(CONFIG_PLATFORM_GM8126)
++#define mUsbIntEP0AbortClr(x)           (wFOTGPeri_Port(x,0x144) = BIT5)
++#else
++#define mUsbIntEP0AbortClr(x)	        (wFOTGPeri_Port(x,0x144) &= ~(BIT5))
++#endif
++#if !defined(CONFIG_PLATFORM_GM8126)
++#define mUsbIntSrc0Clr(x)		(wFOTGPeri_Port(x,0x144) = ~0)
++#else
++#define mUsbIntSrc0Clr(x)		(wFOTGPeri_Port(x,0x144) = 0)
++#endif
++#define mUsbIntSrc0Set(x,wValue)	        (wFOTGPeri_Port(x,0x144) |= wValue)
++
++// Interrupt source group 1(0x148)
++#define mUsbIntSrc1Rd(x)			(wFOTGPeri_Port(x,0x148))
++#define mUsbIntSrc1Set(x,wValue)	        (wFOTGPeri_Port(x,0x148) |= wValue)
++
++// Interrupt source group 2(0x14C)
++#define mUsbIntSrc2Rd(x)			(wFOTGPeri_Port(x,0x14C))
++#define mUsbIntSrc2Set(x,wValue)	        (wFOTGPeri_Port(x,0x14C) |= wValue)
++
++
++#if !defined(CONFIG_PLATFORM_GM8126)
++#define mUsbIntBusRstClr(x)		(wFOTGPeri_Port(x,0x14C) = BIT0)
++#define mUsbIntSuspClr(x)		(wFOTGPeri_Port(x,0x14C) = BIT1)
++#define mUsbIntResmClr(x)		(wFOTGPeri_Port(x,0x14C) = BIT2)
++#define mUsbIntIsoSeqErrClr(x)	        (wFOTGPeri_Port(x,0x14C) = BIT3)
++#define mUsbIntIsoSeqAbortClr(x)	(wFOTGPeri_Port(x,0x14C) = BIT4)
++#define mUsbIntTX0ByteClr(x)		(wFOTGPeri_Port(x,0x14C) = BIT5)
++#define mUsbIntRX0ByteClr(x)		(wFOTGPeri_Port(x,0x14C) = BIT6)
++#define mUsbIntDmaFinishClr(x)	        (wFOTGPeri_Port(x,0x14C) = BIT7)
++#define mUsbIntDmaErrClr(x)		(wFOTGPeri_Port(x,0x14C) = BIT8)
++#else
++#define mUsbIntBusRstClr(x)		(wFOTGPeri_Port(x,0x14C) &= ~BIT0)
++#define mUsbIntSuspClr(x)		(wFOTGPeri_Port(x,0x14C) &= ~BIT1)
++#define mUsbIntResmClr(x)		(wFOTGPeri_Port(x,0x14C) &= ~BIT2)
++#define mUsbIntIsoSeqErrClr(x)	        (wFOTGPeri_Port(x,0x14C) &= ~BIT3)
++#define mUsbIntIsoSeqAbortClr(x)	(wFOTGPeri_Port(x,0x14C) &= ~BIT4)
++#define mUsbIntTX0ByteClr(x)		(wFOTGPeri_Port(x,0x14C) &= ~BIT5)
++#define mUsbIntRX0ByteClr(x)		(wFOTGPeri_Port(x,0x14C) &= ~BIT6)
++#define mUsbIntDmaFinishClr(x)	        (wFOTGPeri_Port(x,0x14C) &= ~BIT7)
++#define mUsbIntDmaErrClr(x)		(wFOTGPeri_Port(x,0x14C) &= ~BIT8)
++#endif
++
++#define mUsbIntDmaFinishRd(x)		(wFOTGPeri_Port(x,0x14C) & BIT7)
++#define mUsbIntDmaErrRd(x)		(wFOTGPeri_Port(x,0x14C) & BIT8)
++
++// Rx 0 byte packet register(0x150)
++#define mUsbIntRX0ByteRd(x)		(u8)(wFOTGPeri_Port(x,0x150))
++#define mUsbIntRX0ByteSetClr(x,set)	(wFOTGPeri_Port(x,0x150) &= ~((u32)set))
++
++// Tx 0 byte packet register(0x154)
++#define mUsbIntTX0ByteRd(x)		(u8)(wFOTGPeri_Port(x,0x154))
++#define mUsbIntTX0ByteSetClr(x,data)	(wFOTGPeri_Port(x,0x154) &= ~((u32)data))
++
++// ISO sequential Error/Abort register(0x158)
++#define mUsbIntIsoSeqErrRd(x)		(u8)((wFOTGPeri_Port(x,0x158) & 0xff0000)>>16)
++#define mUsbIntIsoSeqErrSetClr(x,data)	(wFOTGPeri_Port(x,0x158) &= ~(((u32)data)<<16))
++
++#define mUsbIntIsoSeqAbortRd(x)	        (u8)(wFOTGPeri_Port(x,0x158) & 0xff)
++#define mUsbIntIsoSeqAbortSetClr(x,data)	(wFOTGPeri_Port(x,0x158) &= ~((u32)data))
++
++// IN Endpoint MaxPacketSize register(0x160,0x164,...,0x17C)
++#define mUsbEPinHighBandSet(x,EPn, dir , size )	(wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) &= ~(BIT14 |BIT13));  (wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) |= ((((u8)(size >> 11)+1) << 13)* dir) )
++
++#define mUsbEPMxPtSz(x,EPn, dir, size) (wFOTGPeri_Port(x,0x160 + ((1-dir) * 0x20) + ((EPn - 1) << 2)) = (u16)(size))
++
++#define mUsbEPMxPtSzClr(x,EPn, dir)    (wFOTGPeri_Port(x,0x160 + ((1-dir) * 0x20) + ((EPn - 1) << 2)) = 0)
++
++#define mUsbEPMxPtSzRd(x,EPn, dir)     ((wFOTGPeri_Port(x,0x160 + ((1-dir) * 0x20) + ((EPn - 1) << 2))) & 0x7ff)
++
++#define mUsbEPinMxPtSz(x,EPn)		(wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) & 0x7ff)
++#define mUsbEPinStallST(x,EPn)		((wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) & BIT11) >> 11)
++#define mUsbEPinStallClr(x,EPn)		(wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) &= ~BIT11)
++#define mUsbEPinStallSet(x,EPn)		(wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) |=  BIT11)
++#define mUsbEPinRsTgClr(x,EPn)		(wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) &= ~BIT12)
++#define mUsbEPinRsTgSet(x,EPn)	        (wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) |=  BIT12)
++#define mUsbEPinZeroSet(x,EPn)	        (wFOTGPeri_Port(x,0x160 + ((EPn - 1) << 2)) |=  BIT15)
++
++// OUT Endpoint MaxPacketSize register(0x180,0x164,...,0x19C)
++#define mUsbEPoutMxPtSz(x,EPn)	        ((wFOTGPeri_Port(x,0x180 + ((EPn - 1) << 2))) & 0x7ff)
++#define mUsbEPoutStallST(x,EPn)	        ((wFOTGPeri_Port(x,0x180 + ((EPn - 1) << 2)) & BIT11) >> 11)
++#define mUsbEPoutStallClr(x,EPn)	        (wFOTGPeri_Port(x,0x180 + ((EPn - 1) << 2)) &= ~BIT11)
++#define mUsbEPoutStallSet(x,EPn)	        (wFOTGPeri_Port(x,0x180 + ((EPn - 1) << 2)) |=  BIT11)
++#define mUsbEPoutRsTgClr(x,EPn)	        (wFOTGPeri_Port(x,0x180 + ((EPn - 1) << 2)) &= ~BIT12)
++#define mUsbEPoutRsTgSet(x,EPn)	        (wFOTGPeri_Port(x,0x180 + ((EPn - 1) << 2)) |=  BIT12)
++
++// Endpoint & FIFO Configuration
++// Endpoint 1~4 Map register(0x1a0), Endpoint 5~8 Map register(0x1a4)
++#define mUsbEPMap(x,EPn, MAP)	        (bFOTGPeri_Port(x,0x1a0 + (EPn-1)) = MAP)
++#define mUsbEPMapRd(x,EPn)		(bFOTGPeri_Port(x,0x1a0+ (EPn-1)))
++#define mUsbEPMapAllClr(x)		(wFOTGPeri_Port(x,0x1a0) = 0);(wFOTGPeri_Port(x,0x1a4) = 0)
++#define mUsbEPMap1_4Rd(x)                (wFOTGPeri_Port(x,0x1a0))
++
++// FIFO Map register(0x1a8)
++#define mUsbFIFOMap(x,FIFOn, MAP)	        (bFOTGPeri_Port(x,0x1a8 + FIFOn) = MAP)
++#define mUsbFIFOMapRd(x,FIFOn)	        (bFOTGPeri_Port(x,0x1a8 + FIFOn))
++#define mUsbFIFOMapAllClr(x)		(wFOTGPeri_Port(x,0x1a8) = 0)
++#define mUsbFIFOMapAllRd(x)              (wFOTGPeri_Port(x,0x1a8))
++// FIFO Configuration register(0x1ac)
++#define mUsbFIFOConfig(x,FIFOn, CONFIG)	(bFOTGPeri_Port(x,0x1ac + FIFOn) = CONFIG)
++#define mUsbFIFOConfigRd(x,FIFOn)		(bFOTGPeri_Port(x,0x1ac + FIFOn))
++#define mUsbFIFOConfigAllClr(x)		(bFOTGPeri_Port(x,0x1ac) = 0)
++#define FIFOEnBit			0x20
++#define mUsbFIFOConfigAllRd(x)          (wFOTGPeri_Port(x,0x1ac))
++// FIFO byte count register(0x1b0)
++#define mUsbFIFOOutByteCount(x,fifo_num)	(((wFOTGPeri_Port(x,0x1b0+(fifo_num)*4)&0x7ff)))
++#define mUsbFIFODone(x,fifo_num)		(wFOTGPeri_Port(x,0x1b0+(fifo_num)*4) |= BIT11)
++#define mUsbFIFOReset(x,fifo_num)		(wFOTGPeri_Port(x,0x1b0+(fifo_num)*4) |=  BIT12) //john
++#define mUsbFIFOResetOK(x,fifo_num)		(wFOTGPeri_Port(x,0x1b0+(fifo_num)*4) &= ~BIT12) //john
++
++// DMA target FIFO register(0x1c0)
++#define FOTG200_DMA2FIFO_Non 		0
++#define FOTG200_DMA2FIFO0 		BIT0
++#define FOTG200_DMA2FIFO1 		BIT1
++#define FOTG200_DMA2FIFO2 		BIT2
++#define FOTG200_DMA2FIFO3 		BIT3
++#define FOTG200_DMA2CxFIFO 		BIT4
++
++#define mUsbDMA2FIFOSel(x,sel)		(wFOTGPeri_Port(x,0x1c0) = sel)
++#define mUsbDMA2FIFORd(x)		(wFOTGPeri_Port(x,0x1c0))
++
++// DMA parameter set 1 (0x1c8)
++#define mUsbDmaConfig(x,len,Dir)	(wFOTGPeri_Port(x,0x1c8) = (((u32)len)<<8)|(Dir<<1))
++#define mUsbDmaLenRd(x)			((wFOTGPeri_Port(x,0x1c8) & 0x1ffff00) >> 8)
++#define mUsbDmaConfigRd(x)		(wFOTGPeri_Port(x,0x1c8))
++#define mUsbDmaConfigSet(set)		(wFOTGPeri_Port(x,0x1c8) = set)
++
++#define mUsbDmaStart(x)			(wFOTGPeri_Port(x,0x1c8) |= BIT0)
++#define mUsbDmaStop(x)			(wFOTGPeri_Port(x,0x1c8) &= ~BIT0)
++#define mUsbDmaAbort(x)			(wFOTGPeri_Port(x,0x1c8) |= (BIT3 | BIT4))
++
++// DMA parameter set 2 (0x1cc)
++#define mUsbDmaAddr(x,addr)		(wFOTGPeri_Port(x,0x1cc) = addr)
++#define mUsbDmaAddrRd(x)			(wFOTGPeri_Port(x,0x1cc))
++
++// 8 byte command data port(0x1d0)
++#define mUsbEP0CmdDataRdDWord(x)	        (wFOTGPeri_Port(x,0x1d0))
++
++//For OTG Definition;;0x80
++#define mUsb_OTGC_Control_B_BUS_REQ_Rd(x)	(wFOTGPeri_Port(x,0x80)& BIT0)
++#define mUsb_OTGC_Control_B_BUS_REQ_Set(x)  	(wFOTGPeri_Port(x,0x80) |=  BIT0)
++#define mUsb_OTGC_Control_B_BUS_REQ_Clr(x)  	(wFOTGPeri_Port(x,0x80) &=  (~BIT0))
++
++#define mUsb_OTGC_Control_B_HNP_EN_Rd(x)		(wFOTGPeri_Port(x,0x80)& BIT1)
++#define mUsb_OTGC_Control_B_HNP_EN_Set(x)	(wFOTGPeri_Port(x,0x80) |=  BIT1)
++#define mUsb_OTGC_Control_B_HNP_EN_Clr(x)  	(wFOTGPeri_Port(x,0x80) &=  (~BIT1))
++
++#define mUsb_OTGC_Control_B_DSCHG_VBUS_Rd(x)	(wFOTGPeri_Port(x,0x80)& BIT2)
++#define mUsb_OTGC_Control_B_DSCHG_VBUS_Set(x)	(wFOTGPeri_Port(x,0x80) |=  BIT2)
++#define mUsb_OTGC_Control_B_DSCHG_VBUS_Clr(x) 	(wFOTGPeri_Port(x,0x80) &=  (~BIT2))
++
++#define mUsb_OTGC_Control_B_SESS_END_Rd(x)	(wFOTGPeri_Port(x,0x80)& BIT16)
++#define mUsb_TGC_Control_B_SESS_VLD_Rd(x)	(wFOTGPeri_Port(x,0x80)& BIT17)
++#define mUsb_TGC_Control_A_SESS_VLD_Rd(x)	(wFOTGPeri_Port(x,0x80)& BIT18)
++#define mUsb_TGC_Control_A_VBUS_VLD_Rd(x)	(wFOTGPeri_Port(x,0x80)& BIT19)
++
++#define mUsb_OTGC_Control_CROLE_Rd(x)	        (wFOTGPeri_Port(x,0x80)& BIT20) //0:Host 1:Peripheral
++
++#define mUsb_dwOTGC_INT_STS_ROLE_CHG_Rd(x)       (wFOTGPeri_Port(x,0x84)& BIT8)
++
++//For Host Port Reset setting (Timing Critical)
++#define mUsb_mwHost20_PORTSC_PortReset_Rd(x)	(wFOTGPeri_Port(x,0x30) &=  BIT8)
++#define mUsb_mwHost20_PORTSC_PortReset_Set(x)	(wFOTGPeri_Port(x,0x30) |=  BIT8)
++#define mUsb_mwHost20_PORTSC_PortReset_Clr(x)	(wFOTGPeri_Port(x,0x30) &=  ~BIT8)
++
++#define mUsbIntFIFOEn(x,off,val)  (bFOTGPeri_Port(x,CPE_FOTG200_BASE(x) | off) &= ~(val))        //john
++#define mUsbIntFIFODis(x,off,val) (bFOTGPeri_Port(x,CPE_FOTG200_BASE(x) | off) |=  (val))        //john
++
++#endif /* __FOTG200_M_H  */
+diff --git a/drivers/usb/gadget/fotg2xx_udc.c b/drivers/usb/gadget/fotg2xx_udc.c
+new file mode 100644
+index 00000000..fd87ba72
+--- /dev/null
++++ b/drivers/usb/gadget/fotg2xx_udc.c
+@@ -0,0 +1,1686 @@
++/*******************************************************************************
++ * Module name: fotg2xx_udc.c
++ *
++ * Copyright 2006 GM as an unpublished work.
++ * All Rights Reserved.
++ *
++ * The Information contained herein is confidential property of Company.
++ * The user, copying, transfer or disclosure of such Information is
++ * prohibited except by express written agreement with Company.
++ *
++ * Written on 2006/6 by Elliot Hou Au-ping.
++ *
++ * Module Description:
++ *  This OTG UDC dirver for GM FOTG220 controller
++ *
++ ******************************************************************************/
++u8 cx_in_int_assert = 0, cx_out_int_assert = 0, bulk_out_int_assert = 0;
++
++/*-------------------------------------------------------------------------*/
++//*******************************************************************
++// Name:Get_FIFO_Num
++// Description:get the FIFO number from ep
++//             FIFO0=0
++//             FIFO1=1
++//             FIFO2=2
++//             FIFO3=3
++//             FIFO-CX = 0xFF
++//*******************************************************************
++static u8 Get_FIFO_Num(struct FTC_ep *ep)
++{
++	u8 u8fifo_n;
++
++	if (ep->num == 0) {
++		u8fifo_n = FIFOCX;
++		return (u8fifo_n);
++	}
++
++	u8fifo_n = mUsbEPMapRd(ep->dev->va_base,ep->num);	// get the relatived FIFO number
++	if (ep->is_in)
++		u8fifo_n &= 0x0F;
++	else
++		u8fifo_n >>= 4;
++
++	if (u8fifo_n >= MAX_FIFO_NUM)	// over the Max. fifo count ?
++		printk("??? Error ep > FUSB200_MAX_FIFO \n");
++
++	return (u8fifo_n);
++}
++
++/*-------------------------------------------------------------------------*/
++//****************************************************
++// Name:CX_dma_Directly
++// Description: Start DMA directly
++//              <1>.For Control Command - Get Stayus (Only for ep0)
++// Input:<1>.For Control Command - Get Stayus
++//       <2>.status
++// Output:none
++//****************************************************
++static int CX_dma_Directly(struct FTC_udc *dev, u8 * pu8Buffer, u32 u8Num, u8 bdir)
++{
++	u32 FIFO_Sel, wTemp, wDMABuffer, temp;
++	u8 u8fifo_n;
++
++	DBG_FUNCC("+CX_dma_Directly, start addr = 0x%x len=0x%x, dir =%x\n",
++		  (u32) pu8Buffer, u8Num, bdir);
++
++	//<1>.Get the FIFO Select
++	u8fifo_n = 0;
++	FIFO_Sel = FOTG200_DMA2CxFIFO;
++
++	//<2>.Map the DMA Buffer
++	temp = (u8Num + 15) / 16;
++	temp = temp * 16;
++	wDMABuffer = dma_map_single((void *)dev, pu8Buffer, temp,	//USB_EPX_BUFSIZ
++				    bdir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
++
++	//<3>.Init DMA start register
++	// EP=0,1,2,3,4
++	if (bdir)
++		mUsbDmaConfig(dev->va_base, u8Num, DIRECTION_OUT);
++	else
++		mUsbDmaConfig(dev->va_base, u8Num, DIRECTION_IN);
++
++	mUsbDMA2FIFOSel(dev->va_base,FIFO_Sel);
++	mUsbDmaAddr(dev->va_base,(u32) wDMABuffer);
++
++	//<4>.Enable the DMA
++	mUsbDmaStart(dev->va_base);
++
++	//<5>.Waiting for DMA complete
++	while (1) {
++		wTemp = mUsbIntSrc2Rd(dev->va_base);
++		if (wTemp & BIT8) {
++			mUsbIntDmaErrClr(dev->va_base);
++			printk("??? Cx IN DMA error..");
++			break;
++		}
++		if (wTemp & BIT7) {
++			mUsbIntDmaFinishClr(dev->va_base);
++			break;
++		}
++		if ((wTemp & 0x00000007) > 0) {	//If (Resume/Suspend/Reset) exit
++			mUsbIntDmaFinishClr(dev->va_base);
++			printk
++			    ("???? Cx IN DMA stop because USB Resume/Suspend/Reset..");
++			break;
++		}
++	}
++	mUsbDMA2FIFOSel(dev->va_base,FOTG200_DMA2FIFO_Non);
++
++	//<6>.Unmap the DMA
++	dma_unmap_single((void *)dev, wDMABuffer, temp,	//USB_EPX_BUFSIZ,  //req->req.length+32,
++			 bdir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
++	return 0;
++}
++
++//****************************************************
++// Name:start_dma
++// Description: Start the DMA
++//              For FOTG200-Peripheral HW:
++//              <1>.Control-8 byte command => Only PIO
++//              <2>.Others => Only DMA
++//
++// Input:<1>.ep structure point
++//       <2>.status
++// Output:none
++//****************************************************
++// return:  0 = q running, 1 = q stopped, negative = errno
++static int start_dma(struct FTC_ep *ep, struct FTC_request *req)
++{
++	struct FTC_udc *dev = ep->dev;
++	u32 FIFO_Sel = 0;
++	u8 u8fifo_n;
++
++    if ((dev->EPUseDMA != DMA_CHANEL_FREE) && (dev->EPUseDMA != ep->num))
++        return 0;
++
++	DBG_FUNCC("+start_dma, start addr = 0x%x len = 0x%x\n", req->req.dma, req->req.length);
++
++	//<0>.
++	//<1>.Get the FIFO Select
++	u8fifo_n = Get_FIFO_Num(ep);
++	if (u8fifo_n == FIFOCX)
++		FIFO_Sel = FOTG200_DMA2CxFIFO;
++	else
++		FIFO_Sel = 1 << (u8fifo_n);
++
++	//<2>.Init DMA start register
++	// EP=0,1,2,3,4
++	if (likely(ep->is_in)) {
++		if (req->req.length == 0) {
++			if ((ep->num) == 0)
++				mUsbEP0DoneSet(dev->va_base);
++			else
++				mUsbEPinZeroSet(dev->va_base, ep->num);
++            DBG_CTRLL("%s,%d: dma done(ep:%d)\n", __func__, __LINE__, ep->num);
++			done(ep, req, 0);
++			return 0;
++        } else {
++            if (ep->num==0) {
++                u32 max_packet = 64;
++
++                if (req->req.length <= max_packet)      //one packet is enough
++                    ep->wDMA_Set_Length = req->req.length;
++                else
++                    ep->wDMA_Set_Length = max_packet;
++            } else {
++                // for EP 1/3, we will IN all data at one time
++                ep->wDMA_Set_Length = req->req.length;
++            }
++            mUsbDmaConfig(dev->va_base, ep->wDMA_Set_Length, DIRECTION_IN);
++        }
++	} else {
++		if (ep->num == 0) {
++            u32 max_packet = 64;
++
++            if (cx_out_int_assert) {
++                cx_out_int_assert = 0;
++            } else {
++                ep->wDMA_Set_Length = 0;
++                return 0;
++            }
++
++            if (req->req.length <= max_packet)
++                ep->wDMA_Set_Length = req->req.length;
++            else
++                ep->wDMA_Set_Length = max_packet;
++			mUsbDmaConfig(dev->va_base, ep->wDMA_Set_Length, DIRECTION_OUT);
++		} else { //For EP1~EP4
++		    unsigned int out_fifo_byte_cnt = 0, ep_max_pkt_sz = 0;
++
++            out_fifo_byte_cnt = mUsbFIFOOutByteCount(dev->va_base, ((ep->num) - 1));
++            ep_max_pkt_sz = mUsbEPMxPtSzRd(dev->va_base, ((ep->num)), DIRECTION_OUT);
++
++			//Read the Byte Counter
++			if (out_fifo_byte_cnt == 0)
++				return 0;
++
++			DBG_CTRLL(">>>start_dma ==>(mUsbFIFOOutByteCount=0x%x(ep->num=0x%x)(MaxPackSize=0x%x))\n",
++				 out_fifo_byte_cnt, ep->num, ep_max_pkt_sz);
++
++			if (out_fifo_byte_cnt < ep_max_pkt_sz)
++				ep->wDMA_Set_Length = out_fifo_byte_cnt;
++			else
++				ep->wDMA_Set_Length = ep_max_pkt_sz;
++            mUsbDmaConfig(dev->va_base, ep->wDMA_Set_Length, DIRECTION_OUT);
++		}
++	}
++
++	mUsbDMA2FIFOSel(dev->va_base, FIFO_Sel);
++	mUsbDmaAddr(dev->va_base, req->req.dma);
++	DBG_CTRLL(">>>(mUsbDmaConfigRd=0x%x(Request Length=0x%x))\n",
++		  mUsbDmaConfigRd(dev->va_base), req->req.length);
++	DBG_CTRLL(">>>(mUsbDMA2FIFOSel=0x%x)\n", mUsbDMA2FIFORd(dev->va_base));
++	DBG_CTRLL(">>>(mUsbDmaAddr=0x%x)\n", mUsbDmaAddrRd(dev->va_base));
++
++	//<3>.Record who use the DMA chanel(In use)
++	dev->EPUseDMA = ep->num;
++
++	//<4>.Disable FIFO-Interrupt
++	// If use DMA, no FIFO interrupt for FIFO
++	//FIFO_Interrupt(ep,0);
++
++    // fifo interrupt on/off
++    if (ep->num == 0) {
++        if (ep->is_in == 0)
++            mUsbIntEP0OutDis(dev->va_base);
++    } else {
++        if (ep->is_in)
++            mUsbIntFXINDis(dev->va_base,((ep->num) - 1));
++        else
++            mUsbIntFXOUTDis(dev->va_base,((ep->num) - 1));
++    }
++
++	//<5>.Enable the DMA Interrupt
++	mUsbIntDmaErrEn(dev->va_base);
++	mUsbIntDmaFinishEn(dev->va_base);
++
++#if 0 // removed for PTP
++    if ((ep->num)!=0)
++        mUsbIntEP0SetupDis(dev->va_base);
++#endif
++
++	//<6>.Enable the DMA
++	mUsbDmaStart(dev->va_base);
++
++	DBG_FUNCC("-start_dma...\n");
++	return 0;
++}
++
++//****************************************************
++// Name:dma_advance
++// Description: After finish DMA
++// Input:<1>.dev structure pointer
++//       <2>.ep structure pointer
++// Output:none
++//****************************************************
++static void dma_advance(struct FTC_udc *dev, struct FTC_ep *ep)
++{
++	struct FTC_request *req;
++
++	DBG_FUNCC("+dma_advance\n");
++
++    if (unlikely(list_empty(&ep->queue))) {
++
++stop://Disable DMA)
++        mUsbDmaStop(dev->va_base);
++        mUsbIntDmaErrDis(dev->va_base);
++        mUsbIntDmaFinishDis(dev->va_base);
++        mUsbDMA2FIFOSel(dev->va_base,FOTG200_DMA2FIFO_Non);
++        dev->EPUseDMA = DMA_CHANEL_FREE;
++
++        if (unlikely(ep->num)) {	//ep->num>0
++            //Disable the FIFO-Interrupt (ep->Num>0)
++            if (likely(ep->is_in))
++                mUsbIntFXINDis(dev->va_base,((ep->num) - 1));
++            else
++                mUsbIntFXOUTDis(dev->va_base,((ep->num) - 1));
++        }
++
++        mUsbIntEP0SetupEn(dev->va_base);
++
++        // fifo interrupt on/off
++        if (ep->num == 0) {
++            if (ep->is_in)
++                mUsbIntEP0InEn(dev->va_base);
++            else
++                mUsbIntEP0OutEn(dev->va_base);
++        }
++
++        {
++            int i;
++
++            for (i = 1; i < FUSB220_CURRENT_SUPPORT_EP; i++)
++            {
++                struct FTC_ep *tp = &dev->ep[i];
++
++                if (tp->num == ep->num)
++                    continue;
++                if (unlikely(!list_empty(&tp->queue))) {
++                    if (likely(tp->is_in))
++                        mUsbIntFXINEn(dev->va_base,(i - 1));
++                    else
++                        mUsbIntFXOUTEn(dev->va_base,(i - 1));
++                }
++            }
++        }
++
++        return;
++    }
++
++	req = list_entry(ep->queue.next, struct FTC_request, queue);
++
++	//<2>.Get length
++	/* normal hw dma completion (not abort) */
++	if (mUsbIntDmaErrRd(dev->va_base) == 0) {
++		req->req.actual += ep->wDMA_Set_Length;
++		DBG_CTRLL(">>> dma_advance=>req->req.actual=0x%x  \n",
++			  req->req.actual);
++
++		// only control EP & IN will have such condition
++		if (likely(ep->is_in)) {
++            if (req->req.length > req->req.actual) {
++                u32 max_packet;
++
++                if (ep->num==0) {
++                    if (cx_in_int_assert) {
++                        cx_in_int_assert = 0;
++                    } else {
++                        mUsbIntEP0InEn(dev->va_base); // fifo interrupt on/off
++                        ep->wDMA_Set_Length = 0; // avoid to double count when reentry after cx_in_int
++                        return;
++                    }
++                    max_packet = 64;
++                } else {
++                    max_packet = mUsbEPMxPtSzRd(ep->dev->va_base, ep->num, DIRECTION_IN);
++                }
++
++                ep->wDMA_Set_Length = req->req.length - req->req.actual;
++                if (ep->wDMA_Set_Length > max_packet)
++                    ep->wDMA_Set_Length = max_packet;
++
++                mUsbDmaConfig(dev->va_base,ep->wDMA_Set_Length,DIRECTION_IN);
++                mUsbDmaAddr(dev->va_base,req->req.dma + req->req.actual);
++
++               // fifo interrupt on/off
++                if (ep->num == 0)
++                    mUsbIntEP0InDis(dev->va_base);
++                else
++                    mUsbIntFXINDis(dev->va_base,((ep->num) - 1));
++
++                mUsbIntDmaErrEn(dev->va_base);
++                mUsbIntDmaFinishEn(dev->va_base);
++
++                mUsbDmaStart(dev->va_base);
++                return;
++            }
++		} else {
++            if (ep->num == 0) {
++                if (req->req.length > req->req.actual) {
++                    // for control out ep and entered by cx_out_int triggered
++                    u32 max_packet = 64;
++
++                    if (cx_out_int_assert) {
++                        cx_out_int_assert = 0;
++                    } else {
++                        mUsbIntEP0OutEn(dev->va_base); // fifo interrupt on/off
++                        ep->wDMA_Set_Length = 0;
++                        return;
++                    }
++
++                    ep->wDMA_Set_Length = req->req.length - req->req.actual;
++                    if (ep->wDMA_Set_Length > max_packet)
++                        ep->wDMA_Set_Length = max_packet;
++
++                    mUsbDmaConfig(dev->va_base, ep->wDMA_Set_Length, DIRECTION_OUT);
++                    mUsbDmaAddr(dev->va_base, req->req.dma + req->req.actual);
++
++                    mUsbIntEP0OutDis(dev->va_base); // fifo interrupt on/off
++
++                    mUsbIntDmaErrEn(dev->va_base);
++                    mUsbIntDmaFinishEn(dev->va_base);
++
++                    mUsbDmaStart(dev->va_base);
++                    return;
++                }
++            } else {
++                if (req->req.length > req->req.actual) {
++                    unsigned int out_fifo_byte_cnt = 0, ep_max_pkt_sz = 0;
++
++                    ep_max_pkt_sz = mUsbEPMxPtSzRd(ep->dev->va_base, ((ep->num)), DIRECTION_OUT);
++
++                    if ((req->req.actual % ep_max_pkt_sz) == 0) {
++                        if (bulk_out_int_assert) {
++                            bulk_out_int_assert = 0;
++                        } else {
++                            mUsbIntFXOUTEn(dev->va_base,((ep->num) - 1)); // fifo interrupt on/off
++                            ep->wDMA_Set_Length = 0;
++                            return;
++                        }
++
++                        out_fifo_byte_cnt = mUsbFIFOOutByteCount(ep->dev->va_base, ((ep->num) - 1));
++
++                        // continue transfer remains
++                        if (out_fifo_byte_cnt < ep_max_pkt_sz)
++                            ep->wDMA_Set_Length = out_fifo_byte_cnt;
++                        else
++                            ep->wDMA_Set_Length = ep_max_pkt_sz;
++
++                        mUsbDmaConfig(ep->dev->va_base, ep->wDMA_Set_Length, DIRECTION_OUT);
++                        mUsbDmaAddr(dev->va_base, req->req.dma + req->req.actual);
++
++                        mUsbIntFXOUTDis(dev->va_base,((ep->num) - 1)); // fifo interrupt on/off
++
++                        mUsbIntDmaErrEn(dev->va_base);
++                        mUsbIntDmaFinishEn(dev->va_base);
++
++                        mUsbDmaStart(dev->va_base);
++                        return;
++                    }
++                }
++            }
++		}
++	} else {
++		printk("??? DMA Error...\n");
++		req->req.actual = 0;
++	}
++
++#ifdef USB_TRACE
++	VDBG(dev, "done %s %s dma, %u/%u bytes, req %p\n",
++	     ep->ep.name, ep->is_in ? "IN" : "OUT",
++	     req->req.actual, req->req.length, req);
++#endif
++
++	//<3>.Done the request
++    DBG_CTRLL("%s,%d: dma done(ep:%d)\n", __func__, __LINE__, ep->num);
++	done(ep, req, 0);
++
++	if (list_empty(&ep->queue))
++		goto stop;
++
++	//<4>.Start another req DMA
++	if (ep->num == 0) { // under test, nerver happened
++		req = list_entry(ep->queue.next, struct FTC_request, queue);
++		(void)start_dma(ep, req);
++	} else {
++		//<1>.Free the DMA resource => Waiting for next DMA-Start
++		mUsbDmaStop(dev->va_base);
++		mUsbIntDmaErrDis(dev->va_base);
++		mUsbIntDmaFinishDis(dev->va_base);
++		mUsbDMA2FIFOSel(dev->va_base,FOTG200_DMA2FIFO_Non);
++		dev->EPUseDMA = DMA_CHANEL_FREE;
++
++		//<2>.open the interrupt
++		if (likely(ep->is_in))
++			mUsbIntFXINEn(dev->va_base,((ep->num) - 1));	//Enable the Bulk-In
++		else
++			mUsbIntFXOUTEn(dev->va_base,((ep->num) - 1));	//Enable the Bulk-Out
++        mUsbIntEP0SetupEn(dev->va_base);
++
++        if ((ep->num == 1) || (ep->num == 2)) {
++            int i;
++
++            for (i = 3; i < FUSB220_CURRENT_SUPPORT_EP; i++) {
++                struct FTC_ep *tp = &dev->ep[i];
++
++                if (unlikely(!list_empty(&tp->queue))) {
++                    if (likely(ep->is_in))
++                        mUsbIntFXINDis(dev->va_base,((ep->num) - 1));    //Disable the Bulk-In
++                    else
++                        mUsbIntFXOUTDis(dev->va_base,((ep->num) - 1));   //Disable the Bulk-Out
++
++                    if (likely(tp->is_in))
++                        mUsbIntFXINEn(dev->va_base,(i - 1));    //Enable the Interrupt-In
++                    else
++                        mUsbIntFXOUTEn(dev->va_base,(i - 1));   //Enable the Interrupt-Out
++                }
++            }
++        }
++	}
++}
++
++//****************************************************
++// Name:FTC_queue
++// Description:
++// Input:<1>.ep structure point
++//       <2>.status
++//       <3>.flag
++// Output:none
++//****************************************************
++static int FTC_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags)
++{
++	struct FTC_request *req;
++	struct FTC_ep *ep;
++	struct FTC_udc *dev;
++	unsigned long flags;
++	int status;
++	u32 temp;
++
++	DBG_FUNCC("+FTC_queue()\n");
++
++	//<1>.Check request & ep & dev
++
++	/* always require a cpu-view buffer so pio works */
++	req = container_of(_req, struct FTC_request, req);
++	if (unlikely(!_req || !_req->complete
++		     || !_req->buf || !list_empty(&req->queue))) {
++		printk("??? FTC_queue => return -EINVAL\n");
++		return -EINVAL;
++	}
++
++	ep = container_of(_ep, struct FTC_ep, ep);
++	if (unlikely(!_ep || (!ep->desc && ep->num != 0))) {
++		printk("??? FTC_queue => return -EINVAL\n");
++		return -EINVAL;
++	}
++
++	dev = ep->dev;
++	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
++		printk("??? FTC_queue => return -ESHUTDOWN\n");
++		return -ESHUTDOWN;
++	}
++
++	//Check CX 0 bytes
++	if (req->req.length == 0) {
++		if (ep->num == 0) {	//request Control Transfer 0 byte
++			mUsbEP0DoneSet(dev->va_base);
++			mUsbCfgSet(dev->va_base);//Temp Solution for Set Configuration
++			DBG_CTRLL(">>> FTC_queue => return (set configuration)\n");
++			return 0;
++		}
++		//else => Other ED 0 bytes
++	}
++
++	/* can't touch registers when suspended */
++	if (dev->ep0state == EP0_SUSPEND) {
++		printk("??? FTC_queue => return -EBUSY\n");
++		return -EBUSY;
++	}
++
++	if (_req->dma == DMA_ADDR_INVALID) {
++		DBG_CTRLL("....dma_map_single len = %x, dev = %x, buf = %x\n",
++			  _req->length, dev, _req->buf);
++
++		//important : DMA length will set as 16*n bytes
++		temp = _req->length / 16;
++		if (_req->length % 16)
++			temp++;
++		temp = temp * 16;
++		_req->dma = dma_map_single((void *)dev, _req->buf, temp,	//USB_EPX_BUFSIZ,
++					   ep->is_in ? DMA_TO_DEVICE :
++					   DMA_FROM_DEVICE);
++		req->mapped = 1;
++	}
++#ifdef USB_TRACE
++	VDBG(dev, "%s queue req %p, len %u buf %p\n",
++	     _ep->name, _req, _req->length, _req->buf);
++#endif
++
++	//<2>.Set the req's status ...
++	spin_lock_irqsave(&dev->lock, flags);
++
++	_req->status = -EINPROGRESS;
++	_req->actual = 0;
++
++	//<3>.For control-in => Fource short packet
++
++	/* for ep0 IN without premature status, zlp is required and
++	 * writing EOP starts the status stage (OUT).
++	 */
++	if (unlikely(ep->num == 0 && ep->is_in))
++		_req->zero = 1;
++
++	/* kickstart this i/o queue? */
++	status = 0;
++
++	//In  => Write data to the FIFO directly
++	//Out => Only Enable the FIFO-Read interrupt
++	if (list_empty(&ep->queue) && likely(!ep->stopped)) {
++		//ep->num>0 ==> will add to queue until ed-FIFO-Interrupt be issue
++		/* dma:  done after dma completion IRQ (or error)
++		 * pio:  FOTG200 do not support
++		 */
++		DBG_CTRLL(">>> dev->EPUseDMA = 0x%x (ep->num=%x)\n",
++			  dev->EPUseDMA, ep->num);
++
++		if ((ep->num == 0) && (ep->is_in == 1))
++			status = start_dma(ep, req);
++
++		if (unlikely(status != 0)) {
++			if (status > 0)
++				status = 0;
++			req = 0;
++		}
++	}
++	/* else pio or dma irq handler advances the queue. */
++	//Add request to queue
++	if (likely(req != 0)) {
++        /*
++         * before add request to ep1-queue, check queue state and dma status
++         */
++        if ((ep->num == 1) && !list_empty(&ep->queue) && (dev->EPUseDMA == ep->num)) {
++            while (mUsbDmaConfigRd(dev->va_base) & BIT0)
++                ;
++        }
++
++		DBG_CTRLL(">>> add request to ep(%d) queue(0x%p) ...\n", ep->num, &ep->queue);
++		list_add_tail(&req->queue, &ep->queue);
++		if ((ep->num == 0) && (ep->is_in == 0) && (mUsbIntSrc0MaskRd(dev->va_base) & BIT2))
++            mUsbIntEP0OutEn(dev->va_base);
++	}
++	//Enable the FIFO Interrupt
++	if (likely((ep->num) > 0)) {	//Open the FIFO interrupt
++        if (list_empty(&(dev->ep[0].queue))) {
++    		if (likely((ep->is_in) == 1))	//For In-Ep
++    			mUsbIntFXINEn(dev->va_base,((ep->num) - 1));
++    		else		//For Out-Ep
++    			mUsbIntFXOUTEn(dev->va_base,((ep->num) - 1));
++
++     		DBG_CTRLL(">>> Enable EP-%x Interrupt (Register=0x%x)(Length=0x%x)...\n",
++    		     ep->num, mUsbIntSrc1MaskRd(dev->va_base), req->req.length);
++        }
++	}
++
++	spin_unlock_irqrestore(&dev->lock, flags);
++	return status;
++}
++
++//****************************************************
++// Name:ep_isr
++// Description: For Ep-1 In
++//             <1>.if queue have data start dma
++//
++//
++// Input:dev
++// Output:none
++//****************************************************
++void ep_isr(struct FTC_udc *dev, u8 epNum)
++{
++	struct FTC_request *req;
++	struct FTC_ep *ep;
++
++	DBG_FUNCC("+ep_isr(epNum=0x%x)\n", epNum);
++
++    if ((dev->EPUseDMA != DMA_CHANEL_FREE) && (dev->EPUseDMA != epNum)) {
++		if (likely(dev->ep[epNum].is_in))
++			mUsbIntFXINDis(dev->va_base,(epNum - 1));
++		else
++			mUsbIntFXOUTDis(dev->va_base,(epNum - 1));
++		return;
++	}
++
++	//<1>.Checking data in queue ?
++	ep = &(dev->ep[epNum]);
++
++	if (list_empty(&ep->queue)) {
++		if (likely(ep->is_in))
++			mUsbIntFXINDis(dev->va_base,((ep->num) - 1));//Disable the Bulk--In
++		else
++			mUsbIntFXOUTDis(dev->va_base,((ep->num) - 1));//Disable the Bulk-Out
++		printk("Error ep_isr ==> ep(%d)'s LIST(0x%p) is empty\n", epNum, &ep->queue);
++	} else {		//data in queue
++		if ((dev->EPUseDMA == DMA_CHANEL_FREE) || (dev->EPUseDMA == epNum)) {
++			//Start the DMA
++			req = list_entry(ep->queue.next, struct FTC_request, queue);
++            if (req->req.actual) {
++                if (ep->num == 2)
++                    bulk_out_int_assert = 1;
++                dma_advance(dev, ep);
++            } else
++			    start_dma(ep, req);
++		} else {
++			printk("Error ep_isr ==> LIST is full and DMA used %x\n", dev->EPUseDMA);
++		}
++	}
++}
++
++/////////////////////////////////////////////////////
++//              clrFIFORegister(void)
++//              Description:
++//              input: none
++//              output: none
++/////////////////////////////////////////////////////
++static void vUsbClrFIFORegister(struct FTC_udc *dev)
++{
++	u32 u8ep;
++
++	mUsbEPMapAllClr(dev->va_base);
++	mUsbFIFOMapAllClr(dev->va_base);
++	mUsbFIFOConfigAllClr(dev->va_base);
++
++	for (u8ep = 1; u8ep <= MAX_FIFO_NUM; u8ep++) {
++		mUsbEPMxPtSzClr(dev->va_base, u8ep, DIRECTION_IN);
++		mUsbEPMxPtSzClr(dev->va_base, u8ep, DIRECTION_OUT);
++	}
++}
++
++//////////////////////////////////////////////////////////////////////////////////////////////////
++// config FIFO
++//-----------------------------------------------------------------------
++/////////////////////////////////////////////////////
++//              vUsbFIFO_EPxCfg_HS(struct FTC_udc *dev)
++//              Description:
++//                      1. Configure the FIFO and EPx map
++//              input: none
++//              output: none
++/////////////////////////////////////////////////////
++static void vUsbFIFO_EPxCfg_FS(struct FTC_udc *dev)
++{
++	u32 i;
++
++	DBG_FUNCC("+vUsbFIFO_EPxCfg_FS()\n");
++
++	DBG_CTRLL("FIFO-Start:0~3\n");
++	DBG_CTRLL("Dir:Out=>1 / In =>0\n");
++	DBG_CTRLL("BLKSize:1=>64bytes / 2 =>128 bytes\n");
++	DBG_CTRLL("MaxPackSize:Max=64 bytes\n");
++	DBG_CTRLL("IFO-Use-Num:1=>Single / 2=>Double / 3=>TRIBLE\n");
++	DBG_CTRLL("FULL_ED4_bTYPE:0=>Control / 1=>ISO / 2=>Bulk / 3=>Interrupt\n");
++
++	vUsbClrFIFORegister(dev);
++
++	//EP4
++	mUsbEPMap(dev->va_base, EP4, FULL_EP4_Map);
++	mUsbFIFOMap(dev->va_base, FULL_ED4_FIFO_START, FULL_EP4_FIFO_Map);
++	mUsbFIFOConfig(dev->va_base, FULL_ED4_FIFO_START, FULL_EP4_FIFO_Config);
++
++	for (i = (FULL_ED4_FIFO_START+1);i < (FULL_ED4_FIFO_START+(FULL_ED4_bBLKNO*FULL_ED4_bBLKSIZE));i++) {
++		mUsbFIFOConfig(dev->va_base, i, (FULL_EP4_FIFO_Config & (~BIT7)));
++	}
++
++	mUsbEPMxPtSz(dev->va_base, EP4, FULL_ED4_bDIRECTION, (FULL_ED4_MAXPACKET & 0x7ff));
++	//mUsbEPinHighBandSet(dev->va_base, EP4, FULL_ED4_bDIRECTION, FULL_ED4_MAXPACKET);
++	DBG_CTRLL("EP4 Config = (FIFO-Start=0x%x) (Dir=0x%x)(BLKSize=0x%x)(MaxPackSize=0x%x)\n",
++		 FULL_ED4_FIFO_START, FULL_ED4_bDIRECTION, FULL_ED4_bBLKSIZE,
++		 FULL_ED4_MAXPACKET);
++	DBG_CTRLL("(FIFO-Use-Num=0x%x) (Type=0x%x)\n", FULL_ED4_bBLKNO, FULL_ED4_bTYPE);
++	DBG_CTRLL("Register Dump (mUsbEPMap=0x%x) (mUsbFIFOMap=0x%x)(mUsbFIFOConfig=0x%x)\n",
++		 mUsbEPMap1_4Rd(dev->va_base), mUsbFIFOMapAllRd(dev->va_base), mUsbFIFOConfigAllRd(dev->va_base));
++
++	//EP3
++	mUsbEPMap(dev->va_base, EP3, FULL_EP3_Map);
++	mUsbFIFOMap(dev->va_base, FULL_ED3_FIFO_START, FULL_EP3_FIFO_Map);
++	mUsbFIFOConfig(dev->va_base, FULL_ED3_FIFO_START, FULL_EP3_FIFO_Config);
++
++	for (i = FULL_ED3_FIFO_START+1;i < FULL_ED3_FIFO_START+(FULL_ED3_bBLKNO*FULL_ED3_bBLKSIZE);i++) {
++		mUsbFIFOConfig(dev->va_base, i, (FULL_EP3_FIFO_Config & (~BIT7)));
++	}
++
++	mUsbEPMxPtSz(dev->va_base, EP3, FULL_ED3_bDIRECTION, (FULL_ED3_MAXPACKET & 0x7ff));
++	//mUsbEPinHighBandSet(dev->va_base, EP3, FULL_ED3_bDIRECTION, FULL_ED3_MAXPACKET);
++	DBG_CTRLL("EP3 Config = (FIFO-Start=0x%x) (Dir=0x%x)(BLKSize=0x%x)(MaxPackSize=0x%x)\n",
++		 FULL_ED3_FIFO_START, FULL_ED3_bDIRECTION, FULL_ED3_bBLKSIZE,
++		 FULL_ED3_MAXPACKET);
++	DBG_CTRLL("(FIFO-Use-Num=0x%x) (Type=0x%x)\n", FULL_ED3_bBLKNO, FULL_ED3_bTYPE);
++	DBG_CTRLL("Register Dump (mUsbEPMap=0x%x) (mUsbFIFOMap=0x%x)(mUsbFIFOConfig=0x%x)\n",
++		 mUsbEPMap1_4Rd(dev->va_base), mUsbFIFOMapAllRd(dev->va_base), mUsbFIFOConfigAllRd(dev->va_base));
++
++	//EP2
++	mUsbEPMap(dev->va_base, EP2, FULL_EP2_Map);
++	mUsbFIFOMap(dev->va_base, FULL_ED2_FIFO_START, FULL_EP2_FIFO_Map);
++	mUsbFIFOConfig(dev->va_base, FULL_ED2_FIFO_START, FULL_EP2_FIFO_Config);
++	for (i = FULL_ED2_FIFO_START+1;i < FULL_ED2_FIFO_START+(FULL_ED2_bBLKNO*FULL_ED2_bBLKSIZE);i++) {
++		mUsbFIFOConfig(dev->va_base, i, (FULL_EP2_FIFO_Config & (~BIT7)));
++	}
++
++	mUsbEPMxPtSz(dev->va_base, EP2, FULL_ED2_bDIRECTION, (FULL_ED2_MAXPACKET & 0x7ff));
++	//mUsbEPinHighBandSet(dev->va_base, EP2, FULL_ED2_bDIRECTION, FULL_ED2_MAXPACKET);
++	DBG_CTRLL("EP2 Config = (FIFO-Start=0x%x) (Dir=0x%x)(BLKSize=0x%x)(MaxPackSize=0x%x)\n",
++		 FULL_ED2_FIFO_START, FULL_ED2_bDIRECTION, FULL_ED2_bBLKSIZE,
++		 FULL_ED2_MAXPACKET);
++	DBG_CTRLL("(FIFO-Use-Num=0x%x) (Type=0x%x)\n", FULL_ED2_bBLKNO, FULL_ED2_bTYPE);
++	DBG_CTRLL("Register Dump (mUsbEPMap=0x%x) (mUsbFIFOMap=0x%x)(mUsbFIFOConfig=0x%x)\n",
++		 mUsbEPMap1_4Rd(dev->va_base), mUsbFIFOMapAllRd(dev->va_base), mUsbFIFOConfigAllRd(dev->va_base));
++
++	//EP1
++	mUsbEPMap(dev->va_base, EP1, FULL_EP1_Map);
++	mUsbFIFOMap(dev->va_base, FULL_ED1_FIFO_START, FULL_EP1_FIFO_Map);
++	mUsbFIFOConfig(dev->va_base, FULL_ED1_FIFO_START, FULL_EP1_FIFO_Config);
++
++	for (i = FULL_ED1_FIFO_START+1;i < FULL_ED1_FIFO_START+(FULL_ED1_bBLKNO*FULL_ED1_bBLKSIZE);i++) {
++		mUsbFIFOConfig(dev->va_base, i, (FULL_EP1_FIFO_Config & (~BIT7)));
++	}
++
++	mUsbEPMxPtSz(dev->va_base, EP1, FULL_ED1_bDIRECTION, (FULL_ED1_MAXPACKET & 0x7ff));
++	//mUsbEPinHighBandSet(dev->va_base, EP1, FULL_ED1_bDIRECTION, FULL_ED1_MAXPACKET);
++	DBG_CTRLL("EP1 Config = (FIFO-Start=0x%x) (Dir=0x%x)(BLKSize=0x%x)(MaxPackSize=0x%x)\n",
++		 FULL_ED1_FIFO_START, FULL_ED1_bDIRECTION, FULL_ED1_bBLKSIZE,
++		 FULL_ED1_MAXPACKET);
++	DBG_CTRLL("(FIFO-Use-Num=0x%x) (Type=0x%x)\n", FULL_ED1_bBLKNO, FULL_ED1_bTYPE);
++	DBG_CTRLL("Register Dump (mUsbEPMap=0x%x) (mUsbFIFOMap=0x%x)(mUsbFIFOConfig=0x%x)\n",
++		 mUsbEPMap1_4Rd(dev->va_base), mUsbFIFOMapAllRd(dev->va_base), mUsbFIFOConfigAllRd(dev->va_base));
++}
++
++static void vUsbFIFO_EPxCfg_HS(struct FTC_udc *dev)
++{
++	u32 i;
++
++	DBG_FUNCC("+vUsbFIFO_EPxCfg_HS()\n");
++
++	DBG_CTRLL("FIFO-Start:0~3\n");
++	DBG_CTRLL("Dir:Out=>1 / In =>0\n");
++	DBG_CTRLL("BLKSize:1=>512bytes / 2 =>1024 bytes\n");
++	DBG_CTRLL("MaxPackSize:Max=1023 bytes\n");
++	DBG_CTRLL("IFO-Use-Num:1=>Single / 2=>Double / 3=>TRIBLE\n");
++	DBG_CTRLL("FULL_ED4_bTYPE:0=>Control / 1=>ISO / 2=>Bulk / 3=>Interrupt\n");
++
++	vUsbClrFIFORegister(dev);
++
++	//EP4
++	mUsbEPMap(dev->va_base, EP4, HIGH_EP4_Map);
++	mUsbFIFOMap(dev->va_base, HIGH_ED4_FIFO_START, HIGH_EP4_FIFO_Map);
++	mUsbFIFOConfig(dev->va_base, HIGH_ED4_FIFO_START, HIGH_EP4_FIFO_Config);
++
++	for (i = HIGH_ED4_FIFO_START + 1;
++	     i < HIGH_ED4_FIFO_START + (HIGH_ED4_bBLKNO * HIGH_ED4_bBLKSIZE);
++	     i++) {
++		mUsbFIFOConfig(dev->va_base, i, (HIGH_EP4_FIFO_Config & (~BIT7)));
++	}
++
++	mUsbEPMxPtSz(dev->va_base, EP4, HIGH_ED4_bDIRECTION, (HIGH_ED4_MAXPACKET & 0x7ff));
++	//mUsbEPinHighBandSet(dev->va_base, EP4, HIGH_ED4_bDIRECTION, HIGH_ED4_MAXPACKET);
++	DBG_CTRLL
++	    ("EP4 Config = (FIFO-Start=0x%x) (Dir=0x%x)(BLKSize=0x%x)(MaxPackSize=0x%x)\n",
++	     HIGH_ED4_FIFO_START, HIGH_ED4_bDIRECTION, HIGH_ED4_bBLKSIZE,
++	     HIGH_ED4_MAXPACKET);
++	DBG_CTRLL("             (FIFO-Use-Num=0x%x) (Type=0x%x)\n",
++		  HIGH_ED4_bBLKNO, HIGH_ED4_bTYPE);
++
++	//EP3
++	mUsbEPMap(dev->va_base, EP3, HIGH_EP3_Map);
++	mUsbFIFOMap(dev->va_base, HIGH_ED3_FIFO_START, HIGH_EP3_FIFO_Map);
++	mUsbFIFOConfig(dev->va_base, HIGH_ED3_FIFO_START, HIGH_EP3_FIFO_Config);
++
++	for (i = HIGH_ED3_FIFO_START+1;i < HIGH_ED3_FIFO_START+(HIGH_ED3_bBLKNO*HIGH_ED3_bBLKSIZE);i++) {
++		mUsbFIFOConfig(dev->va_base, i, (HIGH_EP3_FIFO_Config & (~BIT7)));
++	}
++
++	mUsbEPMxPtSz(dev->va_base, EP3, HIGH_ED3_bDIRECTION, (HIGH_ED3_MAXPACKET & 0x7ff));
++	//mUsbEPinHighBandSet(dev->va_base, EP3, HIGH_ED3_bDIRECTION, HIGH_ED3_MAXPACKET);
++	DBG_CTRLL("EP3 Config = (FIFO-Start=0x%x) (Dir=0x%x)(BLKSize=0x%x)(MaxPackSize=0x%x)\n",
++	     HIGH_ED3_FIFO_START, HIGH_ED3_bDIRECTION, HIGH_ED3_bBLKSIZE,
++	     HIGH_ED3_MAXPACKET);
++	DBG_CTRLL("(FIFO-Use-Num=0x%x) (Type=0x%x)\n", HIGH_ED3_bBLKNO, HIGH_ED3_bTYPE);
++
++	//EP2
++	mUsbEPMap(dev->va_base, EP2, HIGH_EP2_Map);
++	mUsbFIFOMap(dev->va_base, HIGH_ED2_FIFO_START, HIGH_EP2_FIFO_Map);
++	mUsbFIFOConfig(dev->va_base, HIGH_ED2_FIFO_START, HIGH_EP2_FIFO_Config);
++
++	for (i = HIGH_ED2_FIFO_START+1;i < HIGH_ED2_FIFO_START+(HIGH_ED2_bBLKNO*HIGH_ED2_bBLKSIZE);i++) {
++		mUsbFIFOConfig(dev->va_base, i, (HIGH_EP2_FIFO_Config & (~BIT7)));
++	}
++
++	mUsbEPMxPtSz(dev->va_base, EP2, HIGH_ED2_bDIRECTION, (HIGH_ED2_MAXPACKET & 0x7ff));
++	//mUsbEPinHighBandSet(dev->va_base, EP2, HIGH_ED2_bDIRECTION, HIGH_ED2_MAXPACKET);
++	DBG_CTRLL("EP2 Config = (FIFO-Start=0x%x) (Dir=0x%x)(BLKSize=0x%x)(MaxPackSize=0x%x)\n",
++	     HIGH_ED2_FIFO_START, HIGH_ED2_bDIRECTION, HIGH_ED2_bBLKSIZE,
++	     HIGH_ED2_MAXPACKET);
++	DBG_CTRLL("(FIFO-Use-Num=0x%x) (Type=0x%x)\n", HIGH_ED2_bBLKNO, HIGH_ED2_bTYPE);
++
++	//EP1
++	mUsbEPMap(dev->va_base, EP1, HIGH_EP1_Map);
++	mUsbFIFOMap(dev->va_base, HIGH_ED1_FIFO_START, HIGH_EP1_FIFO_Map);
++	mUsbFIFOConfig(dev->va_base, HIGH_ED1_FIFO_START, HIGH_EP1_FIFO_Config);
++
++	for (i = HIGH_ED1_FIFO_START+1;i < HIGH_ED1_FIFO_START+(HIGH_ED1_bBLKNO*HIGH_ED1_bBLKSIZE);i++) {
++		mUsbFIFOConfig(dev->va_base, i, (HIGH_EP1_FIFO_Config & (~BIT7)));
++	}
++
++	mUsbEPMxPtSz(dev->va_base, EP1, HIGH_ED1_bDIRECTION, (HIGH_ED1_MAXPACKET & 0x7ff));
++	//mUsbEPinHighBandSet(dev->va_base, EP1, HIGH_ED1_bDIRECTION, HIGH_ED1_MAXPACKET);
++	DBG_CTRLL("EP1 Config = (FIFO-Start=0x%x) (Dir=0x%x)(BLKSize=0x%x)(MaxPackSize=0x%x)\n",
++	     HIGH_ED1_FIFO_START, HIGH_ED1_bDIRECTION, HIGH_ED1_bBLKSIZE,
++	     HIGH_ED1_MAXPACKET);
++	DBG_CTRLL("(FIFO-Use-Num=0x%x) (Type=0x%x)\n", HIGH_ED1_bBLKNO, HIGH_ED1_bTYPE);
++	DBG_CTRLL("Register Dump (mUsbEPMap=0x%x) (mUsbFIFOMap=0x%x)(mUsbFIFOConfig=0x%x)\n",
++	     mUsbEPMap1_4Rd(dev->va_base), mUsbFIFOMapAllRd(dev->va_base), mUsbFIFOConfigAllRd(dev->va_base));
++}
++
++/*-------------------------------------------------------------------------*/
++// GM USB initial code
++
++///////////////////////////////////////////////////////////////////////////////
++//              vFOTG200_Dev_Init()
++//              Description:
++//                      1. Turn on the "Global Interrupt Enable" bit of FOTG200-P
++//                      2. Turn on the "Chip Enable" bit of FOTG200
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vFOTG200_Dev_Init(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+vFOTG200_Dev_Init()\n");
++
++	// suspend counter
++	//mUsbIdleCnt(dev->va_base,7);
++
++	// Soft Reset
++	mUsbSoftRstSet(dev->va_base);	// All circuit change to which state after Soft Reset?
++    //mUsbTstHalfSpeedEn(dev->va_base);
++	//mUsbSoftRstClr(dev->va_base);
++
++	// Clear interrupt
++	mUsbIntBusRstClr(dev->va_base);
++	mUsbIntSuspClr(dev->va_base);
++	mUsbIntResmClr(dev->va_base);
++
++    // Mask interrupt (mask device-idle, wakeupbyVBUS)
++    wFOTGPeri_Port(dev->va_base, 0x13C) = (BIT9 | BIT10);
++
++	// Disable all fifo interrupt
++	mUsbIntFIFO0_3OUTDis(dev->va_base);
++	mUsbIntFIFO0_3INDis(dev->va_base);
++
++	// Clear all fifo
++	mUsbClrAllFIFOSet(dev->va_base);	// will be cleared after one cycle.
++
++    // Mask CX_COMEND
++	mUsbIntEP0EndDis(dev->va_base);
++
++    mUsbChipEnSet(dev->va_base);
++    mUsbGlobIntEnSet(dev->va_base);
++    mUsbUnPLGClr(dev->va_base);
++#if defined(CONFIG_PLATFORM_GM8136)
++    if (CONFIG_GM_OTG_CHOOSE == 1)
++        mUsbForceFSSet(dev->va_base);
++#endif
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              vUsbInit(struct FTC_udc *dev)
++//              Description:
++//                      1. Configure the FIFO and EPx map.
++//                      2. Init FOTG200-Peripheral.
++//                      3. Set the usb interrupt source as edge-trigger.
++//                      4. Enable Usb interrupt.
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vUsbInit(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+vUsbInit()\n");
++
++	// init variables
++	dev->u16TxRxCounter = 0;
++	dev->eUsbCxCommand = CMD_VOID;
++	dev->u8UsbConfigValue = 0;
++	dev->u8UsbInterfaceValue = 0;
++	dev->u8UsbInterfaceAlternateSetting = 0;
++
++	// init hardware
++	vFOTG200_Dev_Init(dev);
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              vUsb_rst(struct FTC_udc *dev)
++//              Description:
++//                      1. Change descriptor table (High or Full speed).
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vUsb_rst(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+vUsb_rst()\n");
++
++	Info(dev, "L%x, Bus reset\n", dev->u8LineCount++);
++
++	mUsbIntBusRstClr(dev->va_base);
++	dev->gadget.speed = USB_SPEED_UNKNOWN;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              vUsb_suspend(dev)
++//              Description:
++//                      1. .
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vUsb_suspend(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+vUsb_suspend()\n");
++
++	Info(dev, "L%x, Bus suspend\n", dev->u8LineCount++);
++	// uP must do-over everything it should handle and do before into the suspend mode
++	// Go Suspend status
++	mUsbIntSuspClr(dev->va_base);
++	if (dev->gadget.b_hnp_enable) {
++		mUsbGlobIntDis(dev->va_base);
++		wFOTGPeri_Port(dev->va_base, 0x130) |= (BIT0 | BIT1 | BIT2);
++		mUsb_OTGC_Control_B_HNP_EN_Set(dev->va_base);
++	}
++	//john, clear FIFO for suspend to avoid extra interrupt
++	mUsbFIFODone(dev->va_base, 0);
++	mUsbFIFODone(dev->va_base, 1);
++	mUsbFIFODone(dev->va_base, 2);
++	mUsbFIFODone(dev->va_base, 3);
++
++	//Bruce;;mUsbGoSuspend();
++	dev->gadget.b_hnp_enable = 0;
++	dev->ep0state = EP0_SUSPEND;
++
++    /* because the iddig detection of otg function is disabled, we can
++     * ignore the suspend state on otg protocol.
++     * we want to show the real status of current speed under the path
++     * /sys/devices/fotg2xx_udc/udc/fotg2xx_udc/current_speed
++     * after usb cable is un-plugged.
++     */
++	dev->gadget.speed = USB_SPEED_UNKNOWN;
++
++#if defined(USB_NOTIFY)
++	sys_kill(pid, SIGUSR2);
++#endif
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              vUsb_resm(struct FTC_udc        *dev)
++//              Description:
++//                      1. Change descriptor table (High or Full speed).
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vUsb_resm(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+vUsb_resm()\n");
++
++	Info(dev, "L%x, Bus resume\n", dev->u8LineCount++);
++	// uP must do-over everything it should handle and do before into the suspend mode
++	// uP must wakeup immediately
++	mUsbIntResmClr(dev->va_base);
++
++	dev->ep0state = EP0_IDLE;
++}
++
++void vUsbClrEPx(struct FTC_udc *dev)
++{
++	u32 u8ep;
++
++	DBG_FUNCC("+vUsbClrEPx()\n");
++
++	// Clear All EPx Toggle Bit
++	for (u8ep = 1; u8ep <= MAX_EP_NUM; u8ep++) {
++		mUsbEPinRsTgSet(dev->va_base,u8ep);
++		mUsbEPinRsTgClr(dev->va_base,u8ep);
++	}
++
++	for (u8ep = 1; u8ep <= MAX_EP_NUM; u8ep++) {
++		mUsbEPoutRsTgSet(dev->va_base,u8ep);
++		mUsbEPoutRsTgClr(dev->va_base,u8ep);
++	}
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              bGet_status(struct FTC_udc *dev)
++//              Description:
++//                      1. Send 2 bytes status to host.
++//              input: none
++//              output: TRUE or FALSE (u8)
++///////////////////////////////////////////////////////////////////////////////
++static u8 bGet_status(struct FTC_udc *dev, const struct usb_ctrlrequest *ctrl)
++{
++	u8 u8ep_n, u8fifo_n, RecipientStatusLow, RecipientStatusHigh;
++	u8 u8Tmp[2];
++	u8 bdir;
++
++	DBG_FUNCC("+bGet_status()  \n");
++
++	RecipientStatusLow = 0;
++	RecipientStatusHigh = 0;
++	switch ((ctrl->bRequestType) & 0x3) {	// Judge which recipient type is at first
++		case 0:		// Device
++			// Return 2-byte's Device status (Bit1:Remote_Wakeup, Bit0:Self_Powered) to Host
++			// Notice that the programe sequence of RecipientStatus
++			RecipientStatusLow = mUsbRmWkupST(dev->va_base) << 1;
++			// Bit0: Self_Powered--> DescriptorTable[0x23], D6(Bit 6)
++			// Now we force device return data as self power. (Andrew)
++			RecipientStatusLow |= ((USB_CONFIG_ATT_SELFPOWER >> 6) & 0x01);
++			break;
++		case 1:		// Interface
++			// Return 2-byte ZEROs Interface status to Host
++			break;
++		case 2:		// Endpoint
++			if (ctrl->wIndex == 0x00) {
++				if (dev->ep0state == EP0_STALL)
++					RecipientStatusLow = TRUE;
++			} else {
++				u8ep_n = (u8) ctrl->wIndex & 0x7F;	// which ep will be clear
++				bdir = (u8) ctrl->wIndex >> 7;	// the direction of this ep
++				if (u8ep_n > MAX_EP_NUM)	// over the Max. ep count ?
++					return FALSE;
++				else {
++					u8fifo_n = mUsbEPMapRd(dev->va_base,u8ep_n);	// get the relatived FIFO number
++					if (bdir == 1)
++						u8fifo_n &= 0x0F;
++					else
++						u8fifo_n >>= 4;
++					if (u8fifo_n >= MAX_FIFO_NUM)	// over the Max. fifo count ?
++						return FALSE;
++					// Check the FIFO had been enable ?
++					if (bdir == 1)	// IN direction ?
++						RecipientStatusLow = mUsbEPinStallST(dev->va_base,u8ep_n);
++					else
++						RecipientStatusLow = mUsbEPoutStallST(dev->va_base,u8ep_n);
++				}
++			}
++			break;
++		default:
++			return FALSE;
++	}
++
++	// return RecipientStatus;
++	u8Tmp[0] = RecipientStatusLow;
++	u8Tmp[1] = RecipientStatusHigh;
++
++	//Use DMA to transfer data
++	CX_dma_Directly(dev, u8Tmp, 2, 1);
++
++	mUsbEP0DoneSet(dev->va_base);
++
++	return TRUE;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              bClear_feature(struct FTC_udc *dev)
++//              Description:
++//                      1. Send 2 bytes status to host.
++//              input: none
++//              output: TRUE or FALSE (u8)
++///////////////////////////////////////////////////////////////////////////////
++static u8 bClear_feature(struct FTC_udc *dev, const struct usb_ctrlrequest *ctrl)
++{
++	u8 u8ep_n;
++	u8 u8fifo_n;
++	u8 bdir;
++
++	DBG_FUNCC("+bClear_feature()\n");
++
++	switch (ctrl->wValue)	// FeatureSelector
++	{
++	case 0:		// ENDPOINT_HALE
++		// Clear "Endpoint_Halt", Turn off the "STALL" bit in Endpoint Control Function Register
++		if (ctrl->wIndex == 0x00)
++			u8ep_n = 0;	//Sp0 ed clear feature
++		else {
++			u8ep_n = ctrl->wIndex & 0x7F;	// which ep will be clear
++			bdir = ctrl->wIndex >> 7;	// the direction of this ep
++			if (u8ep_n > MAX_EP_NUM)	// over the Max. ep count ?
++				return FALSE;
++			else {
++				u8fifo_n = Get_FIFO_Num(&dev->ep[u8ep_n]);	// get the relatived FIFO number
++				if (u8fifo_n < MAX_FIFO_NUM)
++					if ((mUsbFIFOConfigRd(dev->va_base, u8fifo_n) & FIFOEnBit) == 0)//FIFO enable?
++						return FALSE;
++			}
++		}
++		FTC_clear_halt(&dev->ep[u8ep_n]);
++		break;
++	case 1:		// Device Remote Wakeup
++		// Clear "Device_Remote_Wakeup", Turn off the"RMWKUP" bit in Main Control Register
++		mUsbRmWkupClr(dev->va_base);
++		break;
++	case 2:		// Test Mode
++		return FALSE;
++	default:
++		return FALSE;
++	}
++
++	mUsbEP0DoneSet(dev->va_base);
++	return TRUE;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              bSet_feature(struct FTC_udc *dev)
++//              Description:
++//                      1. Send 2 bytes status to host.
++//              input: none
++//              output: TRUE or FALSE (u8)
++///////////////////////////////////////////////////////////////////////////////
++static u8 bSet_feature(struct FTC_udc *dev, const struct usb_ctrlrequest *ctrl)
++{
++	u8 i;
++	u8 u8ep_n;
++	u8 u8fifo_n;
++	u8 u8Tmp[55];
++	u8 *pp;
++	u8 bdir;
++
++	DBG_FUNCC("+bSet_feature()\n");
++
++	switch (ctrl->wValue) {	// FeatureSelector
++		case 0:		// ENDPOINT_HALT
++			// Set "Endpoint_Halt", Turn on the "STALL" bit in Endpoint Control Function Register
++			if (ctrl->wIndex == 0x00)
++				FTC_set_halt(dev->gadget.ep0, PROTO_STALL);	// Return EP0_Stall
++			else {
++				u8ep_n = ctrl->wIndex & 0x7F;	// which ep will be clear
++				bdir = ctrl->wIndex >> 7;	// the direction of this ep
++				u8fifo_n = Get_FIFO_Num(&dev->ep[u8ep_n]);	// get the relatived FIFO number
++				if (u8fifo_n < MAX_FIFO_NUM)	// Check the FIFO had been enable ?
++					if ((mUsbFIFOConfigRd(dev->va_base,u8fifo_n) & FIFOEnBit) ==	0)
++						return FALSE;
++
++				if (bdir == 1)	// IN direction ?
++					mUsbEPinStallSet(dev->va_base,u8ep_n);	// Clear Stall Bit
++				else
++					mUsbEPoutStallSet(dev->va_base,u8ep_n);	// Set Stall Bit
++			}
++			break;
++		case 1:		// Device Remote Wakeup
++			// Set "Device_Remote_Wakeup", Turn on the"RMWKUP" bit in Mode Register
++			mUsbRmWkupSet(dev->va_base);
++			break;
++
++		case 2:		// Test Mode
++			switch ((ctrl->wIndex >> 8)) {	// TestSelector
++				case 0x1:	// Test_J
++					mUsbTsMdWr(dev->va_base, 1 << TEST_J);
++					break;
++				case 0x2:	// Test_K
++					mUsbTsMdWr(dev->va_base, 1 << TEST_K);
++					break;
++				case 0x3:	// TEST_SE0_NAK
++					mUsbTsMdWr(dev->va_base, 1 << TEST_SE0_NAK);
++					break;
++				case 0x4:	// Test_Packet
++					mUsbTsMdWr(dev->va_base, 1 << TEST_PACKET);
++					mUsbEP0DoneSet(dev->va_base);// special case: follow the test sequence
++					pp = u8Tmp;
++					for (i = 0; i < 9; i++)	// JKJKJKJK x 9
++						(*pp++) = (0x00);
++
++					//(*pp++) = (0xAA);
++					//(*pp++) = (0x00);
++
++					for (i = 0; i < 8; i++)	// JJKKJJKK *8, 8*AA
++						(*pp++) = (0xAA);
++
++					for (i = 0; i < 8; i++)	//JJJJKKKK *8, 8*EE
++						(*pp++) = (0xEE);
++
++					(*pp++) = (0xFE);	//JJJJJJJKKKKKKK *8,
++					for (i = 0; i < 11; i++)	// 11*FF
++						(*pp++) = (0xFF);
++
++					(*pp++) = (0x7F);	// JJJJJJJK * 8
++					(*pp++) = (0xBF);
++					(*pp++) = (0xDF);
++					(*pp++) = (0xEF);
++					(*pp++) = (0xF7);
++					(*pp++) = (0xFB);
++					(*pp++) = (0xFD);
++					(*pp++) = (0xFC);
++					(*pp++) = (0x7E);	// {JKKKKKKK * 10}, JK
++					(*pp++) = (0xBF);
++					(*pp++) = (0xDF);
++					(*pp++) = (0xEF);
++					(*pp++) = (0xF7);
++					(*pp++) = (0xFB);
++					(*pp++) = (0xFD);
++					(*pp) = (0x7E);
++					CX_dma_Directly(dev, u8Tmp, 53, 1);
++					mUsbEP0DoneSet(dev->va_base);
++
++					// Turn on "r_test_packet_done" bit(flag) (Bit 5)
++					mUsbTsPkDoneSet(dev->va_base);
++					return TRUE;
++					break;
++				case 0x5:	// Test_Force_Enable
++					//FUSBPort[0x08] = 0x20; //Start Test_Force_Enable
++					break;
++				default:
++					return FALSE;
++			}
++			break;
++		case 3:		//For OTG => b_hnp_enable
++			dev->gadget.b_hnp_enable = 1;
++			//<1>.Set b_Bus_Request
++			mUsb_OTGC_Control_B_BUS_REQ_Set(dev->va_base);
++
++			//<2>.Set the HNP enable
++			mUsb_OTGC_Control_B_HNP_EN_Set(dev->va_base);
++			printk("FOTG2XX Device set HNP ... HNP:%x B_BUS_REQ:%x\n",
++			mUsb_OTGC_Control_B_HNP_EN_Rd(dev->va_base),mUsb_OTGC_Control_B_BUS_REQ_Rd(dev->va_base));
++			break;
++		case 4:		//For OTG => b_hnp_enable
++			dev->gadget.a_hnp_support = 1;
++			break;
++		case 5:		//For OTG => b_hnp_enable
++			dev->gadget.a_alt_hnp_support = 1;
++			printk(">>> Please Connect to an alternate port on the A-device for HNP...\n");
++			break;
++		default:
++			return FALSE;
++	}
++
++	mUsbEP0DoneSet(dev->va_base);
++	return TRUE;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              bSynch_frame(struct FTC_udc *dev)
++//              Description:
++//                      1. If the EP is a Iso EP, then return the 2 bytes Frame number.
++//                               else stall this command
++//              input: none
++//              output: TRUE or FALSE
++///////////////////////////////////////////////////////////////////////////////
++static u8 bSynch_frame(struct FTC_udc *dev, const struct usb_ctrlrequest *ctrl)
++{
++	DBG_FUNCC("+bSynch_frame()  ==> add by Andrew\n");
++
++	if ((ctrl->wIndex == 0) || (ctrl->wIndex > 4))
++		return FALSE;
++
++	// Does the Endpoint support Isochronous transfer type?
++	mUsbEP0DoneSet(dev->va_base);
++	return TRUE;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              bSet_address(struct FTC_udc *dev)
++//              Description:
++//                      1. Set addr to FUSB200 register.
++//              input: none
++//              output: TRUE or FALSE (u8)
++///////////////////////////////////////////////////////////////////////////////
++static u8 bSet_address(struct FTC_udc *dev, const struct usb_ctrlrequest *ctrl)
++{
++	DBG_FUNCC("+bSet_address() = %d\n", ctrl->wValue);
++
++	if (ctrl->wValue >= 0x0100)
++		return FALSE;
++	else {
++		mUsbDevAddrSet(dev->va_base,ctrl->wValue);
++		mUsbEP0DoneSet(dev->va_base);
++		return TRUE;
++	}
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              vUsb_ep0setup(struct FTC_udc *dev)
++//              Description:
++//                      1. Read the speed
++//                      2. Read 8-byte setup packet.
++//          3. Process the standard command:
++//             <1>.bSet_address
++//
++//
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vUsb_ep0setup(struct FTC_udc *dev)
++{
++	u8 u8UsbCmd[8];
++	struct usb_ctrlrequest ctrl;
++	int tmp;
++	u32 u32UsbCmd[2];
++
++	DBG_FUNCC("+vUsb_ep0setup()\n");
++
++	//<1>.Read the speed
++	if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
++		// first ep0 command after usb reset, means we can check usb speed right now.
++		if (mUsbHighSpeedST(dev->va_base))	// First we should judge HS or FS
++		{
++			Info(dev, "L%x, high speed mode\n", dev->u8LineCount++);
++			dev->gadget.speed = USB_SPEED_HIGH;
++			vUsbFIFO_EPxCfg_HS(dev);//Set the FIFO Information
++		} else {
++			Info(dev, "L%x, full speed mode\n", dev->u8LineCount++);
++			dev->gadget.speed = USB_SPEED_FULL;
++			vUsbFIFO_EPxCfg_FS(dev);//Set the FIFO Information
++		}
++		dev->ep0state = EP0_IDLE;
++	}
++	//<2>.Dequeue ALL requests
++	nuke(&dev->ep[0], 0);
++	dev->ep[0].stopped = 0;
++
++	//<3>.Read 8-byte setup packet from FIFO
++
++	// Read 8-byte setup packet from FIFO
++	mUsbDMA2FIFOSel(dev->va_base,FOTG200_DMA2CxFIFO);
++	u32UsbCmd[0] = mUsbEP0CmdDataRdDWord(dev->va_base);
++	u32UsbCmd[1] = mUsbEP0CmdDataRdDWord(dev->va_base);
++	mUsbDMA2FIFOSel(dev->va_base,FOTG200_DMA2FIFO_Non);
++	memcpy(u8UsbCmd, u32UsbCmd, 8);
++
++	DBG_CTRLL("L%x, EP0Cmd:%02x %02x %02x %02x %02x %02x %02x %02x\n",
++		  dev->u8LineCount++, u8UsbCmd[0], u8UsbCmd[1], u8UsbCmd[2],
++		  u8UsbCmd[3], u8UsbCmd[4], u8UsbCmd[5], u8UsbCmd[6],
++		  u8UsbCmd[7]);
++
++	/* read SETUP packet and enter DATA stage */
++	ctrl.bRequestType = u8UsbCmd[0];
++	ctrl.bRequest = u8UsbCmd[1];
++	ctrl.wValue = (u8UsbCmd[3] << 8) | u8UsbCmd[2];
++	ctrl.wIndex = (u8UsbCmd[5] << 8) | u8UsbCmd[4];
++	ctrl.wLength = (u8UsbCmd[7] << 8) | u8UsbCmd[6];
++
++	if (likely(ctrl.bRequestType & USB_DIR_IN)) {
++		dev->ep[0].is_in = 1;
++		dev->ep0state = EP0_IN;
++	} else {
++		dev->ep[0].is_in = 0;
++		dev->ep0state = EP0_OUT;
++	}
++
++	if ((ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
++    	//Parsing the Standard Command
++    	switch (ctrl.bRequest)	// by Standard Request codes
++    	{
++    	case USB_REQ_CLEAR_FEATURE:	// clear feature
++    		if (bClear_feature(dev, &(ctrl)) == FALSE)
++    			goto stall;
++    		break;
++    	case USB_REQ_SET_ADDRESS:	// set address
++    		if (dev->ep0state == EP0_STALL)
++    			goto stall;
++    		if (bSet_address(dev, &(ctrl)) == FALSE)
++    			goto stall;
++    		break;
++    	case USB_REQ_SET_FEATURE:	// clear feature
++    		if (bSet_feature(dev, &(ctrl)) == FALSE)
++    			goto stall;
++    		break;
++    	case USB_REQ_GET_STATUS:	// clear feature
++    		if (bGet_status(dev, &(ctrl)) == FALSE)
++    			goto stall;
++    		break;
++    	case USB_REQ_SYNCH_FRAME:	// clear feature
++    		if (dev->ep0state == EP0_STALL)
++    			goto stall;
++    		if (bSynch_frame(dev, &(ctrl)) == FALSE)
++    			goto stall;
++    		break;
++    	default:		/* pass to gadget driver */
++    		if (dev->ep0state == EP0_STALL)
++    			goto stall;
++
++    		spin_unlock(&dev->lock);
++    		tmp = dev->driver->setup(&dev->gadget, &(ctrl));
++    		spin_lock(&dev->lock);
++    		DBG_CTRLL(">>>Exit Driver call back setup function...\n");
++    		if (unlikely(tmp < 0))
++    			goto stall;
++    		break;
++    	}
++	} else if ((ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) {
++        if (dev->ep0state == EP0_STALL)
++            goto stall;
++
++        spin_unlock(&dev->lock);
++        tmp = dev->driver->setup(&dev->gadget, &(ctrl));
++        spin_lock(&dev->lock);
++        if (unlikely(tmp < 0))
++            goto stall;
++	} else if ((ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
++        printk(">>>EP0 Vendor Cmd:%02x %02x %02x %02x %02x %02x %02x %02x\n",
++              u8UsbCmd[0], u8UsbCmd[1], u8UsbCmd[2], u8UsbCmd[3],
++              u8UsbCmd[4], u8UsbCmd[5], u8UsbCmd[6], u8UsbCmd[7]);
++	}
++	//Normal Exit
++	return;
++
++	//Stall the command
++stall:
++#ifdef USB_TRACE
++	VDBG(dev, "req %02x.%02x protocol STALL; err %d\n", ctrl.bRequestType,
++	     ctrl.bRequest, tmp);
++#endif
++	Info(dev, "Set STALL in vUsb_ep0setup\n");
++	FTC_set_halt(dev->gadget.ep0, PROTO_STALL);	// Return EP0_Stall
++	dev->ep[0].stopped = 1;
++	dev->ep0state = EP0_STALL;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              vUsb_ep0end(struct FTC_udc *dev)
++//              Description:
++//                      1. End this transfer.
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vUsb_ep0end(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+vUsb_ep0end()\n");
++
++	dev->eUsbCxCommand = CMD_VOID;
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              vUsb_ep0fail(struct FTC_udc *dev)
++//              Description:
++//                      1. Stall this transfer.
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vUsb_ep0fail(struct FTC_udc *dev)
++{
++	DBG_FUNCC("+vUsb_ep0fail()\n");
++	Info(dev, "L%x, EP0 fail\n", dev->u8LineCount++);
++
++	FTC_set_halt(dev->gadget.ep0, PROTO_STALL);	// Return EP0_Stall
++}
++
++///////////////////////////////////////////////////////////////////////////////
++//              vUsbHandler(struct FTC_udc      *dev)
++//              Description:
++//                      1. Service all Usb events
++//                      2. ReEnable Usb interrupt.
++//              input: none
++//              output: none
++///////////////////////////////////////////////////////////////////////////////
++static void vUsbHandler(struct FTC_udc *dev)	//FOTG200.ok
++{
++	u32 usb_interrupt_level2;
++	u32 usb_interrupt_Mask;
++	u32 usb_interrupt_Origan;
++
++	DBG_FUNCC("+vUsbHandler(dev->va_base)\n");
++	DBG_CTRLL("usb_interrupt_level1:0x%x\n", dev->usb_interrupt_level1);
++
++	//----- Group Byte 2 ---------
++	if (dev->usb_interrupt_level1 & BIT2) {
++		usb_interrupt_Origan = mUsbIntSrc2Rd(dev->va_base);
++		usb_interrupt_Mask = mUsbIntSrc2MaskRd(dev->va_base);
++		usb_interrupt_level2 =
++		    usb_interrupt_Origan & ~usb_interrupt_Mask;
++		DBG_CTRLL("usb_interrupt_Origan:0x%x\n", usb_interrupt_Origan);
++		DBG_CTRLL("usb_interrupt_Mask:0x%x\n", usb_interrupt_Mask);
++		DBG_CTRLL("usb_interrupt_level2:0x%x\n", usb_interrupt_level2);
++
++		if (usb_interrupt_level2 & BIT0)
++			vUsb_rst(dev);
++		if (usb_interrupt_level2 & BIT1)
++			vUsb_suspend(dev);
++		if (usb_interrupt_level2 & BIT2)
++			vUsb_resm(dev);
++		if (usb_interrupt_level2 & BIT3) {
++			mUsbIntIsoSeqErrClr(dev->va_base);
++			printk("??? ISO sequence error...\n");
++		}
++		if (usb_interrupt_level2 & BIT4) {
++			mUsbIntIsoSeqAbortClr(dev->va_base);
++			printk("??? ISO sequence error...\n");
++		}
++		if (usb_interrupt_level2 & BIT5) {
++			mUsbIntTX0ByteClr(dev->va_base);
++			mUsbIntTX0ByteSetClr(dev->va_base,0x9);	// Clear all zero-legnth
++		}
++
++		if (usb_interrupt_level2 & BIT6)
++			mUsbIntRX0ByteClr(dev->va_base);
++
++		if (usb_interrupt_level2 & BIT7) {
++			mUsbIntDmaFinishClr(dev->va_base);
++			dma_advance(dev, &(dev->ep[dev->EPUseDMA]));
++		}
++		if (usb_interrupt_level2 & BIT8) {
++			mUsbIntDmaErrClr(dev->va_base);
++			printk("??? DMA error Interrupt \n");
++		}
++	}
++	//----- Group Byte 0 ---------
++	if (dev->usb_interrupt_level1 & BIT0) {
++		usb_interrupt_Origan = mUsbIntSrc0Rd(dev->va_base);
++		usb_interrupt_Mask = mUsbIntSrc0MaskRd(dev->va_base);
++		usb_interrupt_level2 =
++		    usb_interrupt_Origan & ~usb_interrupt_Mask;
++
++		DBG_CTRLL("IntSCR0:0x%x\n", usb_interrupt_level2);
++		dev->ep[0].irqs++;
++		//        Stop APB DMA if DMA is still running
++		//        record buffer counter, and clear buffer. Later
++		//        will re-input data use DMA.
++		if (usb_interrupt_level2 & BIT0) {
++            if (dev->EPUseDMA != DMA_CHANEL_FREE) {
++                struct FTC_request *req;
++                struct FTC_ep *ep;
++
++                if (dev->EPUseDMA == 1) {
++                    mUsbDmaAbort(dev->va_base);
++                    while (mUsbDmaConfigRd(dev->va_base) & BIT0)
++                        ;
++
++                    mUsbIntDmaErrDis(dev->va_base);
++                    mUsbIntDmaFinishDis(dev->va_base);
++                    mUsbDMA2FIFOSel(dev->va_base,FOTG200_DMA2FIFO_Non);
++                    dev->EPUseDMA = DMA_CHANEL_FREE;
++                } else if (dev->EPUseDMA == 2) {
++                    // abort ep2's request first
++                    ep = &(dev->ep[dev->EPUseDMA]);
++                    while (!list_empty(&ep->queue))
++                    {
++                        req = list_entry(ep->queue.next, struct FTC_request, queue);
++                        if (req->req.actual && (req->req.actual < req->req.length)) {
++                            done(ep, req, 0);
++                            //done(ep, req, -ESHUTDOWN);
++                        } else {
++                            break;
++                        }
++                    }
++
++                    mUsbIntDmaErrDis(dev->va_base);
++                    mUsbIntDmaFinishDis(dev->va_base);
++                    mUsbDMA2FIFOSel(dev->va_base,FOTG200_DMA2FIFO_Non);
++                    dev->EPUseDMA = DMA_CHANEL_FREE;
++                }
++            }
++
++			DBG_CTRLL("USB ep0 Setup\n");
++            mUsbIntFIFO0_3OUTDis(dev->va_base);
++            mUsbIntFIFO0_3INDis(dev->va_base);
++            vUsb_ep0setup(dev);
++		} else if (usb_interrupt_level2 & BIT3) {
++			DBG_CTRLL("USB ep0 end\n");
++			vUsb_ep0end(dev);
++		}
++
++		if (usb_interrupt_level2 & BIT1) {
++			DBG_CTRLL("USB ep0 TX\n");
++            cx_in_int_assert = 1;
++            dma_advance(dev, &(dev->ep[0]));
++		}
++
++		if (usb_interrupt_level2 & BIT2) {
++            struct FTC_ep *ep = &(dev->ep[0]);
++            struct FTC_request *req;
++
++			DBG_CTRLL("USB ep0 RX\n");
++            cx_out_int_assert = 1;
++            if (list_empty(&ep->queue)) { // only happened at PTP function enabled
++//                printk("Error %s ==> ep0's LIST(0x%p) is empty in cx out\n", __func__, &ep->queue);
++                mUsbIntEP0OutDis(dev->va_base);
++            } else {
++                req = list_entry(ep->queue.next, struct FTC_request, queue);
++                if (req->req.actual)
++                    dma_advance(dev, &(dev->ep[0]));
++                else
++                    start_dma(ep, req);
++            }
++		}
++
++		if (usb_interrupt_level2 & BIT4) {
++			uwarn(dev, "USB ep0 fail\n");
++			vUsb_ep0fail(dev);
++		}
++
++		if (usb_interrupt_level2 & BIT5) {
++			mUsbIntEP0AbortClr(dev->va_base);
++			printk("??? Command Abort Interrupt ...\n");
++		}
++	}
++	//----- Group Byte 1 ---------
++	if (dev->usb_interrupt_level1 & BIT1) {
++		usb_interrupt_Origan = mUsbIntSrc1Rd(dev->va_base);
++		usb_interrupt_Mask = mUsbIntSrc1MaskRd(dev->va_base);
++		usb_interrupt_level2 =
++		    usb_interrupt_Origan & (~usb_interrupt_Mask);
++
++		DBG_CTRLL("(IntSCR1:0x%x)(Mask1:0x%x)(usb_interrupt_level2=0x%x)\n",
++		     usb_interrupt_Origan, mUsbIntSrc1MaskRd(dev->va_base),
++		     usb_interrupt_level2);
++
++		// use FIFO1 for ep2( bulk out)
++		if (usb_interrupt_level2 & BIT3)	// short packet
++			ep_isr(dev, 2);
++		else if (usb_interrupt_level2 & BIT2)	// full packet
++			ep_isr(dev, 2);
++
++		// use FIFO0 for ep1( bulk in)
++		if (usb_interrupt_level2 & BIT16)
++			ep_isr(dev, 1);
++
++		// use FIFO3 for ep4( Interrupt out)
++		if (usb_interrupt_level2 & BIT7)	// short packet
++			ep_isr(dev, 4);
++		else if (usb_interrupt_level2 & BIT6)	// full packet
++			ep_isr(dev, 4);
++
++		// use FIFO2 for ep3( Interrupt in)
++		if (usb_interrupt_level2 & BIT18)
++			ep_isr(dev, 3);
++	}
++}
+diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
+index a8855d0b..41da1495 100644
+--- a/drivers/usb/gadget/gadget_chips.h
++++ b/drivers/usb/gadget/gadget_chips.h
+@@ -50,6 +50,9 @@
+ #define gadget_is_s3c2410(g)		(!strcmp("s3c2410_udc", (g)->name))
+ #define gadget_is_s3c_hsotg(g)		(!strcmp("s3c-hsotg", (g)->name))
+ #define gadget_is_s3c_hsudc(g)		(!strcmp("s3c-hsudc", (g)->name))
++#define gadget_is_fotg(g)		(!strcmp("fotg_udc", (g)->name))
++#define gadget_is_fusb(g)		(!strcmp("fusb_udc", (g)->name))
++#define gadget_is_fotg2xx(g)		(!strcmp("fotg2xx_udc", (g)->name))
+ 
+ /**
+  * usb_gadget_controller_number - support bcdDevice id convention
+@@ -118,6 +121,14 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
+ 		return 0x31;
+ 	else if (gadget_is_dwc3(gadget))
+ 		return 0x32;
++#if defined(CONFIG_GM_FOTG2XX)
++	else if (gadget_is_fusb(gadget))
++		return 0x33;
++	else if (gadget_is_fotg(gadget))
++		return 0x34;
++	else if (gadget_is_fotg2xx(gadget))
++		return 0x35;
++#endif
+ 
+ 	return -ENOENT;
+ }
+diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
+index 85ea14e2..5e6d7873 100644
+--- a/drivers/usb/gadget/storage_common.c
++++ b/drivers/usb/gadget/storage_common.c
+@@ -61,8 +61,13 @@
+  * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+  * Instead:  allocate your own, using normal USB-IF procedures.
+  */
++#if defined(CONFIG_GM_FOTG2XX)
++#define FSG_VENDOR_ID	0x2310	/* Faraday, GM */
++#define FSG_PRODUCT_ID	0x5678	/* Linux-USB File-backed Storage Gadget */
++#else
+ #define FSG_VENDOR_ID	0x0525	/* NetChip */
+ #define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
++#endif
+ 
+ 
+ /*-------------------------------------------------------------------------*/
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index 353cdd48..00f6ea92 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -59,9 +59,93 @@ config USB_EHCI_HCD
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called ehci-hcd.
+ 
++config GM_FOTG2XX
++	bool "GM USB On-The-Go EHCI HCD(USB2.0) support"
++	depends on USB && USB_ARCH_HAS_EHCI && USB_EHCI_HCD
++	select WIRELESS_EXT
++	select WEXT_PRIV
++	---help---
++	  The USB HCD Driver of GM FOTG2XX, USB OTG IP
++	  is designed to meet USB2.0 EHCI specification with
++	  minor modification, Read OTG2XX data sheet for more details.
++
++config GM_FOTG2XX_PHY_TEST
++        bool "Enable FOTG210 phy test on GM USB OTG2XX"
++        depends on GM_FOTG2XX
++        default n
++        ---help---
++          Enable otg phy test on FOTG210
++
++config GM_FOTG2XX_EYE_DIAGRAM
++        bool "Enable eye diagram test on GM USB OTG2XX"
++        depends on GM_FOTG2XX_PHY_TEST
++        default n
++        ---help---
++          Enable eye diagram test on FOTG210
++
++config GM_FOTG2XX_J_STATE
++        bool "Enable J-state test on GM USB OTG2XX"
++        depends on GM_FOTG2XX_PHY_TEST
++        default n
++        ---help---
++          Enable J-state test on FOTG210
++
++config GM_FOTG2XX_K_STATE
++        bool "Enable K-state test on GM USB OTG2XX"
++        depends on GM_FOTG2XX_PHY_TEST
++        default n
++        ---help---
++          Enable K-state test on FOTG210
++
++config GM_FOTG2XX_SE0_NAK
++        bool "Enable SE0_NAK test on GM USB OTG2XX"
++        depends on GM_FOTG2XX_PHY_TEST
++        default n
++        ---help---
++          Enable SE0_NAK test on FOTG210
++
++config GM_FOTG2XX_INFO
++	bool "Provide FOTG2XX information while running"
++	depends on GM_FOTG2XX
++	default n
++	---help---
++	  Dump some important information while FOTG2XX running
++
++config GM_FOTG2XX_LOW_TIMING
++	bool "Set longer EOF1 Time on FPGA stage"
++	depends on GM_FOTG2XX
++	default n
++	---help---
++	  Set EOF1_time on Misc register (0x40) longer on FPGA to avoid USB halt
++	  This will get poor performance
++
++config GM_FUSBH200
++	tristate "GM USB Host EHCI(USB2.0) support"
++	depends on USB && USB_ARCH_HAS_EHCI
++	depends on PLATFORM_GM8181
++	---help---
++	  The USB HCD Driver of GM FUSBH200, USB Host IP
++	  is designed to meet USB2.0 EHCI specification with
++	  minor modification, Read FUSBH200 data sheet for more details.
++
++config GM_FUSBH200_INFO
++	bool "Provide FUSBH200 information while running"
++	depends on GM_FUSBH200
++	default n
++	---help---
++	  Dump some important information while FUSBH200 running
++
++config GM_FUSBH200_LOW_TIMING
++	bool "Set longer EOF1 Time on FPGA stage"
++	depends on GM_FUSBH200
++	default n
++	---help---
++	  Set EOF1_time on Misc register (0x34) longer on FPGA to avoid USB halt
++	  This will get poor performance
++
+ config USB_EHCI_ROOT_HUB_TT
+ 	bool "Root Hub Transaction Translators"
+-	depends on USB_EHCI_HCD
++	depends on USB_EHCI_HCD || GM_FUSBH200 || GM_FOTG2XX
+ 	---help---
+ 	  Some EHCI chips have vendor-specific extensions to integrate
+ 	  transaction translators, so that no OHCI or UHCI companion
+@@ -73,7 +157,7 @@ config USB_EHCI_ROOT_HUB_TT
+ 
+ config USB_EHCI_TT_NEWSCHED
+ 	bool "Improved Transaction Translator scheduling"
+-	depends on USB_EHCI_HCD
++	depends on USB_EHCI_HCD || GM_FUSBH200 || GM_FOTG2XX
+ 	default y
+ 	---help---
+ 	  This changes the periodic scheduling code to fill more of the low
+@@ -492,7 +576,7 @@ config USB_SL811_HCD
+ 	help
+ 	  The SL811HS is a single-port USB controller that supports either
+ 	  host side or peripheral side roles.  Enable this option if your
+-	  board has this chip, and you want to use it as a host controller. 
++	  board has this chip, and you want to use it as a host controller.
+ 	  If unsure, say N.
+ 
+ 	  To compile this driver as a module, choose M here: the
+diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
+index 7ca290fc..638d9e79 100644
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -19,7 +19,10 @@ obj-$(CONFIG_USB_WHCI_HCD)	+= whci/
+ 
+ obj-$(CONFIG_PCI)		+= pci-quirks.o
+ 
+-obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o
++#Host driver of CTD's version
++#obj-$(CONFIG_GM_FOTG2XX)	+= fotg2xx_opt.o fotg210-hcd.o
++#obj-$(CONFIG_GM_FOTG2XX)	+= fotg2xx_opt.o
++obj-$(CONFIG_USB_EHCI_HCD)	+= fotg2xx_opt.o ehci-hcd.o
+ obj-$(CONFIG_USB_OXU210HP_HCD)	+= oxu210hp-hcd.o
+ obj-$(CONFIG_USB_ISP116X_HCD)	+= isp116x-hcd.o
+ obj-$(CONFIG_USB_ISP1362_HCD)	+= isp1362-hcd.o
+diff --git a/drivers/usb/host/ehci-fotg2xx.c b/drivers/usb/host/ehci-fotg2xx.c
+new file mode 100644
+index 00000000..6302610c
+--- /dev/null
++++ b/drivers/usb/host/ehci-fotg2xx.c
+@@ -0,0 +1,308 @@
++/*
++ * (C) Copyright David Brownell 2000-2002
++ *
++ * 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.
++ */
++
++#ifdef CONFIG_USB_DEBUG
++#define DEBUG
++#else
++#undef DEBUG
++#endif
++
++#include "fotg2xx-config.h"
++static struct usb_hcd  *fotg2xx_hcd[FOTG_DEV_NR];
++
++/*
++ * hc states include: unknown, halted, ready, running
++ * transitional states are messy just now
++ * trying to avoid "running" unless urbs are active
++ * a "ready" hc can be finishing prefetched work
++ */
++
++
++static int FTC_ehci_init(struct usb_hcd *hcd);
++
++struct hc_driver ehci_driver = {
++	.description =		hcd_name,
++	.product_desc =		"FOTG2XX HOST",
++	.hcd_priv_size =	sizeof(struct ehci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq =			ehci_irq,
++	.flags =		HCD_MEMORY | HCD_USB2,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.reset =		FTC_ehci_init,
++	.start =		ehci_run,
++	.stop =			ehci_stop,
++	.shutdown =		ehci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue =		ehci_urb_enqueue,
++	.urb_dequeue =		ehci_urb_dequeue,
++	.endpoint_disable =	ehci_endpoint_disable,
++	.endpoint_reset =	ehci_endpoint_reset,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number =	ehci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data =	ehci_hub_status_data,
++	.hub_control =		ehci_hub_control,
++#if defined(CONFIG_PM)
++	.bus_suspend =		ehci_bus_suspend,
++	.bus_resume =		ehci_bus_resume,
++#endif
++	.relinquish_port =	ehci_relinquish_port,
++	.port_handed_over =	ehci_port_handed_over,
++	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
++};
++
++#if 0
++/* FOTG2XX Controll Registers Setup When Interrupt  occured  */
++void fotg_ehci_irq_macro(void)
++{
++	if ( mwOTG20_Interrupt_Status_HOST_Rd()){
++		mwOTG20_Interrupt_Status_HOST_Clr();
++	}
++}
++#endif
++
++static int FTC_ehci_init(struct usb_hcd *hcd)
++{
++	int result;
++	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++	fotg2xx_dbg("call FTC_ehci_init.......ehci = %x\n", (u32)ehci);
++	ehci->big_endian_mmio = 0;
++
++	ehci->caps = hcd->regs;
++	ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
++
++	dbg_hcs_params(ehci, "reset");
++	dbg_hcc_params(ehci, "reset");
++
++	/* cache this readonly data; minimize chip reads */
++	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++	result = ehci_halt(ehci);
++	if (result)
++		return result;
++
++	/* data structure init */
++	result = ehci_init(hcd);
++	if (result)
++		return result;
++
++	hcd->has_tt = 1; //tt means transaction-translator
++
++	ehci->sbrn = 0x20;
++
++	ehci_reset(ehci);
++
++	ehci_port_power(ehci, 0);
++
++	return result;
++}
++
++extern void init_FOTG2XX_Dev(struct usb_hcd *hcd);
++extern void exit_FOTG2XX_Dev(struct usb_hcd *hcd);
++extern int usb_get_pmu_fd(void);
++extern int fotg200_otgd_init(struct platform_device *dev,struct usb_bus *host,struct usb_gadget *gadget);
++extern int fotg200_init(struct device *dev,struct usb_bus *host,struct usb_gadget *gadget);
++
++static void fotg2xx_hw_init(struct usb_hcd *hcd)
++{
++	init_FOTG2XX_Dev(hcd);
++
++#ifdef CONFIG_GM_FOTG2XX_LOW_TIMING
++	//John add timing adjustment code for fast plug/unplug issue, should set
++	//when system boot up
++	{
++		u32 temp;
++
++		printk("Note : SET lower timing on FPGA, will get low performance\n");
++		//Set Timing parameter when system bus too low
++		//special on FPGA, Should set as default value (0x01) in real chip
++		//With this message, you should check your system bus performance
++		temp = readl ((u32)hcd->regs | 0x40);
++		writel (temp | 0x0d,  (u32)hcd->regs | 0x40 );
++		temp = readl ((u32)hcd->regs | 0x40);
++		printk("Timing on misc(0x%08x) = 0x%x\n", (u32)hcd->regs | 0x40, temp);
++	}
++#endif
++}
++
++static void fotg2xx_hw_deinit(struct usb_hcd *hcd)
++{
++	exit_FOTG2XX_Dev(hcd);
++}
++
++/**
++ * usb_hcd_fotg2xx_probe - initialize HCDs
++ * @pdev: USB Host Controller being probed
++ * Context: !in_interrupt()
++ *
++ * Allocates basic PCI resources for this USB host controller, and
++ * then invokes the start() method for the HCD associated with it
++ * through the hotplug entry's driver_data.
++ *
++ * Store this function in the HCD's struct pci_driver as probe().
++ */
++int usb_hcd_fotg2xx_probe (struct platform_device *pdev)
++{
++	struct hc_driver	*driver;
++	struct usb_hcd		*hcd;
++	struct resource		*res;
++	int			irq;
++	int			retval;
++
++	fotg2xx_dbg("usb_hcd_fotg2xx_probe: %x \n",(u32)pdev);
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	driver = &ehci_driver;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev,
++			"Found HC with no physical mem. Check %s setup!\n",
++			dev_name(&pdev->dev));
++		return -ENODEV;
++	}
++	irq = platform_get_irq(pdev, 0);
++
++	pdev->dev.power.power_state = PMSG_ON;
++
++    fotg2xx_hcd[pdev->id] = hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
++	if (!hcd) {
++		retval = -ENOMEM;
++		goto fail_create_hcd;
++	}
++
++	if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI
++
++		hcd->rsrc_start = res->start;
++		hcd->rsrc_len = resource_size(res);
++
++		if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
++					driver->description)) {
++			dev_dbg(&pdev->dev, "controller already in use\n");
++			retval = -EBUSY;
++			goto fail_request_resource;
++		}
++		hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
++		if (hcd->regs == NULL) {
++			dev_dbg(&pdev->dev, "error mapping memory\n");
++			retval = -EFAULT;
++			goto fail_ioremap;
++		}
++
++	} else { 				// UHCI
++		printk("Warning usb_hcd_fotg2xx_probe --- FOTG2XX Not support UHCI Flags \n");
++		retval = -ENOMEM;
++		goto fail_create_hcd;
++	}
++
++	hcd->product_desc = "FOTG2XX";
++
++	retval = fotg200_otgd_init(pdev, &hcd->self, NULL);
++
++	fotg2xx_hw_init(hcd);
++
++	retval = usb_add_hcd (hcd, irq, IRQF_SHARED);
++	fotg2xx_dbg("usb_hcd_fotg2xx_probe: %x \n",retval);
++
++	if (retval != 0)
++		goto fail_add_hcd;
++
++	retval = fotg200_init(&(pdev->dev), &hcd->self, NULL);
++
++	return retval;
++
++fail_add_hcd:
++	iounmap (hcd->regs);
++fail_ioremap:
++	release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
++fail_request_resource:
++	usb_put_hcd (hcd);
++fail_create_hcd:
++	dev_err (&(pdev->dev), "init %s fail, %d\n", pdev->name, retval);
++	return retval;
++}
++
++/**
++ * usb_hcd_fotg2xx_remove - shutdown processing for PCI-based HCDs
++ * @dev: USB Host Controller being removed
++ * Context: !in_interrupt()
++ *
++ * Reverses the effect of usb_hcd_fotg2xx_probe(), first invoking
++ * the HCD's stop() method.  It is always called from a thread
++ * context, normally "rmmod", "apmd", or something similar.
++ *
++ * Store this function in the HCD's struct pci_driver as remove().
++ */
++int usb_hcd_fotg2xx_remove (struct platform_device *pdev)
++{
++	struct usb_hcd		*hcd;
++	struct resource		*res;
++
++    hcd = fotg2xx_hcd[pdev->id];
++	if (!hcd)
++		return 0;
++
++	fotg2xx_hw_deinit(hcd);
++
++	usb_remove_hcd (hcd);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev,
++			"Found HC with no physical mem. Check %s setup!\n",
++			dev_name(&pdev->dev));
++		return -ENODEV;
++	}
++
++	if (hcd->driver->flags & HCD_MEMORY) {
++		iounmap (hcd->regs);
++		release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
++	}
++	else {
++		release_region (hcd->rsrc_start, hcd->rsrc_len);
++	}
++	usb_put_hcd (hcd);
++	return 0;
++}
++
++static struct platform_driver fotg210_ehci_driver = {
++	.probe = usb_hcd_fotg2xx_probe,
++	.remove = usb_hcd_fotg2xx_remove,
++	.driver = {
++		.name = "fotg210",
++		.owner = THIS_MODULE,
++	},
++};
+diff --git a/drivers/usb/host/ehci-fusbh200.c b/drivers/usb/host/ehci-fusbh200.c
+new file mode 100644
+index 00000000..38e48d5e
+--- /dev/null
++++ b/drivers/usb/host/ehci-fusbh200.c
+@@ -0,0 +1,379 @@
++/*
++ * (C) Copyright David Brownell 2000-2002
++ *
++ * 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.
++ */
++
++#ifdef CONFIG_USB_DEBUG
++#define DEBUG
++#else
++#undef DEBUG
++#endif
++
++static struct usb_hcd  *fusbh200_hcd;
++static int usbh_pmu_fd = -1;
++
++#define FUSBH200PHY (BIT23|BIT24|BIT25)
++static pmuReg_t regUSBHArray[] = {
++	/* reg_off,bit_masks,lock_bits,init_val,init_mask */
++#if defined(CONFIG_PLATFORM_GM8185_v2)
++	{0x38, BIT2, BIT2, 0, BIT2},
++#elif defined(CONFIG_PLATFORM_GM8181)
++	{0x38, BIT17, BIT17, 0, BIT17},
++	{0x6C, FUSBH200PHY, FUSBH200PHY, 0, FUSBH200PHY},
++	{0x80, ~0x0, ~0x0, 0, 0},
++#endif
++};
++static pmuRegInfo_t usbh_clk_info = {
++	"fusbh200_clk",
++	ARRAY_SIZE(regUSBHArray),
++	ATTR_TYPE_NONE,             /* no clock source */
++	regUSBHArray
++};
++
++static int ftc_ehci_init(struct usb_hcd *hcd);
++
++struct hc_driver fusbh200_ehci_driver = {
++	.description =		hcd_name,
++	.product_desc =		"FUSBH200 HOST",
++	.hcd_priv_size =	sizeof(struct ehci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq =			ehci_irq,
++	.flags =		HCD_MEMORY | HCD_USB2,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.reset =		ftc_ehci_init,
++	.start =		ehci_run,
++	.stop =			ehci_stop,
++	.shutdown =     ehci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue =		ehci_urb_enqueue,
++	.urb_dequeue =		ehci_urb_dequeue,
++	.endpoint_disable =	ehci_endpoint_disable,
++	.endpoint_reset =	ehci_endpoint_reset,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number =	ehci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data =	ehci_hub_status_data,
++	.hub_control =		ehci_hub_control,
++#if defined(CONFIG_PM)
++	.bus_suspend =		ehci_bus_suspend,
++	.bus_resume =		ehci_bus_resume,
++#endif
++	.relinquish_port = ehci_relinquish_port,
++	.port_handed_over = ehci_port_handed_over,
++	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
++};
++
++#if 0
++void ehci_reset_h200_PHY(void)
++{
++#ifndef REMOVE_COVERHW
++	//Reset PHY
++	mwH20_Control_Phy_Reset_Set();
++	udelay(1000);//1000 About 0.2ms
++	mwH20_Control_Phy_Reset_Clr();
++#endif
++}
++#endif
++
++static int ftc_ehci_init(struct usb_hcd *hcd)
++{
++	int result;
++	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++
++	fotg2xx_dbg("call ftc_ehci_init.......ehci = %x\n", (u32)ehci);
++	ehci->big_endian_mmio = 0;
++
++	ehci->caps = hcd->regs;
++	ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
++
++	dbg_hcs_params(ehci, "reset");
++	dbg_hcc_params(ehci, "reset");
++
++	/* cache this readonly data; minimize chip reads */
++	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++	result = ehci_halt(ehci);
++	if (result)
++		return result;
++
++	/* data structure init */
++	result = ehci_init(hcd);
++	if (result)
++		return result;
++
++	hcd->has_tt=1; //tt means transaction-translator
++
++	ehci->sbrn = 0x20;
++
++	ehci_reset(ehci);
++
++	ehci_port_power(ehci, 0);
++
++	return result;
++}
++
++static void init_FUSBH200_Dev(struct usb_hcd *hcd)
++{
++#if defined(CONFIG_PLATFORM_GM8185_v2)
++	ftpmu010_write_reg(usbh_pmu_fd, 0x38, 0, BIT2);
++#elif defined(CONFIG_PLATFORM_GM8181)
++	if ((ftpmu010_get_attr(ATTR_TYPE_PMUVER) & 0xF0) == 0x20) { /* 8181T/8186 */
++		ftpmu010_write_reg(usbh_pmu_fd, 0x6C, BIT1<<23, BIT1<<23);
++	}
++	ftpmu010_write_reg(usbh_pmu_fd, 0x38, 0, BIT17);
++	mdelay(10); // waiting for PHY clock be stable, while clock source changed from externel to internel, at lease 5ms
++	if ((ftpmu010_get_attr(ATTR_TYPE_PMUVER) & 0xF0) == 0x20) { /* 8181T/8186 */
++		unsigned int tmp;
++
++		tmp = ftpmu010_read_reg(0x80);
++		tmp &= ~0x1F0;
++		tmp |= 0x3 << 6; /// IREF_ST[2:0], default:0x4
++		tmp |= 0x1 << 4; /// PCR[1:0], default:0x1
++		ftpmu010_write_reg(usbh_pmu_fd, 0x80, tmp, tmp);
++
++		mwH20Bit_Clr(hcd->regs,0x34,BIT6); // place PHY in suspend mode
++		mdelay(10);
++		mwH20Bit_Set(hcd->regs,0x34,BIT6);
++		mdelay(10);
++	}
++#endif
++#ifdef CONFIG_711MA_PHY
++	//Set cover bit to cover 711MA PHY full speed reset issue
++	mwH20_Control_COVER_FS_PHY_Reset_Set(hcd->regs);
++#endif
++	//Set OTG200 interrupt to high active
++	mwH20_Interrupt_OutPut_High_Set(hcd->regs);  //For A320
++	//Important: If AHB clock is >=15Mhz and <= 30MHz, please remark this line (Enable half speed)).
++	//IF > 30Hz, Disable half speed
++	mwH20_Control_VBUS_OFF_Clr(hcd->regs);
++#ifdef EnableHalfSpeed
++	mwH20_Control_HALFSPEEDEnable_Set(hcd->regs);
++#else /* EnableHalfSpeed */
++	mwH20_Control_HALFSPEEDEnable_Clr(hcd->regs);
++#endif /* EnableHalfSpeed */
++
++	mwH20_Control_ForceHighSpeed_Clr(hcd->regs);
++	mwH20_Control_ForceFullSpeed_Clr(hcd->regs);
++#if 0 // debug for force usbh phy speed
++	mwH20_Control_ForceFullSpeed_Set(hcd->regs); // force to full-speed (do not ack to device's KJ pattern)
++	//mwH20_Control_ForceHighSpeed_Set(hcd->regs); // force to high-speed
++	if (mwHost20Bit_Rd(0x40, BIT7))
++		printk("!!!! Force Phy to Full-Speed !!!!\n");
++	else if (mwHost20Bit_Rd(0x40, BIT6))
++		printk("!!!! Force Phy to High-Speed !!!!\n");
++#endif
++	mwH20_Int_BM_OVC_En(hcd->regs);
++	mwH20_Int_BM_VBUS_ERR_En(hcd->regs);
++}
++
++void fusbh200_hw_init(struct usb_hcd *hcd)
++{
++
++	if ((usbh_pmu_fd = ftpmu010_register_reg(&usbh_clk_info)) < 0)
++		printk(KERN_ERR "%s: Register USB to PMU failed\n", __func__);
++#if defined(CONFIG_PLATFORM_GM8181) && defined(CONFIG_PCI)
++#include <linux/pci.h>
++	// only BGA684 package has PCI pin out
++	// if PCI device mode enabled, no more init FUSBH200 doing, just exit
++	if (((ftpmu010_read_reg(0x0)>>5) & 0x07) == 0) {
++		if ((* (volatile unsigned int *) (PCIC_FTPCI100_VA_BASE + 0xA0) & BIT4) == 0)
++			return -1;
++	}
++#endif
++	init_FUSBH200_Dev(hcd);
++#ifdef CONFIG_GM_FUSBH200_LOW_TIMING
++	//John add timing adjustment code for fast plug/unplug issue, should set
++	//when system boot up
++	{
++		u32 temp;
++
++		printk("Note : SET lower timing on FPGA, will get low performance\n");
++		//Set Timing parameter when system bus too low
++		//special on FPGA, Should set as default value (0x01) in real chip
++		//With this message, you should check your system bus performance
++		temp = readl ((u32)hcd->regs | 0x34);
++		writel (temp | 0x0d,  (u32)hcd->regs | 0x34 );
++		temp = readl ((u32)hcd->regs | 0x34);
++		printk("Timing on misc(0x%08x) = 0x%x\n",(u32)hcd->regs | 0x34, temp);
++	}
++#endif
++}
++
++void fusbh200_hw_deinit(void)
++{
++#ifdef CONFIG_PLATFORM_GM8185_v2
++	ftpmu010_write_reg(usbh_pmu_fd, 0x38, BIT2, BIT2);
++#elif defined(CONFIG_PLATFORM_GM8181)
++	ftpmu010_write_reg(usbh_pmu_fd, 0x38, BIT17, BIT17);
++#endif
++	if (ftpmu010_deregister_reg(usbh_pmu_fd) < 0)
++		printk(KERN_ERR "%s: Unregister USB from PMU Failed\n", __func__);
++}
++
++/**
++ * usb_hcd_fusbh200_probe - initialize HCDs
++ * @pdev: USB Host Controller being probed
++ * Context: !in_interrupt()
++ *
++ * Allocates basic PCI resources for this USB host controller, and
++ * then invokes the start() method for the HCD associated with it
++ * through the hotplug entry's driver_data.
++ *
++ * Store this function in the HCD's struct pci_driver as probe().
++ */
++int usb_hcd_fusbh200_probe (struct platform_device *pdev)
++{
++	struct hc_driver	*driver;
++	struct usb_hcd		*hcd;
++	struct resource		*res;
++	int			irq;
++	int			retval;
++
++	fotg2xx_dbg("usb_hcd_fotg2xx_probe: %x \n",(u32)pdev);
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	driver = &fusbh200_ehci_driver;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev,
++			"Found HC with no physical mem. Check %s setup!\n",
++			dev_name(&pdev->dev));
++		return -ENODEV;
++	}
++	irq = platform_get_irq(pdev, 0);
++
++	pdev->dev.power.power_state = PMSG_ON;
++
++	fusbh200_hcd = hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
++	if (!hcd) {
++		retval = -ENOMEM;
++		goto fail_create_hcd;
++	}
++
++	if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI
++
++		hcd->rsrc_start = res->start;
++		hcd->rsrc_len = res->end - res->start + 1;
++
++		if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
++					driver->description)) {
++			dev_dbg(&pdev->dev, "controller already in use\n");
++			retval = -EBUSY;
++			goto fail_request_resource;
++		}
++		hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
++		if (hcd->regs == NULL) {
++			dev_dbg(&pdev->dev, "error mapping memory\n");
++			retval = -EFAULT;
++			goto fail_ioremap;
++		}
++
++	} else { 				// UHCI
++		printk("Warning usb_hcd_fotg2xx_probe --- FOTG2XX Not support UHCI Flags \n");
++		retval = -ENOMEM;
++		goto fail_create_hcd;
++	}
++
++	hcd->product_desc = "FUSBH200";
++
++	fusbh200_hw_init(hcd);
++
++	retval = usb_add_hcd (hcd, irq, IRQF_SHARED);
++	fotg2xx_dbg("usb_hcd_fotg2xx_probe: %x \n",retval);
++
++	if (retval != 0)
++		goto fail_add_hcd;
++	return retval;
++
++fail_add_hcd:
++	iounmap (hcd->regs);
++fail_ioremap:
++	release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
++fail_request_resource:
++	usb_put_hcd (hcd);
++fail_create_hcd:
++	dev_err (&(pdev->dev), "init %s fail, %d\n", pdev->name, retval);
++	return retval;
++}
++
++/**
++ * usb_hcd_fusbh200_remove - shutdown processing for PCI-based HCDs
++ * @pdev: USB Host Controller being removed
++ * Context: !in_interrupt()
++ *
++ * Reverses the effect of usb_hcd_fusbh200_probe(), first invoking
++ * the HCD's stop() method.  It is always called from a thread
++ * context, normally "rmmod", "apmd", or something similar.
++ *
++ * Store this function in the HCD's struct pci_driver as remove().
++ */
++int usb_hcd_fusbh200_remove (struct platform_device *pdev)
++{
++	struct usb_hcd		*hcd;
++	struct resource		*res;
++
++	fusbh200_hw_deinit();
++
++	hcd = fusbh200_hcd;
++	if (!hcd)
++		return 0;
++
++	usb_remove_hcd (hcd);
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(&pdev->dev,
++			"Found HC with no physical mem. Check %s setup!\n",
++			dev_name(&pdev->dev));
++		return -ENODEV;
++	}
++
++	if (hcd->driver->flags & HCD_MEMORY) {
++		iounmap (hcd->regs);
++		release_mem_region (hcd->rsrc_start, hcd->rsrc_len);
++	}
++	else {
++		release_region (hcd->rsrc_start, hcd->rsrc_len);
++	}
++	usb_put_hcd (hcd);
++	return 0;
++}
++
++static struct platform_driver fusbh200_plat_driver = {
++	.probe = usb_hcd_fusbh200_probe,
++	.remove = usb_hcd_fusbh200_remove,
++	.driver = {
++		.name = "GM_fusbh200",
++	},
++};
+diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
+index a007a9fe..c3c10463 100644
+--- a/drivers/usb/host/ehci-hcd.c
++++ b/drivers/usb/host/ehci-hcd.c
+@@ -52,6 +52,15 @@
+ #include <asm/firmware.h>
+ #endif
+ 
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++#include <linux/platform_device.h>
++#include "fotg2xx_opt-macro.h"
++//#include "../gadget/GM_udc.h"
++#include <mach/ftpmu010.h>
++#include <mach/platform/platform_io.h>
++#include "fotg2xx-config.h"
++#include "fotg2xx-ehci-macro.h"
++#endif
+ /*-------------------------------------------------------------------------*/
+ 
+ /*
+@@ -581,7 +590,15 @@ static void ehci_stop (struct usb_hcd *hcd)
+ 	if (ehci->async)
+ 		ehci_work (ehci);
+ 	spin_unlock_irq (&ehci->lock);
++
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++	if (!hcd->self.is_b_host)
++		ehci_mem_cleanup (ehci);
++	ehci->watchdog.data=0;
++	ehci->iaa_watchdog.data=0;
++#else
+ 	ehci_mem_cleanup (ehci);
++#endif
+ 
+ 	if (ehci->amd_pll_fix == 1)
+ 		usb_amd_dev_put();
+@@ -695,8 +712,13 @@ static int ehci_init(struct usb_hcd *hcd)
+ 		 */
+ 		if (park) {
+ 			park = min(park, (unsigned) 3);
++/*
++ * before FOTG210 v1.15, park mode on cause qTD buffer page number error
++ */
++#if !defined(CONFIG_GM_FOTG2XX)
+ 			temp |= CMD_PARK;
+ 			temp |= park << 8;
++#endif
+ 		}
+ 		ehci_dbg(ehci, "park %d\n", park);
+ 	}
+@@ -760,11 +782,29 @@ static int ehci_run (struct usb_hcd *hcd)
+ #endif
+ 	}
+ 
++#ifdef CONFIG_GM_FOTG2XX
++	// extend EOF 1 timing, if OTG is running on full-speed, and device is connected behind a hub
++	mwOTG20Bit_Set(hcd->regs,0x40,0xc);
++#endif
++#ifdef CONFIG_GM_FUSBH200
++	// extend EOF 1 timing, if OTG is running on full-speed, and device is connected behind a hub
++	mwH20Bit_Set(hcd->regs,0x34,0xc);
++#endif
+ 
+ 	// Philips, Intel, and maybe others need CMD_RUN before the
+ 	// root hub will detect new devices (why?); NEC doesn't
+ 	ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
++
++/*
++ * before FOTG210 v1.15, park mode on cause qTD buffer page number error
++ */
++#if !defined(CONFIG_GM_FOTG2XX)
++	ehci->command |= CMD_PARK | (3<<8);
++#endif
++#if !defined(CONFIG_GM_FUSBH200)
++	/* FOTG200 can't set this bit, but FOTG210 is ok */
+ 	ehci->command |= CMD_RUN;
++#endif
+ 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ 	dbg_cmd (ehci, "init", ehci->command);
+ 
+@@ -786,7 +826,9 @@ static int ehci_run (struct usb_hcd *hcd)
+ 	ehci->rh_state = EHCI_RH_RUNNING;
+ 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+-	msleep(5);
++	// john, cannot busy wait, use short delay
++	//msleep(5);
++	udelay(500);
+ 	up_write(&ehci_cf_port_reset_rwsem);
+ 	ehci->last_periodic_enable = ktime_get_real();
+ 
+@@ -839,18 +881,275 @@ static int __maybe_unused ehci_setup (struct usb_hcd *hcd)
+ 	return 0;
+ }
+ 
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++static void reset_host(struct ehci_hcd *ehci)
++{
++	u32 regcommand, regenable, regstatus;
++	u32 i,temp;
++
++    printk("periodic=%x,%x\n", ehci->periodic_dma,readl(&ehci->regs->frame_list));
++    printk("async=%x,%x\n",ehci->async->qh_dma, readl(&ehci->regs->async_next));
++    printk("command=%x,%x\n",ehci->command, readl(&ehci->regs->command));
++
++	regcommand = readl(&ehci->regs->command);
++    regcommand &= ((0xFF << 16) | (0x3 << 2));
++	regenable = readl(&ehci->regs->intr_enable);
++
++    //set HC_RESET
++	writel(CMD_RESET,&ehci->regs->command);
++	i=0;
++	temp = CMD_RESET;
++	while (((temp & CMD_RESET)) && (i<=1000)) {
++		mdelay(1);
++		i++;
++		temp = readl(&ehci->regs->command);
++	}
++
++    //set port reset
++    writel(PORT_RESET, &ehci->regs->port_status);
++    mdelay(50);
++
++    /* re-init operational registers */
++    writel(ehci->periodic_dma, &ehci->regs->frame_list);
++    writel(ehci->async->qh_dma, &ehci->regs->async_next);
++
++    writel(regcommand, &ehci->regs->command);
++    mdelay(5);
++    writel(regcommand | CMD_RUN,&ehci->regs->command);
++    writel(regenable,&ehci->regs->intr_enable);
++    regstatus = readl(&ehci->regs->port_status);
++    writel(regstatus & ~PORT_RESET,&ehci->regs->port_status);
++}
++
++void ftusb_reset_host(struct usb_hcd *hcd)
++{
++    struct ehci_hcd *ehci = hcd_to_ehci (hcd);
++
++    reset_host(ehci);
++}
++#endif
+ /*-------------------------------------------------------------------------*/
+ 
++/* FOTG210 eye pattern test */
++#if defined(CONFIG_GM_FOTG2XX_PHY_TEST)
++#include "../gadget/fotg2xx-peri-macro.h"
++#define DIRECTION_IN 1
++static void fotg210_write_cx_fifo(struct usb_hcd *hcd, u8 *buf, u16 num)
++{
++	u32 tmp, wDMABuffer;
++
++	if (likely(num != 0)) {
++
++		wDMABuffer = dma_map_single(NULL, buf, num, DMA_TO_DEVICE);
++		mUsbDmaConfig(hcd->regs, num, DIRECTION_IN);
++		mUsbDMA2FIFOSel(hcd->regs,FOTG200_DMA2CxFIFO);
++		mUsbDmaAddr(hcd->regs,wDMABuffer);
++		mUsbDmaStart(hcd->regs);
++		while(1) {
++			tmp = mUsbIntSrc2Rd(hcd->regs);
++			if(tmp & BIT8) {
++				mUsbCxFClr(hcd->regs);
++				mUsbIntDmaErrClr(hcd->regs);
++				printk(KERN_ERR"%s: Cx IN DMA error\n", __func__);
++				break;
++			}
++			if(tmp & BIT7) {
++				mUsbIntDmaFinishClr(hcd->regs);
++				break;
++			}
++			if((tmp & 0x00000007) > 0) {//If (Resume/Suspend/Reset) exit
++				mUsbDMAResetSet(hcd->regs);
++				mUsbCxFClr(hcd->regs);
++				mUsbIntDmaFinishClr(hcd->regs);
++				printk("%s: Cx IN DMA stop because USB Resume/Suspend/Reset\n", __func__);
++				break;
++			}
++		}
++		mUsbDMA2FIFOSel(hcd->regs, FOTG200_DMA2FIFO_Non);
++		dma_unmap_single(NULL, wDMABuffer, num, DMA_TO_DEVICE);
++	}
++}
++
++static void fotg210_eye_diagram_test(struct usb_hcd *hcd)
++{
++	u8 i, tmp[53], *pp;
++
++#define mUsb_mwOTG20_isRun(x) mwOTG20Bit_Rd(x,0x10,BIT0)
++
++	if (mwOTG20_b_conn_Rd(hcd->regs) == 1) {
++		mUsb_mwHost20_PORTSC_PortReset_Set(hcd->regs);
++		mdelay(100);
++		mUsb_mwHost20_PORTSC_PortReset_Clr(hcd->regs);
++
++		/* Check host run/stop and enable/disable it */
++		if (mUsb_mwOTG20_isRun(hcd->regs) == 0) {
++			mwOTG20_start_host(hcd->regs);
++			while(mUsb_mwOTG20_isRun(hcd->regs) == 0);
++		}
++		if (mUsb_mwOTG20_isRun(hcd->regs) > 0) {
++			//Make sure the Async schedule is disbale
++			if (mwOTG20Bit_Rd(hcd->regs,0x10,BIT5) > 0) {
++				mwOTG20Bit_Clr(hcd->regs,0x10,BIT5);
++				while(mwOTG20Bit_Rd(hcd->regs,0x14,BIT15) > 0);
++			}
++
++			mwOTG20_stop_host(hcd->regs);
++			while(mUsb_mwOTG20_isRun(hcd->regs) > 0);
++		}
++
++#if defined(CONFIG_GM_FOTG2XX_EYE_DIAGRAM)
++		printk(KERN_INFO"%s: Transmit Test Packet\n", __func__);
++
++		/* Set Test Packet */
++		mwOTG20Bit_Set(hcd->regs, 0x30, (4<<16));
++
++		pp = tmp;
++		for (i=0; i<9; i++){	// JKJKJKJK x 9
++			(*pp) = (0x00);
++			pp++;
++		}
++
++		for (i=0; i<8; i++){ 	// JJKKJJKK*8, 8*AA
++			(*pp) = (0xAA);
++			pp++;
++		}
++
++		for (i=0; i<8; i++) {	// JJJJKKKK*8, 8*EE
++			(*pp) = (0xEE);
++			pp++;
++		}
++		(*pp) = (0xFE);		// JJJJJJJKKKKKKK *8
++		pp ++;
++
++		for (i=0; i<11; i++) {	// 11*FF
++			(*pp) = (0xFF);
++			pp++;
++		}
++
++		(*pp) = (0x7F);		// JJJJJJJK *8
++		pp++;
++		(*pp) = (0xBF);
++		pp++;
++		(*pp) = (0xDF);
++		pp++;
++		(*pp) = (0xEF);
++		pp++;
++		(*pp) = (0xF7);
++		pp++;
++		(*pp) = (0xFB);
++		pp++;
++		(*pp) = (0xFD);
++		pp++;
++		(*pp) = (0xFC);
++		pp++;
++		(*pp) = (0x7E);		// {JKKKKKKK * 10}, JK
++		pp++;
++		(*pp) = (0xBF);
++		pp++;
++		(*pp) = (0xDF);
++		pp++;
++		(*pp) = (0xEF);
++		pp++;
++		(*pp) = (0xF7);
++		pp++;
++		(*pp) = (0xFB);
++		pp++;
++		(*pp) = (0xFD);
++		pp++;
++		(*pp) = (0x7E);
++		fotg210_write_cx_fifo(hcd, tmp, 53);
++
++		mdelay(2000);
++		/* after filling test packet into FIFO by DMA, set HC_TST_PKDONE to 1 */
++		mwOTG20Bit_Set(hcd->regs, 0x30, BIT20);
++
++		while (1);
++#endif
++#if defined(CONFIG_GM_FOTG2XX_J_STATE)
++		/* Set Test J-state */
++		mwOTG20Bit_Set(hcd->regs, 0x30, (1<<16));
++#endif
++#if defined(CONFIG_GM_FOTG2XX_K_STATE)
++		/* Set Test K-state */
++		mwOTG20Bit_Set(hcd->regs, 0x30, (2<<16));
++#endif
++#if defined(CONFIG_GM_FOTG2XX_SE0_NAK)
++        /* Set Test SE0_NAK */
++        mwOTG20Bit_Set(hcd->regs, 0x30, (3<<16));
++#endif
++	}
++}
++#endif
++
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++extern void set_irq_is_hcd(int val);
++extern int get_irq_is_hcd(void);
++#endif
+ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
+ {
+ 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+ 	u32			status, masked_status, pcd_status = 0, cmd;
+-	int			bh;
++	int			bh = 0;
+ 
+ 	spin_lock (&ehci->lock);
+ 
++#ifdef CONFIG_GM_FUSBH200
++	if (memcmp(hcd->product_desc, H200_NAME, sizeof(H200_NAME)) == 0) {
++		u32 __iomem  *reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBH200_BUS_MONITOR);
++		u32 tmp = ehci_readl(ehci,reg_ptr);
++
++        set_irq_is_hcd(1);
++		if ( tmp & USBH200_BUS_MONITOR_OVC ){
++			printk("Over current!!\n");
++			ehci_writel(ehci,USBH200_BUS_MONITOR_OVC,reg_ptr);
++			reset_host(ehci);
++			spin_unlock(&ehci->lock);
++			return IRQ_HANDLED;
++		}
++		else if ( tmp & USBH200_BUS_MONITOR_VBUS_ERR ){
++			printk("Vbus Error!!\n");
++			ehci_writel(ehci, USBH200_BUS_MONITOR_VBUS_ERR, reg_ptr);
++			reset_host(ehci);
++			spin_unlock(&ehci->lock);
++			return IRQ_HANDLED;
++		}
++	}
++#endif
++
++#ifdef CONFIG_GM_FOTG2XX
++	if (memcmp(hcd->product_desc, OTG2XX_NAME, sizeof(OTG2XX_NAME)) == 0) {
++        set_irq_is_hcd(0);
++		status = ehci_readl(ehci, hcd->regs+0x84);//read interrupt status
++
++		if (!(status & (OTGC_INT_A_TYPE | OTGC_INT_B_TYPE)))
++            set_irq_is_hcd(1);
++
++		if (get_irq_is_hcd())
++			fotg200_handle_irq(hcd->irq);
++
++		status = ehci_readl(ehci, hcd->regs+0xC4) & (~0x04);//enable HC interrupt
++		ehci_writel(ehci, status, hcd->regs+0xC4);
++		status = ehci_readl(ehci, hcd->regs+0x80) & (1<<20);//read role status
++#define OTG_ROLE_HOST 	0
++		if (status != OTG_ROLE_HOST) {
++			spin_unlock(&ehci->lock);
++			if (get_irq_is_hcd())
++				return IRQ_NONE;
++			else
++				return IRQ_HANDLED;
++		} else {
++			fotg200_handle_irq(hcd->irq);
++		}
++	}
++#endif
++
+ 	status = ehci_readl(ehci, &ehci->regs->status);
+ 
++#if defined(CONFIG_GM_FOTG2XX_PHY_TEST)
++    printk("Enter pattern test mode\n");
++    fotg210_eye_diagram_test(hcd);
++#endif
++
+ 	/* e.g. cardbus physical eject */
+ 	if (status == ~(u32) 0) {
+ 		ehci_dbg (ehci, "device removed\n");
+@@ -912,6 +1211,73 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
+ 		if (!(cmd & CMD_RUN))
+ 			usb_hcd_resume_root_hub(hcd);
+ 
++/* Patch from CTD, for port change detect */
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++		if (!(cmd & CMD_RUN)) {
++			u32 temp,i;
++
++			i=0;
++			temp = ehci_readl(ehci, &ehci->regs->status);
++			while ((!(temp & STS_HALT)) && (i<1000)) {
++				udelay(125);
++				i++;
++				temp = ehci_readl(ehci, &ehci->regs->status);
++			}
++
++			if (i<1000) {
++				temp = ehci_readl(ehci, &ehci->regs->command);
++				temp |= CMD_RUN;
++				ehci_writel(ehci, temp, &ehci->regs->command);
++
++				i=0;
++				temp = ehci_readl(ehci, &ehci->regs->status);
++				while ((temp & STS_HALT) && (i<10)) {
++					udelay(125);
++					i++;
++					temp = ehci_readl(ehci, &ehci->regs->status);
++				}
++				if (i>0)
++					printk("polling NOT HALT times.....%d\n",i);
++			}
++			else {
++				u32 regcommand, regenable, regstatus;
++				u32 i,temp;
++
++				//printk("Host cannot exit HALT state, recover.....\n");
++				regcommand = readl(&ehci->regs->command);
++                regcommand &= ((0xFF << 16) | (0x3 << 2));
++				regenable = readl(&ehci->regs->intr_enable);
++
++				writel(CMD_RESET,&ehci->regs->command);
++				i=0;
++				temp = CMD_RESET;
++				while (((temp & CMD_RESET)) && (i<=100)) {
++					mdelay(3);
++					i++;
++					temp = readl(&ehci->regs->command);
++				}
++				//printk("exit HALT OK.....%d\n",i);
++
++                //set port reset
++                writel(PORT_RESET, &ehci->regs->port_status);
++                mdelay(50);
++
++                /* re-init operational registers */
++                writel(ehci->periodic_dma, &ehci->regs->frame_list);
++                writel(ehci->async->qh_dma, &ehci->regs->async_next);
++
++				writel(regcommand,&ehci->regs->command);
++				mdelay(5);
++				writel(regcommand | CMD_RUN,&ehci->regs->command);
++				writel(regenable,&ehci->regs->intr_enable);
++                regstatus = readl(&ehci->regs->port_status);
++                writel(regstatus & ~PORT_RESET,&ehci->regs->port_status);
++
++				//printk("Host-halt recover OK\n");
++			}
++		}
++#endif /* CONFIG_GM_FOTG2XX || CONFIG_GM_FUSBH200 */
++
+ 		/* get per-port change detect bits */
+ 		if (ehci->has_ppcd)
+ 			ppcd = status >> 16;
+@@ -947,18 +1313,30 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
+ 
+ 	/* PCI errors [4.15.2.4] */
+ 	if (unlikely ((status & STS_FATAL) != 0)) {
+-		ehci_err(ehci, "fatal error\n");
+-		dbg_cmd(ehci, "fatal", cmd);
+-		dbg_status(ehci, "fatal", status);
+-		ehci_halt(ehci);
++		/* Patch from CTD, try to recover fatal error */
++		if (strncmp(hcd->self.bus_name, "fotg", 4) == 0) {
++            /*
++             * if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++             */
++            printk("Fatal error.....0x%x\n",status);
++
++            reset_host(ehci);
++
++			printk("recover OK\n");
++		} else {
++			ehci_err(ehci, "fatal error\n");
++			dbg_cmd(ehci, "fatal", cmd);
++			dbg_status(ehci, "fatal", status);
++			ehci_halt(ehci);
+ dead:
+-		ehci_reset(ehci);
+-		ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+-		usb_hc_died(hcd);
+-		/* generic layer kills/unlinks all urbs, then
+-		 * uses ehci_stop to clean up the rest
+-		 */
+-		bh = 1;
++			ehci_reset(ehci);
++			ehci_writel(ehci, 0, &ehci->regs->configured_flag);
++			usb_hc_died(hcd);
++			/* generic layer kills/unlinks all urbs, then
++			 * uses ehci_stop to clean up the rest
++			 */
++			bh = 1;
++		}
+ 	}
+ 
+ 	if (bh)
+@@ -1013,10 +1391,21 @@ static int ehci_urb_enqueue (
+ 		return intr_submit(ehci, urb, &qtd_list, mem_flags);
+ 
+ 	case PIPE_ISOCHRONOUS:
++#if defined(CONFIG_GM_FOTG2XX)
++        if ((strncmp(hcd->self.bus_name, "fotg", 4) == 0) && (ehci_port_speed(ehci, 0) != USB_PORT_STAT_HIGH_SPEED)) {
++            return itd_submit (ehci, urb, mem_flags);
++        } else {
++    		if (urb->dev->speed == USB_SPEED_HIGH)
++    			return itd_submit (ehci, urb, mem_flags);
++    		else
++    			return sitd_submit (ehci, urb, mem_flags);
++        }
++#else
+ 		if (urb->dev->speed == USB_SPEED_HIGH)
+ 			return itd_submit (ehci, urb, mem_flags);
+ 		else
+ 			return sitd_submit (ehci, urb, mem_flags);
++#endif
+ 	}
+ }
+ 
+@@ -1376,16 +1765,36 @@ MODULE_LICENSE ("GPL");
+ #define        PLATFORM_DRIVER         ehci_mv_driver
+ #endif
+ 
++#if defined(CONFIG_GM_FOTG2XX)
++#include "ehci-fotg2xx.c"
++#define PLATFORM_DRIVER		fotg210_ehci_driver
++#if defined(CONFIG_PLATFORM_GM8210)
++#include <mach/fmem.h>
++#endif
++#endif
++
++#if defined(CONFIG_GM_FUSBH200)
++#include "ehci-fusbh200.c"
++#endif
++/** When building for kernel module, this check will cause compiling error
+ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
+-    !defined(XILINX_OF_PLATFORM_DRIVER)
++    !defined(XILINX_OF_PLATFORM_DRIVER) && \
++    !defined(CONFIG_GM_FOTG2XX) && !defined(CONFIG_GM_FUSBH200)
+ #error "missing bus glue for ehci-hcd"
+ #endif
+-
++*/
+ static int __init ehci_hcd_init(void)
+ {
+ 	int retval = 0;
+ 
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id != FMEM_CPU_FA726 || pci_id != FMEM_PCI_HOST)
++		goto clean0;
++#endif
+ 	if (usb_disabled())
+ 		return -ENODEV;
+ 
+@@ -1409,6 +1818,12 @@ static int __init ehci_hcd_init(void)
+ 	}
+ #endif
+ 
++#if defined(CONFIG_GM_FUSBH200)
++	retval = platform_driver_register(&fusbh200_plat_driver);
++	if (retval < 0)
++		goto final;
++#endif
++
+ #ifdef PLATFORM_DRIVER
+ 	retval = platform_driver_register(&PLATFORM_DRIVER);
+ 	if (retval < 0)
+@@ -1464,6 +1879,9 @@ clean0:
+ 	debugfs_remove(ehci_debug_root);
+ 	ehci_debug_root = NULL;
+ err_debug:
++#endif
++#if defined(CONFIG_GM_FUSBH200)
++final:
+ #endif
+ 	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+ 	return retval;
+@@ -1487,10 +1905,12 @@ static void __exit ehci_hcd_cleanup(void)
+ #ifdef PS3_SYSTEM_BUS_DRIVER
+ 	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ #endif
++#ifdef CONFIG_GM_FUSBH200
++	platform_driver_unregister(&fusbh200_plat_driver);
++#endif
+ #ifdef DEBUG
+ 	debugfs_remove(ehci_debug_root);
+ #endif
+ 	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+ }
+ module_exit(ehci_hcd_cleanup);
+-
+diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
+index 77bbb235..c672b8fb 100644
+--- a/drivers/usb/host/ehci-hub.c
++++ b/drivers/usb/host/ehci-hub.c
+@@ -714,6 +714,22 @@ static int ehci_hub_control (
+ 		switch (wValue) {
+ 		case USB_PORT_FEAT_ENABLE:
+ 			ehci_writel(ehci, temp & ~PORT_PE, status_reg);
++#if defined(CONFIG_GM_FOTG2XX)
++			if (temp & PORT_RESET) {
++				u32 retval;
++
++				/* force reset to complete */
++				ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),	status_reg);
++				/* REVISIT:  some hardware needs 550+ usec to clear
++				 * this bit; seems too long to spin routinely...
++				 */
++				retval = handshake(ehci, status_reg, PORT_RESET, 0, 750);
++				if (retval != 0)
++					printk("port %d reset error %d\n", wIndex + 1, retval);
++				else
++					printk("PORT_RESET with C_PORT_ENABLE done\n");
++			}
++#endif
+ 			break;
+ 		case USB_PORT_FEAT_C_ENABLE:
+ 			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+@@ -856,6 +872,10 @@ static int ehci_hub_control (
+ 				}
+ 				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ 			}
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++			else
++				status |= 1<< USB_PORT_FEAT_C_SUSPEND;
++#endif
+ 		}
+ 
+ 		/* whoever resets must GetPortStatus to complete it!! */
+@@ -882,6 +902,11 @@ static int ehci_hub_control (
+ 			/* see what we found out */
+ 			temp = check_reset_complete (ehci, wIndex, status_reg,
+ 					ehci_readl(ehci, status_reg));
++#if defined(CONFIG_GM_FOTG2XX)
++			/* Patch from CTD, Restart Controller */
++			writel(readl(&ehci->regs->command)|CMD_RUN, &ehci->regs->command);
++			while((readl(&ehci->regs->status)&STS_HALT));
++#endif
+ 		}
+ 
+ 		if (!(temp & (PORT_RESUME|PORT_RESET)))
+@@ -1019,6 +1044,62 @@ static int ehci_hub_control (
+ 					wIndex + 1);
+ 				temp |= PORT_OWNER;
+ 			} else {
++#if defined(CONFIG_GM_FOTG2XX)
++                if (strncmp(hcd->self.bus_name, "fotg", 4) == 0) {
++                    u32 temp,count;
++
++                    /* Stop controller for reset */
++                    temp = readl(&ehci->regs->command);
++                    //printk("Stop for reset %x\n",temp);
++                    writel(temp&(~CMD_RUN),&ehci->regs->command);
++                    writel(ehci->periodic_dma, &ehci->regs->frame_list);
++                    writel(ehci->async->qh_dma, &ehci->regs->async_next);
++                    count=0;
++                    temp = 0;
++                    while (((temp & STS_HALT) == 0) && (count<=10000)) {
++                        udelay(3);
++                        count++;
++                        temp = readl(&ehci->regs->status);
++                    }
++                    //printk("......reset host..for port reset..........count %d\n",count);
++                    if (count>=10000) {
++                        u32 regcommand, regenable, regstatus;
++                        u32 i,temp;
++
++                        printk("Host cannot enter HALT state, recover.....\n");
++                        regcommand = readl(&ehci->regs->command);
++                        regcommand &= ((0xFF << 16) | (0x3 << 2));
++                        regenable = readl(&ehci->regs->intr_enable);
++
++                        writel(CMD_RESET,&ehci->regs->command);
++                        i=0;
++                        temp = CMD_RESET;
++                        while (((temp & CMD_RESET)) && (i<=1000)) {
++                            mdelay(1);
++                            i++;
++                            temp = readl(&ehci->regs->command);
++                        }
++                        printk("Reset OK.....%d\n",i);
++
++                        //set port reset
++                        writel(PORT_RESET, &ehci->regs->port_status);
++                        mdelay(50);
++
++                        /* re-init operational registers */
++                        writel(ehci->periodic_dma, &ehci->regs->frame_list);
++                        writel(ehci->async->qh_dma, &ehci->regs->async_next);
++
++                        writel(regcommand, &ehci->regs->command);
++                        mdelay(5);
++                        writel(regcommand | CMD_RUN,&ehci->regs->command);
++                        writel(regenable,&ehci->regs->intr_enable);
++                        regstatus = readl(&ehci->regs->port_status);
++                        writel(regstatus & ~PORT_RESET,&ehci->regs->port_status);
++
++                        printk("Host recover OK\n");
++                    }
++                }
++#endif
+ 				ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);
+ 				temp |= PORT_RESET;
+ 				temp &= ~PORT_PE;
+diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
+index 36ca5077..c081791d 100644
+--- a/drivers/usb/host/ehci-q.c
++++ b/drivers/usb/host/ehci-q.c
+@@ -987,7 +987,15 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ 			/* in case a clear of CMD_ASE didn't take yet */
+ 			(void)handshake(ehci, &ehci->regs->status,
+ 					STS_ASS, 0, 150);
++#if defined(CONFIG_GM_FOTG2XX)
++            if (strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0)
++                /* workaround, fix Ralink wifi dongle issue */
++                cmd |= (CMD_ASE | CMD_PSE);
++            else
++                cmd |= CMD_ASE;
++#else
+ 			cmd |= CMD_ASE;
++#endif
+ 			ehci_writel(ehci, cmd, &ehci->regs->command);
+ 			/* posted write need not be known to HC yet ... */
+ 		}
+@@ -1216,14 +1224,32 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+ 		BUG ();
+ #endif
+ 
++#if 0
++	/* Patch from CTD, if PORTSC run bit = 0, restore qh address */
++	if ((cmd & CMD_RUN) == 0) {
++		printk("unlink qhead in HALT:..%x..%x..%x\n", (u32)qh,
++			ehci_readl(ehci, &ehci->regs->port_status[0]), cmd);
++		ehci_writel(ehci, ehci->async->qh_dma, &ehci->regs->async_next);
++	}
++#endif
++
+ 	/* stop async schedule right now? */
+ 	if (unlikely (qh == ehci->async)) {
+ 		/* can't get here without STS_ASS set */
+ 		if (ehci->rh_state != EHCI_RH_HALTED
+ 				&& !ehci->reclaim) {
+ 			/* ... and CMD_IAAD clear */
++#if defined(CONFIG_GM_FOTG2XX)
++            if ((strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0) && !ehci->periodic_sched)
++                ehci_writel(ehci, cmd & ~(CMD_ASE | CMD_PSE),
++                        &ehci->regs->command);
++            else
++                ehci_writel(ehci, cmd & ~CMD_ASE,
++                        &ehci->regs->command);
++#else
+ 			ehci_writel(ehci, cmd & ~CMD_ASE,
+ 				    &ehci->regs->command);
++#endif
+ 			wmb ();
+ 			// handshake later, if we need to
+ 			timer_action_done (ehci, TIMER_ASYNC_OFF);
+diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
+index a60679cb..907436fc 100644
+--- a/drivers/usb/host/ehci-sched.c
++++ b/drivers/usb/host/ehci-sched.c
+@@ -487,6 +487,17 @@ static int enable_periodic (struct ehci_hcd *ehci)
+ 	if (ehci->periodic_sched++)
+ 		return 0;
+ 
++#if defined(CONFIG_GM_FOTG2XX)
++    if (strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0) {
++        cmd = ehci_readl(ehci, &ehci->regs->command);
++        if (cmd & CMD_PSE) {
++            /* CMD_PSE already pre-enabled to fix Ralink wifi dongle issue */
++            cmd &= ~CMD_PSE;
++            ehci_writel(ehci, cmd, &ehci->regs->command);
++        }
++    }
++#endif
++
+ 	/* did clearing PSE did take effect yet?
+ 	 * takes effect only at frame boundaries...
+ 	 */
+@@ -530,12 +541,19 @@ static int disable_periodic (struct ehci_hcd *ehci)
+ 	/* did setting PSE not take effect yet?
+ 	 * takes effect only at frame boundaries...
+ 	 */
+-	status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
+-					     STS_PSS, STS_PSS, 9 * 125);
+-	if (status) {
+-		usb_hc_died(ehci_to_hcd(ehci));
+-		return status;
+-	}
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++    if ((strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0) && !(ehci_readl(ehci, &ehci->regs->command) & CMD_PSE)) {
++        printk("%s: CMD_PSE already cleared, ignore handshake on STS_PSS\n", __func__);
++    } else
++#endif
++    {
++    	status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
++    					     STS_PSS, STS_PSS, 9 * 125);
++    	if (status) {
++    		usb_hc_died(ehci_to_hcd(ehci));
++    		return status;
++    	}
++    }
+ 
+ 	cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+ 	ehci_writel(ehci, cmd, &ehci->regs->command);
+@@ -980,6 +998,7 @@ iso_stream_init (
+ 	unsigned		epnum, maxp;
+ 	int			is_input;
+ 	long			bandwidth;
++	u32                     ehci_speed;
+ 
+ 	/*
+ 	 * this might be a "high bandwidth" highspeed endpoint,
+@@ -994,11 +1013,55 @@ iso_stream_init (
+ 		buf1 = 0;
+ 	}
+ 
+-	/* knows about ITD vs SITD */
++#if defined(CONFIG_GM_FOTG2XX)
++if ((strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0) && (ehci_port_speed(ehci, 0) != USB_PORT_STAT_HIGH_SPEED)) {
++	unsigned 		multi;
++
++	/* knows about ITD */
++	maxp = max_packet(maxp);
++	if (dev->speed == USB_SPEED_HIGH)
++	    multi = hb_mult(maxp);
++    else
++	    multi = 1;
++	buf1 |= maxp;
++	maxp *= multi;
++
++	stream->buf0 = cpu_to_hc32(ehci, (epnum << 8) | dev->devnum);
++	stream->buf1 = cpu_to_hc32(ehci, buf1);
++	stream->buf2 = cpu_to_hc32(ehci, multi);
++
++	/* usbfs wants to report the average usecs per frame tied up
++	 * when transfers on this endpoint are scheduled ...
++	 */
+ 	if (dev->speed == USB_SPEED_HIGH) {
++		stream->highspeed = 1;
++		stream->usecs = HS_USECS_ISO (maxp);
++	}
++	else {
++		interval <<= 3;
++		stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed,
++				is_input, 1, maxp));
++		stream->usecs /= 8;
++	}
++	bandwidth = stream->usecs * 8;
++	bandwidth /= interval;
++} else {
++#endif
++	ehci_speed = ehci_port_speed(ehci,0);
++	if (ehci_is_TDI(ehci)) {
++		// we use 125us as unit
++		if ( ehci_speed != USB_PORT_STAT_HIGH_SPEED )
++			interval = interval<<3;
++	}
++
++	/* knows about ITD vs SITD */
++	if ((dev->speed == USB_SPEED_HIGH) ||
++			( (ehci_is_TDI(ehci)) && (ehci_speed != USB_PORT_STAT_HIGH_SPEED)) ) {
+ 		unsigned multi = hb_mult(maxp);
+ 
+-		stream->highspeed = 1;
++                /* knows about ITD vs SITD */
++		if (dev->speed == USB_SPEED_HIGH)
++			stream->highspeed = 1;
+ 
+ 		maxp = max_packet(maxp);
+ 		buf1 |= maxp;
+@@ -1011,7 +1074,11 @@ iso_stream_init (
+ 		/* usbfs wants to report the average usecs per frame tied up
+ 		 * when transfers on this endpoint are scheduled ...
+ 		 */
+-		stream->usecs = HS_USECS_ISO (maxp);
++		if ( ehci_speed != USB_PORT_STAT_HIGH_SPEED ) { //full speed
++			stream->usecs = NS_TO_US (usb_calc_bus_time (dev->speed, is_input, 1, maxp));
++			stream->usecs /= 8;   // convert from FS to HS, use 125us as unit
++		} else
++			stream->usecs = HS_USECS_ISO (maxp);
+ 		bandwidth = stream->usecs * 8;
+ 		bandwidth /= interval;
+ 
+@@ -1051,6 +1118,10 @@ iso_stream_init (
+ 		/* stream->splits gets created from raw_mask later */
+ 		stream->address = cpu_to_hc32(ehci, addr);
+ 	}
++#if defined(CONFIG_GM_FOTG2XX)
++}
++#endif
++
+ 	stream->bandwidth = bandwidth;
+ 
+ 	stream->udev = dev;
+@@ -1063,6 +1134,8 @@ iso_stream_init (
+ static void
+ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
+ {
++	u32	ehci_speed = ehci_port_speed(ehci,0);
++
+ 	stream->refcount--;
+ 
+ 	/* free whenever just a dev->ep reference remains.
+@@ -1077,8 +1150,20 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
+ 			entry = stream->free_list.next;
+ 			list_del (entry);
+ 
++#if defined(CONFIG_GM_FOTG2XX)
++if ((strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0) && (ehci_speed != USB_PORT_STAT_HIGH_SPEED)) {
++            /* knows about ITD */
++            struct ehci_itd     *itd;
++
++            itd = list_entry (entry, struct ehci_itd,
++                    itd_list);
++            dma_pool_free (ehci->itd_pool, itd,
++                    itd->itd_dma);
++} else {
++#endif
+ 			/* knows about ITD vs SITD */
+-			if (stream->highspeed) {
++			if ((stream->highspeed) ||
++					((ehci_is_TDI(ehci)) && (ehci_speed != USB_PORT_STAT_HIGH_SPEED))) {
+ 				struct ehci_itd		*itd;
+ 
+ 				itd = list_entry (entry, struct ehci_itd,
+@@ -1093,6 +1178,9 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
+ 				dma_pool_free (ehci->sitd_pool, sitd,
+ 						sitd->sitd_dma);
+ 			}
++#if defined(CONFIG_GM_FOTG2XX)
++}
++#endif
+ 		}
+ 
+ 		stream->bEndpointAddress &= 0x0f;
+@@ -1415,13 +1503,22 @@ iso_stream_schedule (
+ 	int			status;
+ 	unsigned		mod = ehci->periodic_size << 3;
+ 	struct ehci_iso_sched	*sched = urb->hcpriv;
++	u32			ehci_speed = ehci_port_speed(ehci,0);
+ 
+ 	period = urb->interval;
+ 	span = sched->span;
++#if defined(CONFIG_GM_FOTG2XX)
++if ((strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0) && (ehci_speed != USB_PORT_STAT_HIGH_SPEED)) {
++    // do nothing
++} else {
++#endif
+ 	if (!stream->highspeed) {
+ 		period <<= 3;
+ 		span <<= 3;
+ 	}
++#if defined(CONFIG_GM_FOTG2XX)
++}
++#endif
+ 
+ 	if (span > mod - SCHEDULE_SLOP) {
+ 		ehci_dbg (ehci, "iso request %p too long\n", urb);
+@@ -1490,7 +1587,15 @@ iso_stream_schedule (
+ 		do {
+ 			start--;
+ 			/* check schedule: enough space? */
+-			if (stream->highspeed) {
++#if defined(CONFIG_GM_FOTG2XX)
++if ((strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0) && (ehci_speed != USB_PORT_STAT_HIGH_SPEED)) {
++            if (itd_slot_ok(ehci, mod, start,
++                    stream->usecs, period))
++                done = 1;
++} else {
++#endif
++			if ((stream->highspeed) ||
++					((ehci_is_TDI(ehci)) && (ehci_speed != USB_PORT_STAT_HIGH_SPEED))) {
+ 				if (itd_slot_ok(ehci, mod, start,
+ 						stream->usecs, period))
+ 					done = 1;
+@@ -1501,6 +1606,9 @@ iso_stream_schedule (
+ 						start, sched, period))
+ 					done = 1;
+ 			}
++#if defined(CONFIG_GM_FOTG2XX)
++}
++#endif
+ 		} while (start > next && !done);
+ 
+ 		/* no room in the schedule */
+@@ -1823,11 +1931,35 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
+ 		ehci_dbg (ehci, "can't get iso stream\n");
+ 		return -ENOMEM;
+ 	}
+-	if (unlikely (urb->interval != stream->interval)) {
++#if defined(CONFIG_GM_FOTG2XX)
++if ((strncmp(ehci_to_hcd(ehci)->self.bus_name, "fotg", 4) == 0) && (ehci_port_speed(ehci, 0) != USB_PORT_STAT_HIGH_SPEED)) {
++	if (unlikely (urb->interval != stream->interval) &&
++	    (ehci_port_speed(ehci, 0) == USB_PORT_STAT_HIGH_SPEED)) {
+ 		ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
+ 			stream->interval, urb->interval);
+ 		goto done;
+ 	}
++} else {
++#endif
++	if (ehci_is_TDI(ehci)) {
++		u32 ehci_speed = ehci_port_speed(ehci,0);
++
++		if ( unlikely (urb->interval != stream->interval) && (ehci_speed == USB_PORT_STAT_HIGH_SPEED) ) {
++			printk( "can't change iso interval %d --> %d\n",
++					stream->interval, urb->interval);
++			goto done;
++		}
++	}
++	else {
++		if (unlikely (urb->interval != stream->interval)) {
++			ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
++					stream->interval, urb->interval);
++			goto done;
++		}
++	}
++#if defined(CONFIG_GM_FOTG2XX)
++}
++#endif
+ 
+ #ifdef EHCI_URB_TRACE
+ 	ehci_dbg (ehci,
+@@ -2212,6 +2344,13 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
+ 	unsigned long		flags;
+ 	struct ehci_iso_stream	*stream;
+ 
++	if (ehci_is_TDI(ehci)) {
++		u32 ehci_speed = ehci_port_speed(ehci,0);
++
++		if (ehci_speed != USB_PORT_STAT_HIGH_SPEED)  // this is FS itd
++			return itd_submit(ehci,urb,mem_flags);
++	}
++
+ 	/* Get iso_stream head */
+ 	stream = iso_stream_find (ehci, urb);
+ 	if (stream == NULL) {
+diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
+index 0a5fda73..e56962fc 100644
+--- a/drivers/usb/host/ehci.h
++++ b/drivers/usb/host/ehci.h
+@@ -161,6 +161,7 @@ struct ehci_hcd {			/* one per controller */
+ 	unsigned		has_ppcd:1; /* support per-port change bits */
+ 	u8			sbrn;		/* packed release number */
+ 
++
+ 	/* irq statistics */
+ #ifdef EHCI_STATS
+ 	struct ehci_stats	stats;
+@@ -487,7 +488,7 @@ struct ehci_itd {
+ 	unsigned		frame;		/* where scheduled */
+ 	unsigned		pg;
+ 	unsigned		index[8];	/* in urb->iso_frame_desc */
+-} __attribute__ ((aligned (32)));
++} __attribute__ ((aligned (64)));
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+@@ -595,10 +596,47 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
+ 
+ #else
+ 
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200)
++
++#define	ehci_is_TDI(e)			(ehci_to_hcd(e)->has_tt)
++
++static inline unsigned int ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
++{
++	u32 val = 0;
++	struct usb_hcd *hcd = ehci_to_hcd(ehci);
++	//hcd->has_tt =1;
++
++#if defined(CONFIG_GM_FUSBH200)
++	if (memcmp(hcd->product_desc, H200_NAME, sizeof(H200_NAME)) == 0) {
++		val=mwH20Port(hcd->regs,0x40);
++		val = (val >> 9) & 0x03;
++	}
++#endif
++#if defined(CONFIG_GM_FOTG2XX)
++	if (memcmp(hcd->product_desc, OTG2XX_NAME, sizeof(OTG2XX_NAME)) == 0) {
++		val = mwOTG20Port(hcd->regs,0x80);
++		val = (val >> 22) & 0x03;
++	}
++#endif
++
++	switch (val) {
++		case 0:
++			return 0;
++		case 1:
++			return USB_PORT_STAT_LOW_SPEED;
++		case 2:
++			return USB_PORT_STAT_HIGH_SPEED;
++		default:
++			return USB_PORT_STAT_LOW_SPEED;
++	}
++	return USB_PORT_STAT_HIGH_SPEED;
++}
++#else
+ #define	ehci_is_TDI(e)			(0)
+ 
+ #define	ehci_port_speed(ehci, portsc)	USB_PORT_STAT_HIGH_SPEED
+ #endif
++#endif
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
+new file mode 100644
+index 00000000..19707fc8
+--- /dev/null
++++ b/drivers/usb/host/fotg210-hcd.c
+@@ -0,0 +1,6394 @@
++/*
++ * Faraday FOTG210 EHCI-like driver
++ *
++ * Copyright (c) 2013 Faraday Technology Corporation
++ *
++ * Author: Yuan-Hsin Chen <yhchen@faraday-tech.com>
++	   Li-Chun Chen <lichun_c@faraday-tech.com>
++ * 	   Feng-Hsin Chiang <john453@faraday-tech.com>
++ * 	   Po-Yu Chuang <ratbert.chuang@gmail.com>
++ *
++ * Most of code borrowed from the Linux-3.7 EHCI driver
++ *
++ * 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 <linux/module.h>
++#include <linux/device.h>
++#include <linux/dmapool.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/vmalloc.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/hrtimer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/usb.h>
++#include <linux/usb/hcd.h>
++#include <linux/moduleparam.h>
++#include <linux/dma-mapping.h>
++#include <linux/debugfs.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/usb/otg.h>
++
++#include <asm/byteorder.h>
++#include <asm/irq.h>
++#include <asm/unaligned.h>
++
++/*-------------------------------------------------------------------------*/
++#define DRIVER_AUTHOR "Faraday Technology Corporation"
++#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
++
++static const char	hcd_name[] = "fotg210_hcd";
++
++#undef VERBOSE_DEBUG
++#undef FOTG210_URB_TRACE
++
++#ifdef DEBUG
++#define FOTG210_STATS
++#endif
++
++/* magic numbers that can affect system performance */
++#define	FOTG210_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
++#define	FOTG210_TUNE_RL_HS		4	/* nak throttle; see 4.9 */
++#define	FOTG210_TUNE_RL_TT		0
++#define	FOTG210_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
++#define	FOTG210_TUNE_MULT_TT	1
++/*
++ * Some drivers think it's safe to schedule isochronous transfers more than
++ * 256 ms into the future (partly as a result of an old bug in the scheduling
++ * code).  In an attempt to avoid trouble, we will use a minimum scheduling
++ * length of 512 frames instead of 256.
++ */
++#define	FOTG210_TUNE_FLS		1	/* (medium) 512-frame schedule */
++
++/* Initial IRQ latency:  faster than hw default */
++static int log2_irq_thresh = 0;		/* 0 to 6 */
++module_param(log2_irq_thresh, int, S_IRUGO);
++MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
++
++/* initial park setting:  slower than hw default */
++static unsigned park = 0;
++module_param(park, uint, S_IRUGO);
++MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
++
++/* for link power management(LPM) feature */
++static unsigned int hird;
++module_param(hird, int, S_IRUGO);
++MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
++
++#define	INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
++
++#include "fotg210-hcd.h"
++
++/*-------------------------------------------------------------------------*/
++
++#define fotg210_dbg(fotg210, fmt, args...) \
++	dev_dbg(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
++#define fotg210_err(fotg210, fmt, args...) \
++	dev_err(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
++#define fotg210_info(fotg210, fmt, args...) \
++	dev_info(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
++#define fotg210_warn(fotg210, fmt, args...) \
++	dev_warn(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
++
++#ifdef VERBOSE_DEBUG
++#	define fotg210_vdbg fotg210_dbg
++#else
++	static inline void fotg210_vdbg(struct fotg210_hcd *fotg210, ...) {}
++#endif
++
++#ifdef	DEBUG
++
++/* check the values in the HCSPARAMS register
++ * (host controller _Structural_ parameters)
++ * see EHCI spec, Table 2-4 for each value
++ */
++static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label)
++{
++	u32	params = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
++
++	fotg210_dbg(fotg210,
++		"%s hcs_params 0x%x ports=%d\n",
++		label, params,
++		HCS_N_PORTS(params)
++		);
++}
++#else
++
++static inline void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) {}
++
++#endif
++
++#ifdef	DEBUG
++
++/* check the values in the HCCPARAMS register
++ * (host controller _Capability_ parameters)
++ * see EHCI Spec, Table 2-5 for each value
++ * */
++static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label)
++{
++	u32	params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
++
++	fotg210_dbg(fotg210,
++		"%s hcc_params %04x uframes %s%s\n",
++		label,
++		params,
++		HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
++		HCC_CANPARK(params) ? " park" : "");
++}
++#else
++
++static inline void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) {}
++
++#endif
++
++#ifdef	DEBUG
++
++static void __maybe_unused
++dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd)
++{
++	fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
++		hc32_to_cpup(fotg210, &qtd->hw_next),
++		hc32_to_cpup(fotg210, &qtd->hw_alt_next),
++		hc32_to_cpup(fotg210, &qtd->hw_token),
++		hc32_to_cpup(fotg210, &qtd->hw_buf[0]));
++	if (qtd->hw_buf[1])
++		fotg210_dbg(fotg210, "  p1=%08x p2=%08x p3=%08x p4=%08x\n",
++			hc32_to_cpup(fotg210, &qtd->hw_buf[1]),
++			hc32_to_cpup(fotg210, &qtd->hw_buf[2]),
++			hc32_to_cpup(fotg210, &qtd->hw_buf[3]),
++			hc32_to_cpup(fotg210, &qtd->hw_buf[4]));
++}
++
++static void __maybe_unused
++dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{
++	struct fotg210_qh_hw *hw = qh->hw;
++
++	fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label,
++		qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
++	dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next);
++}
++
++static void __maybe_unused
++dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
++{
++	fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n",
++		label, itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next),
++		itd->urb);
++	fotg210_dbg(fotg210,
++		"  trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
++		hc32_to_cpu(fotg210, itd->hw_transaction[0]),
++		hc32_to_cpu(fotg210, itd->hw_transaction[1]),
++		hc32_to_cpu(fotg210, itd->hw_transaction[2]),
++		hc32_to_cpu(fotg210, itd->hw_transaction[3]),
++		hc32_to_cpu(fotg210, itd->hw_transaction[4]),
++		hc32_to_cpu(fotg210, itd->hw_transaction[5]),
++		hc32_to_cpu(fotg210, itd->hw_transaction[6]),
++		hc32_to_cpu(fotg210, itd->hw_transaction[7]));
++	fotg210_dbg(fotg210,
++		"  buf:   %08x %08x %08x %08x %08x %08x %08x\n",
++		hc32_to_cpu(fotg210, itd->hw_bufp[0]),
++		hc32_to_cpu(fotg210, itd->hw_bufp[1]),
++		hc32_to_cpu(fotg210, itd->hw_bufp[2]),
++		hc32_to_cpu(fotg210, itd->hw_bufp[3]),
++		hc32_to_cpu(fotg210, itd->hw_bufp[4]),
++		hc32_to_cpu(fotg210, itd->hw_bufp[5]),
++		hc32_to_cpu(fotg210, itd->hw_bufp[6]));
++	fotg210_dbg(fotg210, "  index: %d %d %d %d %d %d %d %d\n",
++		itd->index[0], itd->index[1], itd->index[2],
++		itd->index[3], itd->index[4], itd->index[5],
++		itd->index[6], itd->index[7]);
++}
++
++static int __maybe_unused
++dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
++{
++	return scnprintf(buf, len,
++		"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
++		label, label[0] ? " " : "", status,
++		(status & STS_ASS) ? " Async" : "",
++		(status & STS_PSS) ? " Periodic" : "",
++		(status & STS_RECL) ? " Recl" : "",
++		(status & STS_HALT) ? " Halt" : "",
++		(status & STS_IAA) ? " IAA" : "",
++		(status & STS_FATAL) ? " FATAL" : "",
++		(status & STS_FLR) ? " FLR" : "",
++		(status & STS_PCD) ? " PCD" : "",
++		(status & STS_ERR) ? " ERR" : "",
++		(status & STS_INT) ? " INT" : ""
++		);
++}
++
++static int __maybe_unused
++dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
++{
++	return scnprintf(buf, len,
++		"%s%sintrenable %02x%s%s%s%s%s%s",
++		label, label[0] ? " " : "", enable,
++		(enable & STS_IAA) ? " IAA" : "",
++		(enable & STS_FATAL) ? " FATAL" : "",
++		(enable & STS_FLR) ? " FLR" : "",
++		(enable & STS_PCD) ? " PCD" : "",
++		(enable & STS_ERR) ? " ERR" : "",
++		(enable & STS_INT) ? " INT" : ""
++		);
++}
++
++static const char *const fls_strings[] = { "1024", "512", "256", "??" };
++
++static int
++dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
++{
++	return scnprintf(buf, len,
++		"%s%scommand %07x %s=%d ithresh=%d%s%s%s "
++		"period=%s%s %s",
++		label, label[0] ? " " : "", command,
++		(command & CMD_PARK) ? " park" : "(park)",
++		CMD_PARK_CNT(command),
++		(command >> 16) & 0x3f,
++		(command & CMD_IAAD) ? " IAAD" : "",
++		(command & CMD_ASE) ? " Async" : "",
++		(command & CMD_PSE) ? " Periodic" : "",
++		fls_strings[(command >> 2) & 0x3],
++		(command & CMD_RESET) ? " Reset" : "",
++		(command & CMD_RUN) ? "RUN" : "HALT"
++		);
++}
++
++static int
++dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
++{
++	char	*sig;
++
++	/* signaling state */
++	switch (status & (3 << 10)) {
++	case 0 << 10:
++		sig = "se0";
++		break;
++	case 1 << 10:
++		sig = "k";
++		break; /* low speed */
++	case 2 << 10:
++		sig = "j";
++		break;
++	default:
++		sig = "?";
++		break;
++	}
++
++	return scnprintf(buf, len,
++		"%s%sport:%d status %06x %d "
++		"sig=%s%s%s%s%s%s%s%s",
++		label, label[0] ? " " : "", port, status,
++		status>>25,/*device address */
++		sig,
++		(status & PORT_RESET) ? " RESET" : "",
++		(status & PORT_SUSPEND) ? " SUSPEND" : "",
++		(status & PORT_RESUME) ? " RESUME" : "",
++		(status & PORT_PEC) ? " PEC" : "",
++		(status & PORT_PE) ? " PE" : "",
++		(status & PORT_CSC) ? " CSC" : "",
++		(status & PORT_CONNECT) ? " CONNECT" : "");
++}
++
++#else
++static inline void __maybe_unused
++dbg_qh(char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{}
++
++static inline int __maybe_unused
++dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
++{ return 0; }
++
++static inline int __maybe_unused
++dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
++{ return 0; }
++
++static inline int __maybe_unused
++dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
++{ return 0; }
++
++static inline int __maybe_unused
++dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
++{ return 0; }
++
++#endif	/* DEBUG */
++
++/* functions have the "wrong" filename when they're output... */
++#define dbg_status(fotg210, label, status) { \
++	char _buf[80]; \
++	dbg_status_buf(_buf, sizeof(_buf), label, status); \
++	fotg210_dbg(fotg210, "%s\n", _buf); \
++}
++
++#define dbg_cmd(fotg210, label, command) { \
++	char _buf[80]; \
++	dbg_command_buf(_buf, sizeof(_buf), label, command); \
++	fotg210_dbg(fotg210, "%s\n", _buf); \
++}
++
++#define dbg_port(fotg210, label, port, status) { \
++	char _buf[80]; \
++	dbg_port_buf(_buf, sizeof(_buf), label, port, status); \
++	fotg210_dbg(fotg210, "%s\n", _buf); \
++}
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef STUB_DEBUG_FILES
++
++static inline void create_debug_files(struct fotg210_hcd *bus) { }
++static inline void remove_debug_files(struct fotg210_hcd *bus) { }
++
++#else
++
++/* troubleshooting help: expose state in debugfs */
++
++static int debug_async_open(struct inode *, struct file *);
++static int debug_periodic_open(struct inode *, struct file *);
++static int debug_registers_open(struct inode *, struct file *);
++static int debug_async_open(struct inode *, struct file *);
++
++static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
++static int debug_close(struct inode *, struct file *);
++
++static const struct file_operations debug_async_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_async_open,
++	.read		= debug_output,
++	.release	= debug_close,
++	.llseek		= default_llseek,
++};
++static const struct file_operations debug_periodic_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_periodic_open,
++	.read		= debug_output,
++	.release	= debug_close,
++	.llseek		= default_llseek,
++};
++static const struct file_operations debug_registers_fops = {
++	.owner		= THIS_MODULE,
++	.open		= debug_registers_open,
++	.read		= debug_output,
++	.release	= debug_close,
++	.llseek		= default_llseek,
++};
++
++static struct dentry *fotg210_debug_root;
++
++struct debug_buffer {
++	ssize_t (*fill_func)(struct debug_buffer *);	/* fill method */
++	struct usb_bus *bus;
++	struct mutex mutex;	/* protect filling of buffer */
++	size_t count;		/* number of characters filled into buffer */
++	char *output_buf;
++	size_t alloc_size;
++};
++
++#define speed_char(info1)({ char tmp; \
++		switch (info1 & (3 << 12)) { \
++		case QH_FULL_SPEED:	\
++			tmp = 'f'; break; \
++		case QH_LOW_SPEED:	\
++			tmp = 'l'; break; \
++		case QH_HIGH_SPEED:	\
++			tmp = 'h'; break; \
++		default:		\
++			tmp = '?'; break; \
++		}; tmp; })
++
++static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token)
++{
++	__u32 v = hc32_to_cpu(fotg210, token);
++
++	if (v & QTD_STS_ACTIVE)
++		return '*';
++	if (v & QTD_STS_HALT)
++		return '-';
++	if (!IS_SHORT_READ(v))
++		return ' ';
++	/* tries to advance through hw_alt_next */
++	return '/';
++}
++
++static void qh_lines(
++	struct fotg210_hcd *fotg210,
++	struct fotg210_qh *qh,
++	char **nextp,
++	unsigned *sizep
++)
++{
++	u32			scratch;
++	u32			hw_curr;
++	struct fotg210_qtd	*td;
++	unsigned		temp;
++	unsigned		size = *sizep;
++	char			*next = *nextp;
++	char			mark;
++	__le32			list_end = FOTG210_LIST_END(fotg210);
++	struct fotg210_qh_hw	*hw = qh->hw;
++
++	if (hw->hw_qtd_next == list_end)	/* NEC does this */
++		mark = '@';
++	else
++		mark = token_mark(fotg210, hw->hw_token);
++	if (mark == '/') {	/* qh_alt_next controls qh advance? */
++		if ((hw->hw_alt_next & QTD_MASK(fotg210))
++				== fotg210->async->hw->hw_alt_next)
++			mark = '#';	/* blocked */
++		else if (hw->hw_alt_next == list_end)
++			mark = '.';	/* use hw_qtd_next */
++		/* else alt_next points to some other qtd */
++	}
++	scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
++	hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0;
++	temp = scnprintf(next, size,
++			"qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)",
++			qh, scratch & 0x007f,
++			speed_char(scratch),
++			(scratch >> 8) & 0x000f,
++			scratch, hc32_to_cpup(fotg210, &hw->hw_info2),
++			hc32_to_cpup(fotg210, &hw->hw_token), mark,
++			(cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token)
++				? "data1" : "data0",
++			(hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f);
++	size -= temp;
++	next += temp;
++
++	/* hc may be modifying the list as we read it ... */
++	list_for_each_entry(td, &qh->qtd_list, qtd_list) {
++		scratch = hc32_to_cpup(fotg210, &td->hw_token);
++		mark = ' ';
++		if (hw_curr == td->qtd_dma)
++			mark = '*';
++		else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma))
++			mark = '+';
++		else if (QTD_LENGTH(scratch)) {
++			if (td->hw_alt_next == fotg210->async->hw->hw_alt_next)
++				mark = '#';
++			else if (td->hw_alt_next != list_end)
++				mark = '/';
++		}
++		temp = snprintf(next, size,
++				"\n\t%p%c%s len=%d %08x urb %p",
++				td, mark, ({ char *tmp;
++				 switch ((scratch>>8)&0x03) {
++				 case 0:
++					tmp = "out";
++					break;
++				 case 1:
++					tmp = "in";
++					break;
++				 case 2:
++					tmp = "setup";
++					break;
++				 default:
++					tmp = "?";
++					break;
++				 } tmp; }),
++				(scratch >> 16) & 0x7fff,
++				scratch,
++				td->urb);
++		if (size < temp)
++			temp = size;
++		size -= temp;
++		next += temp;
++		if (temp == size)
++			goto done;
++	}
++
++	temp = snprintf(next, size, "\n");
++	if (size < temp)
++		temp = size;
++	size -= temp;
++	next += temp;
++
++done:
++	*sizep = size;
++	*nextp = next;
++}
++
++static ssize_t fill_async_buffer(struct debug_buffer *buf)
++{
++	struct usb_hcd		*hcd;
++	struct fotg210_hcd	*fotg210;
++	unsigned long		flags;
++	unsigned		temp, size;
++	char			*next;
++	struct fotg210_qh		*qh;
++
++	hcd = bus_to_hcd(buf->bus);
++	fotg210 = hcd_to_fotg210(hcd);
++	next = buf->output_buf;
++	size = buf->alloc_size;
++
++	*next = 0;
++
++	/* dumps a snapshot of the async schedule.
++	 * usually empty except for long-term bulk reads, or head.
++	 * one QH per line, and TDs we know about
++	 */
++	spin_lock_irqsave(&fotg210->lock, flags);
++	for (qh = fotg210->async->qh_next.qh; size > 0 && qh;
++	     qh = qh->qh_next.qh)
++		qh_lines(fotg210, qh, &next, &size);
++	if (fotg210->async_unlink && size > 0) {
++		temp = scnprintf(next, size, "\nunlink =\n");
++		size -= temp;
++		next += temp;
++
++		for (qh = fotg210->async_unlink; size > 0 && qh;
++				qh = qh->unlink_next)
++			qh_lines(fotg210, qh, &next, &size);
++	}
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++
++	return strlen(buf->output_buf);
++}
++
++#define DBG_SCHED_LIMIT 64
++static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
++{
++	struct usb_hcd		*hcd;
++	struct fotg210_hcd		*fotg210;
++	unsigned long		flags;
++	union fotg210_shadow	p, *seen;
++	unsigned		temp, size, seen_count;
++	char			*next;
++	unsigned		i;
++	__hc32			tag;
++
++	seen = kmalloc(DBG_SCHED_LIMIT * sizeof(*seen), GFP_ATOMIC);
++	if (!seen)
++		return 0;
++	seen_count = 0;
++
++	hcd = bus_to_hcd(buf->bus);
++	fotg210 = hcd_to_fotg210(hcd);
++	next = buf->output_buf;
++	size = buf->alloc_size;
++
++	temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size);
++	size -= temp;
++	next += temp;
++
++	/* dump a snapshot of the periodic schedule.
++	 * iso changes, interrupt usually doesn't.
++	 */
++	spin_lock_irqsave(&fotg210->lock, flags);
++	for (i = 0; i < fotg210->periodic_size; i++) {
++		p = fotg210->pshadow[i];
++		if (likely(!p.ptr))
++			continue;
++		tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]);
++
++		temp = scnprintf(next, size, "%4d: ", i);
++		size -= temp;
++		next += temp;
++
++		do {
++			struct fotg210_qh_hw *hw;
++
++			switch (hc32_to_cpu(fotg210, tag)) {
++			case Q_TYPE_QH:
++				hw = p.qh->hw;
++				temp = scnprintf(next, size, " qh%d-%04x/%p",
++						p.qh->period,
++						hc32_to_cpup(fotg210,
++							&hw->hw_info2)
++							/* uframe masks */
++							& (QH_CMASK | QH_SMASK),
++						p.qh);
++				size -= temp;
++				next += temp;
++				/* don't repeat what follows this qh */
++				for (temp = 0; temp < seen_count; temp++) {
++					if (seen[temp].ptr != p.ptr)
++						continue;
++					if (p.qh->qh_next.ptr) {
++						temp = scnprintf(next, size,
++							" ...");
++						size -= temp;
++						next += temp;
++					}
++					break;
++				}
++				/* show more info the first time around */
++				if (temp == seen_count) {
++					u32	scratch = hc32_to_cpup(fotg210,
++							&hw->hw_info1);
++					struct fotg210_qtd	*qtd;
++					char		*type = "";
++
++					/* count tds, get ep direction */
++					temp = 0;
++					list_for_each_entry(qtd,
++							&p.qh->qtd_list,
++							qtd_list) {
++						temp++;
++						switch (0x03 & (hc32_to_cpu(
++							fotg210,
++							qtd->hw_token) >> 8)) {
++						case 0:
++							type = "out";
++							continue;
++						case 1:
++							type = "in";
++							continue;
++						}
++					}
++
++					temp = scnprintf(next, size,
++						"(%c%d ep%d%s "
++						"[%d/%d] q%d p%d)",
++						speed_char(scratch),
++						scratch & 0x007f,
++						(scratch >> 8) & 0x000f, type,
++						p.qh->usecs, p.qh->c_usecs,
++						temp,
++						0x7ff & (scratch >> 16));
++
++					if (seen_count < DBG_SCHED_LIMIT)
++						seen[seen_count++].qh = p.qh;
++				} else
++					temp = 0;
++				tag = Q_NEXT_TYPE(fotg210, hw->hw_next);
++				p = p.qh->qh_next;
++				break;
++			case Q_TYPE_FSTN:
++				temp = scnprintf(next, size,
++					" fstn-%8x/%p", p.fstn->hw_prev,
++					p.fstn);
++				tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next);
++				p = p.fstn->fstn_next;
++				break;
++			case Q_TYPE_ITD:
++				temp = scnprintf(next, size,
++					" itd/%p", p.itd);
++				tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next);
++				p = p.itd->itd_next;
++				break;
++			}
++			size -= temp;
++			next += temp;
++		} while (p.ptr);
++
++		temp = scnprintf(next, size, "\n");
++		size -= temp;
++		next += temp;
++	}
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	kfree(seen);
++
++	return buf->alloc_size - size;
++}
++#undef DBG_SCHED_LIMIT
++
++static const char *rh_state_string(struct fotg210_hcd *fotg210)
++{
++	switch (fotg210->rh_state) {
++	case FOTG210_RH_HALTED:
++		return "halted";
++	case FOTG210_RH_SUSPENDED:
++		return "suspended";
++	case FOTG210_RH_RUNNING:
++		return "running";
++	case FOTG210_RH_STOPPING:
++		return "stopping";
++	}
++	return "?";
++}
++
++static ssize_t fill_registers_buffer(struct debug_buffer *buf)
++{
++	struct usb_hcd		*hcd;
++	struct fotg210_hcd	*fotg210;
++	unsigned long		flags;
++	unsigned		temp, size, i;
++	char			*next, scratch[80];
++	static const char	fmt[] = "%*s\n";
++	static const char	label[] = "";
++
++	hcd = bus_to_hcd(buf->bus);
++	fotg210 = hcd_to_fotg210(hcd);
++	next = buf->output_buf;
++	size = buf->alloc_size;
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++
++	if (!HCD_HW_ACCESSIBLE(hcd)) {
++		size = scnprintf(next, size,
++			"bus %s, device %s\n"
++			"%s\n"
++			"SUSPENDED(no register access)\n",
++			hcd->self.controller->bus->name,
++			dev_name(hcd->self.controller),
++			hcd->product_desc);
++		goto done;
++	}
++
++	/* Capability Registers */
++	i = HC_VERSION(fotg210, fotg210_readl(fotg210,
++					      &fotg210->caps->hc_capbase));
++	temp = scnprintf(next, size,
++		"bus %s, device %s\n"
++		"%s\n"
++		"EHCI %x.%02x, rh state %s\n",
++		hcd->self.controller->bus->name,
++		dev_name(hcd->self.controller),
++		hcd->product_desc,
++		i >> 8, i & 0x0ff, rh_state_string(fotg210));
++	size -= temp;
++	next += temp;
++
++	/* FIXME interpret both types of params */
++	i = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
++	temp = scnprintf(next, size, "structural params 0x%08x\n", i);
++	size -= temp;
++	next += temp;
++
++	i = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
++	temp = scnprintf(next, size, "capability params 0x%08x\n", i);
++	size -= temp;
++	next += temp;
++
++	/* Operational Registers */
++	temp = dbg_status_buf(scratch, sizeof(scratch), label,
++			fotg210_readl(fotg210, &fotg210->regs->status));
++	temp = scnprintf(next, size, fmt, temp, scratch);
++	size -= temp;
++	next += temp;
++
++	temp = dbg_command_buf(scratch, sizeof(scratch), label,
++			fotg210_readl(fotg210, &fotg210->regs->command));
++	temp = scnprintf(next, size, fmt, temp, scratch);
++	size -= temp;
++	next += temp;
++
++	temp = dbg_intr_buf(scratch, sizeof(scratch), label,
++			fotg210_readl(fotg210, &fotg210->regs->intr_enable));
++	temp = scnprintf(next, size, fmt, temp, scratch);
++	size -= temp;
++	next += temp;
++
++	temp = scnprintf(next, size, "uframe %04x\n",
++			fotg210_read_frame_index(fotg210));
++	size -= temp;
++	next += temp;
++
++	if (fotg210->async_unlink) {
++		temp = scnprintf(next, size, "async unlink qh %p\n",
++				fotg210->async_unlink);
++		size -= temp;
++		next += temp;
++	}
++
++#ifdef FOTG210_STATS
++	temp = scnprintf(next, size,
++		"irq normal %ld err %ld iaa %ld(lost %ld)\n",
++		fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa,
++		fotg210->stats.lost_iaa);
++	size -= temp;
++	next += temp;
++
++	temp = scnprintf(next, size, "complete %ld unlink %ld\n",
++		fotg210->stats.complete, fotg210->stats.unlink);
++	size -= temp;
++	next += temp;
++#endif
++
++done:
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++
++	return buf->alloc_size - size;
++}
++
++static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
++				ssize_t (*fill_func)(struct debug_buffer *))
++{
++	struct debug_buffer *buf;
++
++	buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
++
++	if (buf) {
++		buf->bus = bus;
++		buf->fill_func = fill_func;
++		mutex_init(&buf->mutex);
++		buf->alloc_size = PAGE_SIZE;
++	}
++
++	return buf;
++}
++
++static int fill_buffer(struct debug_buffer *buf)
++{
++	int ret = 0;
++
++	if (!buf->output_buf)
++		buf->output_buf = vmalloc(buf->alloc_size);
++
++	if (!buf->output_buf) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	ret = buf->fill_func(buf);
++
++	if (ret >= 0) {
++		buf->count = ret;
++		ret = 0;
++	}
++
++out:
++	return ret;
++}
++
++static ssize_t debug_output(struct file *file, char __user *user_buf,
++			    size_t len, loff_t *offset)
++{
++	struct debug_buffer *buf = file->private_data;
++	int ret = 0;
++
++	mutex_lock(&buf->mutex);
++	if (buf->count == 0) {
++		ret = fill_buffer(buf);
++		if (ret != 0) {
++			mutex_unlock(&buf->mutex);
++			goto out;
++		}
++	}
++	mutex_unlock(&buf->mutex);
++
++	ret = simple_read_from_buffer(user_buf, len, offset,
++				      buf->output_buf, buf->count);
++
++out:
++	return ret;
++
++}
++
++static int debug_close(struct inode *inode, struct file *file)
++{
++	struct debug_buffer *buf = file->private_data;
++
++	if (buf) {
++		vfree(buf->output_buf);
++		kfree(buf);
++	}
++
++	return 0;
++}
++static int debug_async_open(struct inode *inode, struct file *file)
++{
++	file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
++
++	return file->private_data ? 0 : -ENOMEM;
++}
++
++static int debug_periodic_open(struct inode *inode, struct file *file)
++{
++	struct debug_buffer *buf;
++	buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
++	if (!buf)
++		return -ENOMEM;
++
++	buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
++	file->private_data = buf;
++	return 0;
++}
++
++static int debug_registers_open(struct inode *inode, struct file *file)
++{
++	file->private_data = alloc_buffer(inode->i_private,
++					  fill_registers_buffer);
++
++	return file->private_data ? 0 : -ENOMEM;
++}
++
++static inline void create_debug_files(struct fotg210_hcd *fotg210)
++{
++	struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
++
++	fotg210->debug_dir = debugfs_create_dir(bus->bus_name,
++						fotg210_debug_root);
++	if (!fotg210->debug_dir)
++		return;
++
++	if (!debugfs_create_file("async", S_IRUGO, fotg210->debug_dir, bus,
++						&debug_async_fops))
++		goto file_error;
++
++	if (!debugfs_create_file("periodic", S_IRUGO, fotg210->debug_dir, bus,
++						&debug_periodic_fops))
++		goto file_error;
++
++	if (!debugfs_create_file("registers", S_IRUGO, fotg210->debug_dir, bus,
++						    &debug_registers_fops))
++		goto file_error;
++
++	return;
++
++file_error:
++	debugfs_remove_recursive(fotg210->debug_dir);
++}
++
++static inline void remove_debug_files(struct fotg210_hcd *fotg210)
++{
++	debugfs_remove_recursive(fotg210->debug_dir);
++}
++
++#endif /* STUB_DEBUG_FILES */
++/*-------------------------------------------------------------------------*/
++
++/*
++ * handshake - spin reading hc until handshake completes or fails
++ * @ptr: address of hc register to be read
++ * @mask: bits to look at in result of read
++ * @done: value of those bits when handshake succeeds
++ * @usec: timeout in microseconds
++ *
++ * Returns negative errno, or zero on success
++ *
++ * Success happens when the "mask" bits have the specified value (hardware
++ * handshake done).  There are two failure modes:  "usec" have passed (major
++ * hardware flakeout), or the register reads as all-ones (hardware removed).
++ *
++ * That last failure should_only happen in cases like physical cardbus eject
++ * before driver shutdown. But it also seems to be caused by bugs in cardbus
++ * bridge shutdown:  shutting down the bridge before the devices using it.
++ */
++static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr,
++		      u32 mask, u32 done, int usec)
++{
++	u32	result;
++
++	do {
++		result = fotg210_readl(fotg210, ptr);
++		if (result == ~(u32)0)		/* card removed */
++			return -ENODEV;
++		result &= mask;
++		if (result == done)
++			return 0;
++		udelay(1);
++		usec--;
++	} while (usec > 0);
++	return -ETIMEDOUT;
++}
++
++/*
++ * Force HC to halt state from unknown (EHCI spec section 2.3).
++ * Must be called with interrupts enabled and the lock not held.
++ */
++static int fotg210_halt(struct fotg210_hcd *fotg210)
++{
++	u32	temp;
++
++	spin_lock_irq(&fotg210->lock);
++
++	/* disable any irqs left enabled by previous code */
++	fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
++
++	/*
++	 * This routine gets called during probe before fotg210->command
++	 * has been initialized, so we can't rely on its value.
++	 */
++	fotg210->command &= ~CMD_RUN;
++	temp = fotg210_readl(fotg210, &fotg210->regs->command);
++	temp &= ~(CMD_RUN | CMD_IAAD);
++	fotg210_writel(fotg210, temp, &fotg210->regs->command);
++
++	spin_unlock_irq(&fotg210->lock);
++	synchronize_irq(fotg210_to_hcd(fotg210)->irq);
++
++	return handshake(fotg210, &fotg210->regs->status,
++			  STS_HALT, STS_HALT, 16 * 125);
++}
++
++/*
++ * Reset a non-running (STS_HALT == 1) controller.
++ * Must be called with interrupts enabled and the lock not held.
++ */
++static int fotg210_reset(struct fotg210_hcd *fotg210)
++{
++	int	retval;
++	u32	command = fotg210_readl(fotg210, &fotg210->regs->command);
++
++	/* If the EHCI debug controller is active, special care must be
++	 * taken before and after a host controller reset */
++	if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210)))
++		fotg210->debug = NULL;
++
++	command |= CMD_RESET;
++	dbg_cmd(fotg210, "reset", command);
++	fotg210_writel(fotg210, command, &fotg210->regs->command);
++	fotg210->rh_state = FOTG210_RH_HALTED;
++	fotg210->next_statechange = jiffies;
++	retval = handshake(fotg210, &fotg210->regs->command,
++			    CMD_RESET, 0, 250 * 1000);
++
++	if (retval)
++		return retval;
++
++	if (fotg210->debug)
++		dbgp_external_startup(fotg210_to_hcd(fotg210));
++
++	fotg210->port_c_suspend = fotg210->suspended_ports =
++			fotg210->resuming_ports = 0;
++	return retval;
++}
++
++/*
++ * Idle the controller (turn off the schedules).
++ * Must be called with interrupts enabled and the lock not held.
++ */
++static void fotg210_quiesce(struct fotg210_hcd *fotg210)
++{
++	u32	temp;
++
++	if (fotg210->rh_state != FOTG210_RH_RUNNING)
++		return;
++
++	/* wait for any schedule enables/disables to take effect */
++	temp = (fotg210->command << 10) & (STS_ASS | STS_PSS);
++	handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp,
++		  16 * 125);
++
++	/* then disable anything that's still active */
++	spin_lock_irq(&fotg210->lock);
++	fotg210->command &= ~(CMD_ASE | CMD_PSE);
++	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
++	spin_unlock_irq(&fotg210->lock);
++
++	/* hardware can take 16 microframes to turn off ... */
++	handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0,
++		  16 * 125);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void end_unlink_async(struct fotg210_hcd *fotg210);
++static void unlink_empty_async(struct fotg210_hcd *fotg210);
++static void fotg210_work(struct fotg210_hcd *fotg210);
++static void start_unlink_intr(struct fotg210_hcd *fotg210,
++			      struct fotg210_qh *qh);
++static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
++
++/*-------------------------------------------------------------------------*/
++
++/* Set a bit in the USBCMD register */
++static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit)
++{
++	fotg210->command |= bit;
++	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
++
++	/* unblock posted write */
++	fotg210_readl(fotg210, &fotg210->regs->command);
++}
++
++/* Clear a bit in the USBCMD register */
++static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit)
++{
++	fotg210->command &= ~bit;
++	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
++
++	/* unblock posted write */
++	fotg210_readl(fotg210, &fotg210->regs->command);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * EHCI timer support...  Now using hrtimers.
++ *
++ * Lots of different events are triggered from fotg210->hrtimer.  Whenever
++ * the timer routine runs, it checks each possible event; events that are
++ * currently enabled and whose expiration time has passed get handled.
++ * The set of enabled events is stored as a collection of bitflags in
++ * fotg210->enabled_hrtimer_events, and they are numbered in order of
++ * increasing delay values (ranging between 1 ms and 100 ms).
++ *
++ * Rather than implementing a sorted list or tree of all pending events,
++ * we keep track only of the lowest-numbered pending event, in
++ * fotg210->next_hrtimer_event.  Whenever fotg210->hrtimer gets restarted, its
++ * expiration time is set to the timeout value for this event.
++ *
++ * As a result, events might not get handled right away; the actual delay
++ * could be anywhere up to twice the requested delay.  This doesn't
++ * matter, because none of the events are especially time-critical.  The
++ * ones that matter most all have a delay of 1 ms, so they will be
++ * handled after 2 ms at most, which is okay.  In addition to this, we
++ * allow for an expiration range of 1 ms.
++ */
++
++/*
++ * Delay lengths for the hrtimer event types.
++ * Keep this list sorted by delay length, in the same order as
++ * the event types indexed by enum fotg210_hrtimer_event in fotg210.h.
++ */
++static unsigned event_delays_ns[] = {
++	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_ASS */
++	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_PSS */
++	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_DEAD */
++	1125 * NSEC_PER_USEC,	/* FOTG210_HRTIMER_UNLINK_INTR */
++	2 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_FREE_ITDS */
++	6 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_ASYNC_UNLINKS */
++	10 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_IAA_WATCHDOG */
++	10 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_DISABLE_PERIODIC */
++	15 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_DISABLE_ASYNC */
++	100 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_IO_WATCHDOG */
++};
++
++/* Enable a pending hrtimer event */
++static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event,
++		bool resched)
++{
++	ktime_t		*timeout = &fotg210->hr_timeouts[event];
++
++	if (resched)
++		*timeout = ktime_add(ktime_get(),
++				ktime_set(0, event_delays_ns[event]));
++	fotg210->enabled_hrtimer_events |= (1 << event);
++
++	/* Track only the lowest-numbered pending event */
++	if (event < fotg210->next_hrtimer_event) {
++		fotg210->next_hrtimer_event = event;
++		hrtimer_start_range_ns(&fotg210->hrtimer, *timeout,
++				NSEC_PER_MSEC, HRTIMER_MODE_ABS);
++	}
++}
++
++
++/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
++static void fotg210_poll_ASS(struct fotg210_hcd *fotg210)
++{
++	unsigned	actual, want;
++
++	/* Don't enable anything if the controller isn't running (e.g., died) */
++	if (fotg210->rh_state != FOTG210_RH_RUNNING)
++		return;
++
++	want = (fotg210->command & CMD_ASE) ? STS_ASS : 0;
++	actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS;
++
++	if (want != actual) {
++
++		/* Poll again later, but give up after about 20 ms */
++		if (fotg210->ASS_poll_count++ < 20) {
++			fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS,
++					     true);
++			return;
++		}
++		fotg210_warn(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n",
++				want, actual);
++	}
++	fotg210->ASS_poll_count = 0;
++
++	/* The status is up-to-date; restart or stop the schedule as needed */
++	if (want == 0) {	/* Stopped */
++		if (fotg210->async_count > 0)
++			fotg210_set_command_bit(fotg210, CMD_ASE);
++
++	} else {		/* Running */
++		if (fotg210->async_count == 0) {
++
++			/* Turn off the schedule after a while */
++			fotg210_enable_event(fotg210,
++					     FOTG210_HRTIMER_DISABLE_ASYNC,
++					true);
++		}
++	}
++}
++
++/* Turn off the async schedule after a brief delay */
++static void fotg210_disable_ASE(struct fotg210_hcd *fotg210)
++{
++	fotg210_clear_command_bit(fotg210, CMD_ASE);
++}
++
++
++/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
++static void fotg210_poll_PSS(struct fotg210_hcd *fotg210)
++{
++	unsigned	actual, want;
++
++	/* Don't do anything if the controller isn't running (e.g., died) */
++	if (fotg210->rh_state != FOTG210_RH_RUNNING)
++		return;
++
++	want = (fotg210->command & CMD_PSE) ? STS_PSS : 0;
++	actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS;
++
++	if (want != actual) {
++
++		/* Poll again later, but give up after about 20 ms */
++		if (fotg210->PSS_poll_count++ < 20) {
++			fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS,
++					     true);
++			return;
++		}
++		fotg210_warn(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
++				want, actual);
++	}
++	fotg210->PSS_poll_count = 0;
++
++	/* The status is up-to-date; restart or stop the schedule as needed */
++	if (want == 0) {	/* Stopped */
++		if (fotg210->periodic_count > 0)
++			fotg210_set_command_bit(fotg210, CMD_PSE);
++
++	} else {		/* Running */
++		if (fotg210->periodic_count == 0) {
++
++			/* Turn off the schedule after a while */
++			fotg210_enable_event(fotg210,
++					     FOTG210_HRTIMER_DISABLE_PERIODIC,
++					true);
++		}
++	}
++}
++
++/* Turn off the periodic schedule after a brief delay */
++static void fotg210_disable_PSE(struct fotg210_hcd *fotg210)
++{
++	fotg210_clear_command_bit(fotg210, CMD_PSE);
++}
++
++
++/* Poll the STS_HALT status bit; see when a dead controller stops */
++static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210)
++{
++	if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) {
++
++		/* Give up after a few milliseconds */
++		if (fotg210->died_poll_count++ < 5) {
++			/* Try again later */
++			fotg210_enable_event(fotg210,
++					     FOTG210_HRTIMER_POLL_DEAD, true);
++			return;
++		}
++		fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n");
++	}
++
++	/* Clean up the mess */
++	fotg210->rh_state = FOTG210_RH_HALTED;
++	fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
++	fotg210_work(fotg210);
++	end_unlink_async(fotg210);
++
++	/* Not in process context, so don't try to reset the controller */
++}
++
++
++/* Handle unlinked interrupt QHs once they are gone from the hardware */
++static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210)
++{
++	bool		stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
++
++	/*
++	 * Process all the QHs on the intr_unlink list that were added
++	 * before the current unlink cycle began.  The list is in
++	 * temporal order, so stop when we reach the first entry in the
++	 * current cycle.  But if the root hub isn't running then
++	 * process all the QHs on the list.
++	 */
++	fotg210->intr_unlinking = true;
++	while (fotg210->intr_unlink) {
++		struct fotg210_qh	*qh = fotg210->intr_unlink;
++
++		if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle)
++			break;
++		fotg210->intr_unlink = qh->unlink_next;
++		qh->unlink_next = NULL;
++		end_unlink_intr(fotg210, qh);
++	}
++
++	/* Handle remaining entries later */
++	if (fotg210->intr_unlink) {
++		fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
++				     true);
++		++fotg210->intr_unlink_cycle;
++	}
++	fotg210->intr_unlinking = false;
++}
++
++
++/* Start another free-iTDs/siTDs cycle */
++static void start_free_itds(struct fotg210_hcd *fotg210)
++{
++	if (!(fotg210->enabled_hrtimer_events &
++			BIT(FOTG210_HRTIMER_FREE_ITDS))) {
++		fotg210->last_itd_to_free = list_entry(
++				fotg210->cached_itd_list.prev,
++				struct fotg210_itd, itd_list);
++		fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true);
++	}
++}
++
++/* Wait for controller to stop using old iTDs and siTDs */
++static void end_free_itds(struct fotg210_hcd *fotg210)
++{
++	struct fotg210_itd		*itd, *n;
++
++	if (fotg210->rh_state < FOTG210_RH_RUNNING)
++		fotg210->last_itd_to_free = NULL;
++
++	list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) {
++		list_del(&itd->itd_list);
++		dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma);
++		if (itd == fotg210->last_itd_to_free)
++			break;
++	}
++
++	if (!list_empty(&fotg210->cached_itd_list))
++		start_free_itds(fotg210);
++}
++
++
++/* Handle lost (or very late) IAA interrupts */
++static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)
++{
++	if (fotg210->rh_state != FOTG210_RH_RUNNING)
++		return;
++
++	/*
++	 * Lost IAA irqs wedge things badly; seen first with a vt8235.
++	 * So we need this watchdog, but must protect it against both
++	 * (a) SMP races against real IAA firing and retriggering, and
++	 * (b) clean HC shutdown, when IAA watchdog was pending.
++	 */
++	if (fotg210->async_iaa) {
++		u32 cmd, status;
++
++		/* If we get here, IAA is *REALLY* late.  It's barely
++		 * conceivable that the system is so busy that CMD_IAAD
++		 * is still legitimately set, so let's be sure it's
++		 * clear before we read STS_IAA.  (The HC should clear
++		 * CMD_IAAD when it sets STS_IAA.)
++		 */
++		cmd = fotg210_readl(fotg210, &fotg210->regs->command);
++
++		/*
++		 * If IAA is set here it either legitimately triggered
++		 * after the watchdog timer expired (_way_ late, so we'll
++		 * still count it as lost) ... or a silicon erratum:
++		 * - VIA seems to set IAA without triggering the IRQ;
++		 * - IAAD potentially cleared without setting IAA.
++		 */
++		status = fotg210_readl(fotg210, &fotg210->regs->status);
++		if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
++			COUNT(fotg210->stats.lost_iaa);
++			fotg210_writel(fotg210, STS_IAA,
++				       &fotg210->regs->status);
++		}
++
++		fotg210_vdbg(fotg210, "IAA watchdog: status %x cmd %x\n",
++				status, cmd);
++		end_unlink_async(fotg210);
++	}
++}
++
++
++/* Enable the I/O watchdog, if appropriate */
++static void turn_on_io_watchdog(struct fotg210_hcd *fotg210)
++{
++	/* Not needed if the controller isn't running or it's already enabled */
++	if (fotg210->rh_state != FOTG210_RH_RUNNING ||
++			(fotg210->enabled_hrtimer_events &
++				BIT(FOTG210_HRTIMER_IO_WATCHDOG)))
++		return;
++
++	/*
++	 * Isochronous transfers always need the watchdog.
++	 * For other sorts we use it only if the flag is set.
++	 */
++	if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog &&
++			fotg210->async_count + fotg210->intr_count > 0))
++		fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG,
++				     true);
++}
++
++
++/*
++ * Handler functions for the hrtimer event types.
++ * Keep this array in the same order as the event types indexed by
++ * enum fotg210_hrtimer_event in fotg210.h.
++ */
++static void (*event_handlers[])(struct fotg210_hcd *) = {
++	fotg210_poll_ASS,			/* FOTG210_HRTIMER_POLL_ASS */
++	fotg210_poll_PSS,			/* FOTG210_HRTIMER_POLL_PSS */
++	fotg210_handle_controller_death,	/* FOTG210_HRTIMER_POLL_DEAD */
++	fotg210_handle_intr_unlinks,	/* FOTG210_HRTIMER_UNLINK_INTR */
++	end_free_itds,			/* FOTG210_HRTIMER_FREE_ITDS */
++	unlink_empty_async,		/* FOTG210_HRTIMER_ASYNC_UNLINKS */
++	fotg210_iaa_watchdog,		/* FOTG210_HRTIMER_IAA_WATCHDOG */
++	fotg210_disable_PSE,		/* FOTG210_HRTIMER_DISABLE_PERIODIC */
++	fotg210_disable_ASE,		/* FOTG210_HRTIMER_DISABLE_ASYNC */
++	fotg210_work,			/* FOTG210_HRTIMER_IO_WATCHDOG */
++};
++
++static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t)
++{
++	struct fotg210_hcd *fotg210 =
++			container_of(t, struct fotg210_hcd, hrtimer);
++	ktime_t		now;
++	unsigned long	events;
++	unsigned long	flags;
++	unsigned	e;
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++
++	events = fotg210->enabled_hrtimer_events;
++	fotg210->enabled_hrtimer_events = 0;
++	fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
++
++	/*
++	 * Check each pending event.  If its time has expired, handle
++	 * the event; otherwise re-enable it.
++	 */
++	now = ktime_get();
++	for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) {
++		if (now.tv64 >= fotg210->hr_timeouts[e].tv64)
++			event_handlers[e](fotg210);
++		else
++			fotg210_enable_event(fotg210, e, false);
++	}
++
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	return HRTIMER_NORESTART;
++}
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef	CONFIG_PM
++
++static int fotg210_port_change(struct fotg210_hcd *fotg210)
++{
++	/* First check if the controller indicates a change event */
++
++	if (fotg210_readl(fotg210, &fotg210->regs->status) & STS_PCD)
++		return 1;
++
++	/*
++	 * Not all controllers appear to update this while going from D3 to D0,
++	 * so check the individual port status registers as well
++	 */
++
++	if (fotg210_readl(fotg210, &fotg210->regs->port_status) & PORT_CSC)
++		return 1;
++
++	return 0;
++}
++
++static void fotg210_adjust_port_wakeup_flags(struct fotg210_hcd *fotg210,
++		bool suspending, bool do_wakeup)
++{
++	u32 __iomem	*reg = &fotg210->regs->port_status;
++	u32		t1;
++
++	/* If remote wakeup is enabled for the root hub but disabled
++	 * for the controller, we must adjust all the port wakeup flags
++	 * when the controller is suspended or resumed.  In all other
++	 * cases they don't need to be changed.
++	 */
++	if (!fotg210_to_hcd(fotg210)->self.root_hub->do_remote_wakeup || do_wakeup)
++		return;
++
++	spin_lock_irq(&fotg210->lock);
++
++	t1 = fotg210_readl(fotg210, reg) & ~PORT_RWC_BITS;
++	fotg210_writel(fotg210, t1, reg);
++
++	/* Does the root hub have a port wakeup pending? */
++	if (!suspending && fotg210_port_change(fotg210))
++		usb_hcd_resume_root_hub(fotg210_to_hcd(fotg210));
++
++	spin_unlock_irq(&fotg210->lock);
++}
++
++static int fotg210_bus_suspend (struct usb_hcd *hcd)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210 (hcd);
++	u32 __iomem	*reg = &fotg210->regs->port_status;
++	int			mask;
++	int			changed;
++	u32		t1, t2;
++
++	fotg210_info(fotg210, "suspend root hub\n");
++
++	if (time_before (jiffies, fotg210->next_statechange))
++		msleep(5);
++
++	/* stop the schedules */
++	fotg210_quiesce(fotg210);
++
++	spin_lock_irq (&fotg210->lock);
++	if (fotg210->rh_state < FOTG210_RH_RUNNING)
++		goto done;
++
++	/* Once the controller is stopped, port resumes that are already
++	 * in progress won't complete.  Hence if remote wakeup is enabled
++	 * for the root hub and any ports are in the middle of a resume or
++	 * remote wakeup, we must fail the suspend.
++	 */
++	if (hcd->self.root_hub->do_remote_wakeup) {
++		if (fotg210->resuming_ports) {
++			spin_unlock_irq(&fotg210->lock);
++			fotg210_err(fotg210, "suspend failed because a port is resuming\n");
++			return -EBUSY;
++		}
++	}
++
++	/* Unlike other USB host controller types, EHCI doesn't have
++	 * any notion of "global" or bus-wide suspend.  The driver has
++	 * to manually suspend all the active unsuspended ports, and
++	 * then manually resume them in the bus_resume() routine.
++	 */
++	fotg210->bus_suspended = 0;
++	changed = 0;
++
++	t1 = fotg210_readl(fotg210, reg) & ~PORT_RWC_BITS;
++	t2 = t1;
++
++	/* keep track of which ports we suspend */
++	if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
++		t2 |= PORT_SUSPEND;
++		set_bit(0, &fotg210->bus_suspended);
++	}
++
++	if (t1 != t2) {
++		fotg210_info (fotg210, "port %d, %08x -> %08x\n",
++			1, t1, t2);
++		fotg210_writel(fotg210, t2, reg);
++		changed = 1;
++	}
++	spin_unlock_irq(&fotg210->lock);
++
++	/* Apparently some devices need a >= 1-uframe delay here */
++	if (fotg210->bus_suspended)
++		udelay(150);
++
++	/* turn off now-idle HC */
++	fotg210_halt (fotg210);
++
++	spin_lock_irq(&fotg210->lock);
++	if (fotg210->enabled_hrtimer_events & BIT(FOTG210_HRTIMER_POLL_DEAD))
++		fotg210_handle_controller_death(fotg210);
++	if (fotg210->rh_state != FOTG210_RH_RUNNING)
++		goto done;
++	fotg210->rh_state = FOTG210_RH_SUSPENDED;
++
++	end_unlink_async(fotg210);
++	unlink_empty_async(fotg210);
++	fotg210_handle_intr_unlinks(fotg210);
++	end_free_itds(fotg210);
++
++	/* allow remote wakeup */
++	mask = INTR_MASK;
++	if (!hcd->self.root_hub->do_remote_wakeup)
++		mask &= ~STS_PCD;
++	fotg210_writel(fotg210, mask, &fotg210->regs->intr_enable);
++	fotg210_readl(fotg210, &fotg210->regs->intr_enable);
++
++ done:
++	fotg210->next_statechange = jiffies + msecs_to_jiffies(10);
++	fotg210->enabled_hrtimer_events = 0;
++	fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
++	spin_unlock_irq (&fotg210->lock);
++
++	hrtimer_cancel(&fotg210->hrtimer);
++	return 0;
++}
++
++
++/* caller has locked the root hub, and should reset/reinit on error */
++static int fotg210_bus_resume (struct usb_hcd *hcd)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210 (hcd);
++	u32			temp;
++	u32			power_okay;
++	unsigned long		resume_needed = 0;
++
++	if (time_before (jiffies, fotg210->next_statechange))
++		msleep(5);
++	spin_lock_irq (&fotg210->lock);
++	if (!HCD_HW_ACCESSIBLE(hcd) || fotg210->shutdown)
++		goto shutdown;
++
++	if (unlikely(fotg210->debug)) {
++		if (!dbgp_reset_prep(hcd))
++			fotg210->debug = NULL;
++		else
++			dbgp_external_startup(hcd);
++	}
++
++	/* Ideally and we've got a real resume here, and no port's power
++	 * was lost.  (For PCI, that means Vaux was maintained.)  But we
++	 * could instead be restoring a swsusp snapshot -- so that BIOS was
++	 * the last user of the controller, not reset/pm hardware keeping
++	 * state we gave to it.
++	 */
++	power_okay = fotg210_readl(fotg210, &fotg210->regs->intr_enable);
++	fotg210_info(fotg210, "resume root hub%s\n",
++			power_okay ? "" : " after power loss");
++
++	/* at least some APM implementations will try to deliver
++	 * IRQs right away, so delay them until we're ready.
++	 */
++	fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
++
++	/* re-init operational registers */
++	fotg210_writel(fotg210, fotg210->periodic_dma, &fotg210->regs->frame_list);
++	fotg210_writel(fotg210, (u32) fotg210->async->qh_dma, &fotg210->regs->async_next);
++
++	/* restore CMD_RUN, framelist size, and irq threshold */
++	fotg210->command |= CMD_RUN;
++	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
++	fotg210->rh_state = FOTG210_RH_RUNNING;
++
++	/* Some controller/firmware combinations need a delay during which
++	 * they set up the port statuses.  See Bugzilla #8190. */
++	spin_unlock_irq(&fotg210->lock);
++	msleep(8);
++	spin_lock_irq(&fotg210->lock);
++	if (fotg210->shutdown)
++		goto shutdown;
++
++	/* manually resume the ports we suspended during bus_suspend() */
++	temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
++	temp &= ~PORT_RWC_BITS;
++	if (test_bit(0, &fotg210->bus_suspended) &&
++			(temp & PORT_SUSPEND)) {
++		temp |= PORT_RESUME;
++		set_bit(0, &resume_needed);
++	}
++	fotg210_writel(fotg210, temp, &fotg210->regs->port_status);
++
++	/* msleep for 20ms only if code is trying to resume port */
++	if (resume_needed) {
++		spin_unlock_irq(&fotg210->lock);
++		msleep(20);
++		spin_lock_irq(&fotg210->lock);
++		if (fotg210->shutdown)
++			goto shutdown;
++	}
++
++	temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
++	if (test_bit(0, &resume_needed)) {
++		temp &= ~(PORT_RWC_BITS | PORT_RESUME);
++		fotg210_writel(fotg210, temp, &fotg210->regs->port_status);
++		fotg210_info (fotg210, "resumed port %d\n", 1);
++	}
++
++	fotg210->next_statechange = jiffies + msecs_to_jiffies(5);
++	spin_unlock_irq(&fotg210->lock);
++
++	/* Now we can safely re-enable irqs */
++	spin_lock_irq(&fotg210->lock);
++	if (fotg210->shutdown)
++		goto shutdown;
++	fotg210_writel(fotg210, INTR_MASK, &fotg210->regs->intr_enable);
++	(void) fotg210_readl(fotg210, &fotg210->regs->intr_enable);
++	spin_unlock_irq(&fotg210->lock);
++
++	return 0;
++
++ shutdown:
++	spin_unlock_irq(&fotg210->lock);
++	return -ESHUTDOWN;
++}
++
++#else
++
++#define fotg210_bus_suspend	NULL
++#define fotg210_bus_resume	NULL
++
++#endif	/* CONFIG_PM */
++
++/*-------------------------------------------------------------------------*/
++
++static int check_reset_complete(
++	struct fotg210_hcd	*fotg210,
++	int		index,
++	u32 __iomem	*status_reg,
++	int		port_status
++) {
++	if (!(port_status & PORT_CONNECT))
++		return port_status;
++
++	/* if reset finished and it's still not enabled -- handoff */
++	if (!(port_status & PORT_PE)) {
++		/* with integrated TT, there's nobody to hand it to! */
++		fotg210_err(fotg210,
++			"Failed to enable port %d on root hub TT\n",
++			index+1);
++		return port_status;
++	} else {
++		fotg210_info(fotg210, "port %d reset complete, port enabled\n",
++			index + 1);
++	}
++
++	return port_status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++
++/* build "status change" packet (one or two bytes) from HC registers */
++
++static int
++fotg210_hub_status_data(struct usb_hcd *hcd, char *buf)
++{
++	struct fotg210_hcd	*fotg210 = hcd_to_fotg210(hcd);
++	u32		temp, status;
++	u32		mask;
++	int		retval = 1;
++	unsigned long	flags;
++
++	/* init status to no-changes */
++	buf[0] = 0;
++
++	/* Inform the core about resumes-in-progress by returning
++	 * a non-zero value even if there are no status changes.
++	 */
++	status = fotg210->resuming_ports;
++
++	mask = PORT_CSC | PORT_PEC;
++	/* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */
++
++	/* no hub change reports (bit 0) for now (power, ...) */
++
++	/* port N changes (bit N)? */
++	spin_lock_irqsave(&fotg210->lock, flags);
++
++	temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
++
++	/*
++	 * Return status information even for ports with OWNER set.
++	 * Otherwise khubd wouldn't see the disconnect event when a
++	 * high-speed device is switched over to the companion
++	 * controller by the user.
++	 */
++
++	if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend)
++			|| (fotg210->reset_done[0] && time_after_eq(
++				jiffies, fotg210->reset_done[0]))) {
++		buf[0] |= 1 << 1;
++		status = STS_PCD;
++	}
++	/* FIXME autosuspend idle root hubs */
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	return status ? retval : 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void
++fotg210_hub_descriptor(
++	struct fotg210_hcd		*fotg210,
++	struct usb_hub_descriptor	*desc
++) {
++	int		ports = HCS_N_PORTS(fotg210->hcs_params);
++	u16		temp;
++
++	desc->bDescriptorType = 0x29;
++	desc->bPwrOn2PwrGood = 10;	/* fotg210 1.0, 2.3.9 says 20ms max */
++	desc->bHubContrCurrent = 0;
++
++	desc->bNbrPorts = ports;
++	temp = 1 + (ports / 8);
++	desc->bDescLength = 7 + 2 * temp;
++
++	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
++	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
++	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
++
++	temp = 0x0008;		/* per-port overcurrent reporting */
++	temp |= 0x0002;		/* no power switching */
++	desc->wHubCharacteristics = cpu_to_le16(temp);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int fotg210_hub_control(
++	struct usb_hcd	*hcd,
++	u16		typeReq,
++	u16		wValue,
++	u16		wIndex,
++	char		*buf,
++	u16		wLength
++) {
++	struct fotg210_hcd	*fotg210 = hcd_to_fotg210(hcd);
++	int		ports = HCS_N_PORTS(fotg210->hcs_params);
++	u32 __iomem	*status_reg = &fotg210->regs->port_status;
++	u32		temp, temp1, status;
++	unsigned long	flags;
++	int		retval = 0;
++	unsigned	selector;
++
++	/*
++	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
++	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
++	 * (track current state ourselves) ... blink for diagnostics,
++	 * power, "this is the one", etc.  EHCI spec supports this.
++	 */
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++	switch (typeReq) {
++	case ClearHubFeature:
++		switch (wValue) {
++		case C_HUB_LOCAL_POWER:
++		case C_HUB_OVER_CURRENT:
++			/* no hub-wide feature/status flags */
++			break;
++		default:
++			goto error;
++		}
++		break;
++	case ClearPortFeature:
++		if (!wIndex || wIndex > ports)
++			goto error;
++		wIndex--;
++		temp = fotg210_readl(fotg210, status_reg);
++		temp &= ~PORT_RWC_BITS;
++
++		/*
++		 * Even if OWNER is set, so the port is owned by the
++		 * companion controller, khubd needs to be able to clear
++		 * the port-change status bits (especially
++		 * USB_PORT_STAT_C_CONNECTION).
++		 */
++
++		switch (wValue) {
++		case USB_PORT_FEAT_ENABLE:
++			fotg210_writel(fotg210, temp & ~PORT_PE, status_reg);
++			break;
++		case USB_PORT_FEAT_C_ENABLE:
++			fotg210_writel(fotg210, temp | PORT_PEC, status_reg);
++			break;
++		case USB_PORT_FEAT_SUSPEND:
++			if (temp & PORT_RESET)
++				goto error;
++			if (!(temp & PORT_SUSPEND))
++				break;
++			if ((temp & PORT_PE) == 0)
++				goto error;
++
++			/* resume signaling for 20 msec */
++			fotg210_writel(fotg210, temp | PORT_RESUME, status_reg);
++			fotg210->reset_done[wIndex] = jiffies
++					+ msecs_to_jiffies(20);
++			break;
++		case USB_PORT_FEAT_C_SUSPEND:
++			clear_bit(wIndex, &fotg210->port_c_suspend);
++			break;
++		case USB_PORT_FEAT_POWER:
++			break;
++		case USB_PORT_FEAT_C_CONNECTION:
++			fotg210_writel(fotg210, temp | PORT_CSC, status_reg);
++			break;
++		case USB_PORT_FEAT_C_OVER_CURRENT:
++			fotg210_writel(fotg210, temp | OTGISR_OVC,
++				       &fotg210->regs->otgisr);
++			break;
++		case USB_PORT_FEAT_C_RESET:
++			/* GetPortStatus clears reset */
++			break;
++		default:
++			goto error;
++		}
++		fotg210_readl(fotg210, &fotg210->regs->command);
++		break;
++	case GetHubDescriptor:
++		fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *)
++			buf);
++		break;
++	case GetHubStatus:
++		/* no hub-wide feature/status flags */
++		memset(buf, 0, 4);
++		/*cpu_to_le32s ((u32 *) buf); */
++		break;
++	case GetPortStatus:
++		if (!wIndex || wIndex > ports)
++			goto error;
++		wIndex--;
++		status = 0;
++		temp = fotg210_readl(fotg210, status_reg);
++
++		/* wPortChange bits */
++		if (temp & PORT_CSC)
++			status |= USB_PORT_STAT_C_CONNECTION << 16;
++		if (temp & PORT_PEC)
++			status |= USB_PORT_STAT_C_ENABLE << 16;
++
++		temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
++		if (temp1 & OTGISR_OVC)
++			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
++
++		/* whoever resumes must GetPortStatus to complete it!! */
++		if (temp & PORT_RESUME) {
++
++			/* Remote Wakeup received? */
++			if (!fotg210->reset_done[wIndex]) {
++				/* resume signaling for 20 msec */
++				fotg210->reset_done[wIndex] = jiffies
++						+ msecs_to_jiffies(20);
++				/* check the port again */
++				mod_timer(&fotg210_to_hcd(fotg210)->rh_timer,
++						fotg210->reset_done[wIndex]);
++			}
++
++			/* resume completed? */
++			else if (time_after_eq(jiffies,
++					fotg210->reset_done[wIndex])) {
++				clear_bit(wIndex, &fotg210->suspended_ports);
++				set_bit(wIndex, &fotg210->port_c_suspend);
++				fotg210->reset_done[wIndex] = 0;
++
++				/* stop resume signaling */
++				temp = fotg210_readl(fotg210, status_reg);
++				fotg210_writel(fotg210,
++					temp & ~(PORT_RWC_BITS | PORT_RESUME),
++					status_reg);
++				clear_bit(wIndex, &fotg210->resuming_ports);
++				retval = handshake(fotg210, status_reg,
++					   PORT_RESUME, 0, 2000 /* 2msec */);
++				if (retval != 0) {
++					fotg210_err(fotg210,
++						"port %d resume error %d\n",
++						wIndex + 1, retval);
++					goto error;
++				}
++				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
++			}
++		}
++
++		/* whoever resets must GetPortStatus to complete it!! */
++		if ((temp & PORT_RESET)
++				&& time_after_eq(jiffies,
++					fotg210->reset_done[wIndex])) {
++			status |= USB_PORT_STAT_C_RESET << 16;
++			fotg210->reset_done[wIndex] = 0;
++			clear_bit(wIndex, &fotg210->resuming_ports);
++
++			/* force reset to complete */
++			fotg210_writel(fotg210,
++				       temp & ~(PORT_RWC_BITS | PORT_RESET),
++					status_reg);
++			/* REVISIT:  some hardware needs 550+ usec to clear
++			 * this bit; seems too long to spin routinely...
++			 */
++			retval = handshake(fotg210, status_reg,
++					PORT_RESET, 0, 1000);
++			if (retval != 0) {
++				fotg210_err(fotg210, "port %d reset error %d\n",
++					wIndex + 1, retval);
++				goto error;
++			}
++
++			/* see what we found out */
++			temp = check_reset_complete(fotg210, wIndex, status_reg,
++					fotg210_readl(fotg210, status_reg));
++		}
++
++		if (!(temp & (PORT_RESUME|PORT_RESET))) {
++			fotg210->reset_done[wIndex] = 0;
++			clear_bit(wIndex, &fotg210->resuming_ports);
++		}
++
++		/* transfer dedicated ports to the companion hc */
++		if ((temp & PORT_CONNECT) &&
++				test_bit(wIndex, &fotg210->companion_ports)) {
++			temp &= ~PORT_RWC_BITS;
++			fotg210_writel(fotg210, temp, status_reg);
++			fotg210_dbg(fotg210, "port %d --> companion\n",
++				    wIndex + 1);
++			temp = fotg210_readl(fotg210, status_reg);
++		}
++
++		/*
++		 * Even if OWNER is set, there's no harm letting khubd
++		 * see the wPortStatus values (they should all be 0 except
++		 * for PORT_POWER anyway).
++		 */
++
++		if (temp & PORT_CONNECT) {
++			status |= USB_PORT_STAT_CONNECTION;
++			status |= fotg210_port_speed(fotg210, temp);
++		}
++		if (temp & PORT_PE)
++			status |= USB_PORT_STAT_ENABLE;
++
++		/* maybe the port was unsuspended without our knowledge */
++		if (temp & (PORT_SUSPEND|PORT_RESUME)) {
++			status |= USB_PORT_STAT_SUSPEND;
++		} else if (test_bit(wIndex, &fotg210->suspended_ports)) {
++			clear_bit(wIndex, &fotg210->suspended_ports);
++			clear_bit(wIndex, &fotg210->resuming_ports);
++			fotg210->reset_done[wIndex] = 0;
++			if (temp & PORT_PE)
++				set_bit(wIndex, &fotg210->port_c_suspend);
++		}
++
++		temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
++		if (temp1 & OTGISR_OVC)
++			status |= USB_PORT_STAT_OVERCURRENT;
++		if (temp & PORT_RESET)
++			status |= USB_PORT_STAT_RESET;
++		if (test_bit(wIndex, &fotg210->port_c_suspend))
++			status |= USB_PORT_STAT_C_SUSPEND << 16;
++
++#ifndef	VERBOSE_DEBUG
++	if (status & ~0xffff)	/* only if wPortChange is interesting */
++#endif
++		dbg_port(fotg210, "GetStatus", wIndex + 1, temp);
++		put_unaligned_le32(status, buf);
++		break;
++	case SetHubFeature:
++		switch (wValue) {
++		case C_HUB_LOCAL_POWER:
++		case C_HUB_OVER_CURRENT:
++			/* no hub-wide feature/status flags */
++			break;
++		default:
++			goto error;
++		}
++		break;
++	case SetPortFeature:
++		selector = wIndex >> 8;
++		wIndex &= 0xff;
++
++		if (!wIndex || wIndex > ports)
++			goto error;
++		wIndex--;
++		temp = fotg210_readl(fotg210, status_reg);
++		temp &= ~PORT_RWC_BITS;
++		switch (wValue) {
++		case USB_PORT_FEAT_SUSPEND:
++			if ((temp & PORT_PE) == 0
++					|| (temp & PORT_RESET) != 0)
++				goto error;
++
++			/* After above check the port must be connected.
++			 * Set appropriate bit thus could put phy into low power
++			 * mode if we have hostpc feature
++			 */
++			fotg210_writel(fotg210, temp | PORT_SUSPEND,
++				       status_reg);
++			set_bit(wIndex, &fotg210->suspended_ports);
++			break;
++		case USB_PORT_FEAT_POWER:
++			break;
++		case USB_PORT_FEAT_RESET:
++			if (temp & PORT_RESUME)
++				goto error;
++			/* line status bits may report this as low speed,
++			 * which can be fine if this root hub has a
++			 * transaction translator built in.
++			 */
++			fotg210_vdbg(fotg210, "port %d reset\n", wIndex + 1);
++			temp |= PORT_RESET;
++			temp &= ~PORT_PE;
++
++			/*
++			 * caller must wait, then call GetPortStatus
++			 * usb 2.0 spec says 50 ms resets on root
++			 */
++			fotg210->reset_done[wIndex] = jiffies
++					+ msecs_to_jiffies(50);
++			fotg210_writel(fotg210, temp, status_reg);
++			break;
++
++		/* For downstream facing ports (these):  one hub port is put
++		 * into test mode according to USB2 11.24.2.13, then the hub
++		 * must be reset (which for root hub now means rmmod+modprobe,
++		 * or else system reboot).  See EHCI 2.3.9 and 4.14 for info
++		 * about the EHCI-specific stuff.
++		 */
++		case USB_PORT_FEAT_TEST:
++			if (!selector || selector > 5)
++				goto error;
++			spin_unlock_irqrestore(&fotg210->lock, flags);
++			fotg210_quiesce(fotg210);
++			spin_lock_irqsave(&fotg210->lock, flags);
++
++			/* Put all enabled ports into suspend */
++			temp = fotg210_readl(fotg210, status_reg) &
++				~PORT_RWC_BITS;
++			if (temp & PORT_PE)
++				fotg210_writel(fotg210, temp | PORT_SUSPEND,
++						status_reg);
++
++			spin_unlock_irqrestore(&fotg210->lock, flags);
++			fotg210_halt(fotg210);
++			spin_lock_irqsave(&fotg210->lock, flags);
++
++			temp = fotg210_readl(fotg210, status_reg);
++			temp |= selector << 16;
++			fotg210_writel(fotg210, temp, status_reg);
++			break;
++
++		default:
++			goto error;
++		}
++		fotg210_readl(fotg210, &fotg210->regs->command);
++		break;
++
++	default:
++error:
++		/* "stall" on error */
++		retval = -EPIPE;
++	}
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	return retval;
++}
++
++static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd,
++		int portnum)
++{
++	return;
++}
++
++static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd,
++		int portnum)
++{
++	return 0;
++}
++/*-------------------------------------------------------------------------*/
++/*
++ * There's basically three types of memory:
++ *	- data used only by the HCD ... kmalloc is fine
++ *	- async and periodic schedules, shared by HC and HCD ... these
++ *	  need to use dma_pool or dma_alloc_coherent
++ *	- driver buffers, read/written by HC ... single shot DMA mapped
++ *
++ * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
++ * No memory seen by this driver is pageable.
++ */
++
++/*-------------------------------------------------------------------------*/
++
++/* Allocate the key transfer structures from the previously allocated pool */
++
++static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210,
++				    struct fotg210_qtd *qtd, dma_addr_t dma)
++{
++	memset(qtd, 0, sizeof(*qtd));
++	qtd->qtd_dma = dma;
++	qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
++	qtd->hw_next = FOTG210_LIST_END(fotg210);
++	qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
++	INIT_LIST_HEAD(&qtd->qtd_list);
++}
++
++static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210,
++					     gfp_t flags)
++{
++	struct fotg210_qtd		*qtd;
++	dma_addr_t		dma;
++
++	qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma);
++	if (qtd != NULL)
++		fotg210_qtd_init(fotg210, qtd, dma);
++
++	return qtd;
++}
++
++static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210,
++				    struct fotg210_qtd *qtd)
++{
++	dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma);
++}
++
++
++static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{
++	/* clean qtds first, and know this is not linked */
++	if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
++		fotg210_err(fotg210, "unused qh not empty!\n");
++		BUG();
++	}
++	if (qh->dummy)
++		fotg210_qtd_free(fotg210, qh->dummy);
++	dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
++	kfree(qh);
++}
++
++static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210,
++					   gfp_t flags)
++{
++	struct fotg210_qh		*qh;
++	dma_addr_t		dma;
++
++	qh = kzalloc(sizeof(*qh), GFP_ATOMIC);
++	if (!qh)
++		goto done;
++	qh->hw = (struct fotg210_qh_hw *)
++		dma_pool_alloc(fotg210->qh_pool, flags, &dma);
++	if (!qh->hw)
++		goto fail;
++	memset(qh->hw, 0, sizeof(*qh->hw));
++	qh->qh_dma = dma;
++	INIT_LIST_HEAD(&qh->qtd_list);
++
++	/* dummy td enables safe urb queuing */
++	qh->dummy = fotg210_qtd_alloc(fotg210, flags);
++	if (qh->dummy == NULL) {
++		fotg210_warn(fotg210, "no dummy td\n");
++		goto fail1;
++	}
++done:
++	return qh;
++fail1:
++	dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
++fail:
++	kfree(qh);
++	return NULL;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* The queue heads and transfer descriptors are managed from pools tied
++ * to each of the "per device" structures.
++ * This is the initialisation and cleanup code.
++ */
++
++static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210)
++{
++	if (fotg210->async)
++		qh_destroy(fotg210, fotg210->async);
++	fotg210->async = NULL;
++
++	if (fotg210->dummy)
++		qh_destroy(fotg210, fotg210->dummy);
++	fotg210->dummy = NULL;
++
++	/* DMA consistent memory and pools */
++	if (fotg210->qtd_pool)
++		dma_pool_destroy(fotg210->qtd_pool);
++	fotg210->qtd_pool = NULL;
++
++	if (fotg210->qh_pool) {
++		dma_pool_destroy(fotg210->qh_pool);
++		fotg210->qh_pool = NULL;
++	}
++
++	if (fotg210->itd_pool)
++		dma_pool_destroy(fotg210->itd_pool);
++	fotg210->itd_pool = NULL;
++
++	if (fotg210->periodic)
++		dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller,
++			fotg210->periodic_size * sizeof(u32),
++			fotg210->periodic, fotg210->periodic_dma);
++	fotg210->periodic = NULL;
++
++	/* shadow periodic table */
++	kfree(fotg210->pshadow);
++	fotg210->pshadow = NULL;
++}
++
++/* remember to add cleanup code (above) if you add anything here */
++static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags)
++{
++	int i;
++
++	/* QTDs for control/bulk/intr transfers */
++	fotg210->qtd_pool = dma_pool_create("fotg210_qtd",
++			fotg210_to_hcd(fotg210)->self.controller,
++			sizeof(struct fotg210_qtd),
++			32 /* byte alignment (for hw parts) */,
++			4096 /* can't cross 4K */);
++	if (!fotg210->qtd_pool)
++		goto fail;
++
++	/* QHs for control/bulk/intr transfers */
++	fotg210->qh_pool = dma_pool_create("fotg210_qh",
++			fotg210_to_hcd(fotg210)->self.controller,
++			sizeof(struct fotg210_qh_hw),
++			32 /* byte alignment (for hw parts) */,
++			4096 /* can't cross 4K */);
++	if (!fotg210->qh_pool)
++		goto fail;
++
++	fotg210->async = fotg210_qh_alloc(fotg210, flags);
++	if (!fotg210->async)
++		goto fail;
++
++	/* ITD for high speed ISO transfers */
++	fotg210->itd_pool = dma_pool_create("fotg210_itd",
++			fotg210_to_hcd(fotg210)->self.controller,
++			sizeof(struct fotg210_itd),
++			64 /* byte alignment (for hw parts) */,
++			4096 /* can't cross 4K */);
++	if (!fotg210->itd_pool)
++		goto fail;
++
++	/* Hardware periodic table */
++	fotg210->periodic = (__le32 *)
++		dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller,
++			fotg210->periodic_size * sizeof(__le32),
++			&fotg210->periodic_dma, 0);
++	if (fotg210->periodic == NULL)
++		goto fail;
++
++		for (i = 0; i < fotg210->periodic_size; i++)
++			fotg210->periodic[i] = FOTG210_LIST_END(fotg210);
++
++	/* software shadow of hardware table */
++	fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *),
++				   flags);
++	if (fotg210->pshadow != NULL)
++		return 0;
++
++fail:
++	fotg210_err(fotg210, "couldn't init memory\n");
++	fotg210_mem_cleanup(fotg210);
++	return -ENOMEM;
++}
++/*-------------------------------------------------------------------------*/
++/*
++ * EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
++ *
++ * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
++ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
++ * buffers needed for the larger number).  We use one QH per endpoint, queue
++ * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
++ *
++ * ISO traffic uses "ISO TD" (itd) records, and (along with
++ * interrupts) needs careful scheduling.  Performance improvements can be
++ * an ongoing challenge.  That's in "ehci-sched.c".
++ *
++ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
++ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
++ * (b) special fields in qh entries or (c) split iso entries.  TTs will
++ * buffer low/full speed data so the host collects it at high speed.
++ */
++
++/*-------------------------------------------------------------------------*/
++
++/* fill a qtd, returning how much of the buffer we were able to queue up */
++
++static int
++qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd, dma_addr_t buf,
++		  size_t len, int token, int maxpacket)
++{
++	int	i, count;
++	u64	addr = buf;
++
++	/* one buffer entry per 4K ... first might be short or unaligned */
++	qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr);
++	qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32));
++	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
++	if (likely(len < count))		/* ... iff needed */
++		count = len;
++	else {
++		buf +=  0x1000;
++		buf &= ~0x0fff;
++
++		/* per-qtd limit: from 16K to 20K (best alignment) */
++		for (i = 1; count < len && i < 5; i++) {
++			addr = buf;
++			qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr);
++			qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210,
++					(u32)(addr >> 32));
++			buf += 0x1000;
++			if ((count + 0x1000) < len)
++				count += 0x1000;
++			else
++				count = len;
++		}
++
++		/* short packets may only terminate transfers */
++		if (count != len)
++			count -= (count % maxpacket);
++	}
++	qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token);
++	qtd->length = count;
++
++	return count;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static inline void
++qh_update(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
++	  struct fotg210_qtd *qtd)
++{
++	struct fotg210_qh_hw *hw = qh->hw;
++
++	/* writes to an active overlay are unsafe */
++	BUG_ON(qh->qh_state != QH_STATE_IDLE);
++
++	hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma);
++	hw->hw_alt_next = FOTG210_LIST_END(fotg210);
++
++	/* Except for control endpoints, we make hardware maintain data
++	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
++	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
++	 * ever clear it.
++	 */
++	if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) {
++		unsigned	is_out, epnum;
++
++		is_out = qh->is_out;
++		epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f;
++		if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
++			hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE);
++			usb_settoggle(qh->dev, epnum, is_out, 1);
++		}
++	}
++
++	hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING);
++}
++
++/* if it weren't for a common silicon quirk (writing the dummy into the qh
++ * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
++ * recovery (including urb dequeue) would need software changes to a QH...
++ */
++static void
++qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{
++	struct fotg210_qtd *qtd;
++
++	if (list_empty(&qh->qtd_list))
++		qtd = qh->dummy;
++	else {
++		qtd = list_entry(qh->qtd_list.next,
++				struct fotg210_qtd, qtd_list);
++		/*
++		 * first qtd may already be partially processed.
++		 * If we come here during unlink, the QH overlay region
++		 * might have reference to the just unlinked qtd. The
++		 * qtd is updated in qh_completions(). Update the QH
++		 * overlay here.
++		 */
++		if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) {
++			qh->hw->hw_qtd_next = qtd->hw_next;
++			qtd = NULL;
++		}
++	}
++
++	if (qtd)
++		qh_update(fotg210, qh, qtd);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
++
++static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd,
++		struct usb_host_endpoint *ep)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	struct fotg210_qh		*qh = ep->hcpriv;
++	unsigned long		flags;
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++	qh->clearing_tt = 0;
++	if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
++			&& fotg210->rh_state == FOTG210_RH_RUNNING)
++		qh_link_async(fotg210, qh);
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++}
++
++static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210,
++				    struct fotg210_qh *qh,
++		struct urb *urb, u32 token)
++{
++
++	/* If an async split transaction gets an error or is unlinked,
++	 * the TT buffer may be left in an indeterminate state.  We
++	 * have to clear the TT buffer.
++	 *
++	 * Note: this routine is never called for Isochronous transfers.
++	 */
++	if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
++#ifdef DEBUG
++		struct usb_device *tt = urb->dev->tt->hub;
++		dev_dbg(&tt->dev,
++			"clear tt buffer port %d, a%d ep%d t%08x\n",
++			urb->dev->ttport, urb->dev->devnum,
++			usb_pipeendpoint(urb->pipe), token);
++#endif /* DEBUG */
++		if (urb->dev->tt->hub !=
++		    fotg210_to_hcd(fotg210)->self.root_hub) {
++			if (usb_hub_clear_tt_buffer(urb) == 0)
++				qh->clearing_tt = 1;
++		}
++	}
++}
++
++static int qtd_copy_status(
++	struct fotg210_hcd *fotg210,
++	struct urb *urb,
++	size_t length,
++	u32 token
++)
++{
++	int	status = -EINPROGRESS;
++
++	/* count IN/OUT bytes, not SETUP (even short packets) */
++	if (likely(QTD_PID(token) != 2))
++		urb->actual_length += length - QTD_LENGTH(token);
++
++	/* don't modify error codes */
++	if (unlikely(urb->unlinked))
++		return status;
++
++	/* force cleanup after short read; not always an error */
++	if (unlikely(IS_SHORT_READ(token)))
++		status = -EREMOTEIO;
++
++	/* serious "can't proceed" faults reported by the hardware */
++	if (token & QTD_STS_HALT) {
++		if (token & QTD_STS_BABBLE) {
++			/* FIXME "must" disable babbling device's port too */
++			status = -EOVERFLOW;
++		/* CERR nonzero + halt --> stall */
++		} else if (QTD_CERR(token)) {
++			status = -EPIPE;
++
++		/* In theory, more than one of the following bits can be set
++		 * since they are sticky and the transaction is retried.
++		 * Which to test first is rather arbitrary.
++		 */
++		} else if (token & QTD_STS_MMF) {
++			/* fs/ls interrupt xfer missed the complete-split */
++			status = -EPROTO;
++		} else if (token & QTD_STS_DBE) {
++			status = (QTD_PID(token) == 1) /* IN ? */
++				? -ENOSR  /* hc couldn't read data */
++				: -ECOMM; /* hc couldn't write data */
++		} else if (token & QTD_STS_XACT) {
++			/* timeout, bad CRC, wrong PID, etc */
++			fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n",
++				urb->dev->devpath,
++				usb_pipeendpoint(urb->pipe),
++				usb_pipein(urb->pipe) ? "in" : "out");
++			status = -EPROTO;
++		} else {	/* unknown */
++			status = -EPROTO;
++		}
++
++		fotg210_vdbg(fotg210,
++			"dev%d ep%d%s qtd token %08x --> status %d\n",
++			usb_pipedevice(urb->pipe),
++			usb_pipeendpoint(urb->pipe),
++			usb_pipein(urb->pipe) ? "in" : "out",
++			token, status);
++	}
++
++	return status;
++}
++
++static void
++fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb, int status)
++__releases(fotg210->lock)
++__acquires(fotg210->lock)
++{
++	if (likely(urb->hcpriv != NULL)) {
++		struct fotg210_qh	*qh = (struct fotg210_qh *) urb->hcpriv;
++
++		/* S-mask in a QH means it's an interrupt urb */
++		if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) {
++
++			/* ... update hc-wide periodic stats (for usbfs) */
++			fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--;
++		}
++	}
++
++	if (unlikely(urb->unlinked)) {
++		COUNT(fotg210->stats.unlink);
++	} else {
++		/* report non-error and short read status as zero */
++		if (status == -EINPROGRESS || status == -EREMOTEIO)
++			status = 0;
++		COUNT(fotg210->stats.complete);
++	}
++
++#ifdef FOTG210_URB_TRACE
++	fotg210_dbg(fotg210,
++		"%s %s urb %p ep%d%s status %d len %d/%d\n",
++		__func__, urb->dev->devpath, urb,
++		usb_pipeendpoint(urb->pipe),
++		usb_pipein(urb->pipe) ? "in" : "out",
++		status,
++		urb->actual_length, urb->transfer_buffer_length);
++#endif
++
++	/* complete() can reenter this HCD */
++	usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
++	spin_unlock(&fotg210->lock);
++	usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status);
++	spin_lock(&fotg210->lock);
++}
++
++static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
++
++/*
++ * Process and free completed qtds for a qh, returning URBs to drivers.
++ * Chases up to qh->hw_current.  Returns number of completions called,
++ * indicating how much "real" work we did.
++ */
++static unsigned
++qh_completions(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{
++	struct fotg210_qtd		*last, *end = qh->dummy;
++	struct list_head	*entry, *tmp;
++	int			last_status;
++	int			stopped;
++	unsigned		count = 0;
++	u8			state;
++	struct fotg210_qh_hw	*hw = qh->hw;
++
++	if (unlikely(list_empty(&qh->qtd_list)))
++		return count;
++
++	/* completions (or tasks on other cpus) must never clobber HALT
++	 * till we've gone through and cleaned everything up, even when
++	 * they add urbs to this qh's queue or mark them for unlinking.
++	 *
++	 * NOTE:  unlinking expects to be done in queue order.
++	 *
++	 * It's a bug for qh->qh_state to be anything other than
++	 * QH_STATE_IDLE, unless our caller is scan_async() or
++	 * scan_intr().
++	 */
++	state = qh->qh_state;
++	qh->qh_state = QH_STATE_COMPLETING;
++	stopped = (state == QH_STATE_IDLE);
++
++ rescan:
++	last = NULL;
++	last_status = -EINPROGRESS;
++	qh->needs_rescan = 0;
++
++	/* remove de-activated QTDs from front of queue.
++	 * after faults (including short reads), cleanup this urb
++	 * then let the queue advance.
++	 * if queue is stopped, handles unlinks.
++	 */
++	list_for_each_safe(entry, tmp, &qh->qtd_list) {
++		struct fotg210_qtd	*qtd;
++		struct urb	*urb;
++		u32		token = 0;
++
++		qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
++		urb = qtd->urb;
++
++		/* clean up any state from previous QTD ...*/
++		if (last) {
++			if (likely(last->urb != urb)) {
++				fotg210_urb_done(fotg210, last->urb,
++						 last_status);
++				count++;
++				last_status = -EINPROGRESS;
++			}
++			fotg210_qtd_free(fotg210, last);
++			last = NULL;
++		}
++
++		/* ignore urbs submitted during completions we reported */
++		if (qtd == end)
++			break;
++
++		/* hardware copies qtd out of qh overlay */
++		rmb();
++		token = hc32_to_cpu(fotg210, qtd->hw_token);
++
++		/* always clean up qtds the hc de-activated */
++ retry_xacterr:
++		if ((token & QTD_STS_ACTIVE) == 0) {
++
++			/* Report Data Buffer Error: non-fatal but useful */
++			if (token & QTD_STS_DBE)
++				fotg210_dbg(fotg210,
++					"detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
++					urb,
++					usb_endpoint_num(&urb->ep->desc),
++					usb_endpoint_dir_in(&urb->ep->desc)
++						? "in" : "out",
++					urb->transfer_buffer_length,
++					qtd,
++					qh);
++
++			/* on STALL, error, and short reads this urb must
++			 * complete and all its qtds must be recycled.
++			 */
++			if ((token & QTD_STS_HALT) != 0) {
++
++				/* retry transaction errors until we
++				 * reach the software xacterr limit
++				 */
++				if ((token & QTD_STS_XACT) &&
++						QTD_CERR(token) == 0 &&
++						++qh->xacterrs < QH_XACTERR_MAX &&
++						!urb->unlinked) {
++					fotg210_dbg(fotg210,
++	"detected XactErr len %zu/%zu retry %d\n",
++	qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);
++
++					/* reset the token in the qtd and the
++					 * qh overlay (which still contains
++					 * the qtd) so that we pick up from
++					 * where we left off
++					 */
++					token &= ~QTD_STS_HALT;
++					token |= QTD_STS_ACTIVE |
++							(FOTG210_TUNE_CERR << 10);
++					qtd->hw_token = cpu_to_hc32(fotg210,
++							token);
++					wmb();
++					hw->hw_token = cpu_to_hc32(fotg210,
++							token);
++					goto retry_xacterr;
++				}
++				stopped = 1;
++
++			/* magic dummy for some short reads; qh won't advance.
++			 * that silicon quirk can kick in with this dummy too.
++			 *
++			 * other short reads won't stop the queue, including
++			 * control transfers (status stage handles that) or
++			 * most other single-qtd reads ... the queue stops if
++			 * URB_SHORT_NOT_OK was set so the driver submitting
++			 * the urbs could clean it up.
++			 */
++			} else if (IS_SHORT_READ(token)
++					&& !(qtd->hw_alt_next
++						& FOTG210_LIST_END(fotg210))) {
++				stopped = 1;
++			}
++
++		/* stop scanning when we reach qtds the hc is using */
++		} else if (likely(!stopped
++				&& fotg210->rh_state >= FOTG210_RH_RUNNING)) {
++			break;
++
++		/* scan the whole queue for unlinks whenever it stops */
++		} else {
++			stopped = 1;
++
++			/* cancel everything if we halt, suspend, etc */
++			if (fotg210->rh_state < FOTG210_RH_RUNNING)
++				last_status = -ESHUTDOWN;
++
++			/* this qtd is active; skip it unless a previous qtd
++			 * for its urb faulted, or its urb was canceled.
++			 */
++			else if (last_status == -EINPROGRESS && !urb->unlinked)
++				continue;
++
++			/* qh unlinked; token in overlay may be most current */
++			if (state == QH_STATE_IDLE
++					&& cpu_to_hc32(fotg210, qtd->qtd_dma)
++						== hw->hw_current) {
++				token = hc32_to_cpu(fotg210, hw->hw_token);
++
++				/* An unlink may leave an incomplete
++				 * async transaction in the TT buffer.
++				 * We have to clear it.
++				 */
++				fotg210_clear_tt_buffer(fotg210, qh, urb,
++							token);
++			}
++		}
++
++		/* unless we already know the urb's status, collect qtd status
++		 * and update count of bytes transferred.  in common short read
++		 * cases with only one data qtd (including control transfers),
++		 * queue processing won't halt.  but with two or more qtds (for
++		 * example, with a 32 KB transfer), when the first qtd gets a
++		 * short read the second must be removed by hand.
++		 */
++		if (last_status == -EINPROGRESS) {
++			last_status = qtd_copy_status(fotg210, urb,
++					qtd->length, token);
++			if (last_status == -EREMOTEIO
++					&& (qtd->hw_alt_next
++						& FOTG210_LIST_END(fotg210)))
++				last_status = -EINPROGRESS;
++
++			/* As part of low/full-speed endpoint-halt processing
++			 * we must clear the TT buffer (11.17.5).
++			 */
++			if (unlikely(last_status != -EINPROGRESS &&
++					last_status != -EREMOTEIO)) {
++				/* The TT's in some hubs malfunction when they
++				 * receive this request following a STALL (they
++				 * stop sending isochronous packets).  Since a
++				 * STALL can't leave the TT buffer in a busy
++				 * state (if you believe Figures 11-48 - 11-51
++				 * in the USB 2.0 spec), we won't clear the TT
++				 * buffer in this case.  Strictly speaking this
++				 * is a violation of the spec.
++				 */
++				if (last_status != -EPIPE)
++					fotg210_clear_tt_buffer(fotg210, qh,
++								urb, token);
++			}
++		}
++
++		/* if we're removing something not at the queue head,
++		 * patch the hardware queue pointer.
++		 */
++		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
++			last = list_entry(qtd->qtd_list.prev,
++					struct fotg210_qtd, qtd_list);
++			last->hw_next = qtd->hw_next;
++		}
++
++		/* remove qtd; it's recycled after possible urb completion */
++		list_del(&qtd->qtd_list);
++		last = qtd;
++
++		/* reinit the xacterr counter for the next qtd */
++		qh->xacterrs = 0;
++	}
++
++	/* last urb's completion might still need calling */
++	if (likely(last != NULL)) {
++		fotg210_urb_done(fotg210, last->urb, last_status);
++		count++;
++		fotg210_qtd_free(fotg210, last);
++	}
++
++	/* Do we need to rescan for URBs dequeued during a giveback? */
++	if (unlikely(qh->needs_rescan)) {
++		/* If the QH is already unlinked, do the rescan now. */
++		if (state == QH_STATE_IDLE)
++			goto rescan;
++
++		/* Otherwise we have to wait until the QH is fully unlinked.
++		 * Our caller will start an unlink if qh->needs_rescan is
++		 * set.  But if an unlink has already started, nothing needs
++		 * to be done.
++		 */
++		if (state != QH_STATE_LINKED)
++			qh->needs_rescan = 0;
++	}
++
++	/* restore original state; caller must unlink or relink */
++	qh->qh_state = state;
++
++	/* be sure the hardware's done with the qh before refreshing
++	 * it after fault cleanup, or recovering from silicon wrongly
++	 * overlaying the dummy qtd (which reduces DMA chatter).
++	 */
++	if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) {
++		switch (state) {
++		case QH_STATE_IDLE:
++			qh_refresh(fotg210, qh);
++			break;
++		case QH_STATE_LINKED:
++			/* We won't refresh a QH that's linked (after the HC
++			 * stopped the queue).  That avoids a race:
++			 *  - HC reads first part of QH;
++			 *  - CPU updates that first part and the token;
++			 *  - HC reads rest of that QH, including token
++			 * Result:  HC gets an inconsistent image, and then
++			 * DMAs to/from the wrong memory (corrupting it).
++			 *
++			 * That should be rare for interrupt transfers,
++			 * except maybe high bandwidth ...
++			 */
++
++			/* Tell the caller to start an unlink */
++			qh->needs_rescan = 1;
++			break;
++		/* otherwise, unlink already started */
++		}
++	}
++
++	return count;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
++#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
++/* ... and packet size, for any kind of endpoint descriptor */
++#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
++
++/*
++ * reverse of qh_urb_transaction:  free a list of TDs.
++ * used for cleanup after errors, before HC sees an URB's TDs.
++ */
++static void qtd_list_free(
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	struct list_head	*qtd_list
++) {
++	struct list_head	*entry, *temp;
++
++	list_for_each_safe(entry, temp, qtd_list) {
++		struct fotg210_qtd	*qtd;
++
++		qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
++		list_del(&qtd->qtd_list);
++		fotg210_qtd_free(fotg210, qtd);
++	}
++}
++
++/*
++ * create a list of filled qtds for this URB; won't link into qh.
++ */
++static struct list_head *
++qh_urb_transaction(
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	struct list_head	*head,
++	gfp_t			flags
++) {
++	struct fotg210_qtd		*qtd, *qtd_prev;
++	dma_addr_t		buf;
++	int			len, this_sg_len, maxpacket;
++	int			is_input;
++	u32			token;
++	int			i;
++	struct scatterlist	*sg;
++
++	/*
++	 * URBs map to sequences of QTDs:  one logical transaction
++	 */
++	qtd = fotg210_qtd_alloc(fotg210, flags);
++	if (unlikely(!qtd))
++		return NULL;
++	list_add_tail(&qtd->qtd_list, head);
++	qtd->urb = urb;
++
++	token = QTD_STS_ACTIVE;
++	token |= (FOTG210_TUNE_CERR << 10);
++	/* for split transactions, SplitXState initialized to zero */
++
++	len = urb->transfer_buffer_length;
++	is_input = usb_pipein(urb->pipe);
++	if (usb_pipecontrol(urb->pipe)) {
++		/* SETUP pid */
++		qtd_fill(fotg210, qtd, urb->setup_dma,
++				sizeof(struct usb_ctrlrequest),
++				token | (2 /* "setup" */ << 8), 8);
++
++		/* ... and always at least one more pid */
++		token ^= QTD_TOGGLE;
++		qtd_prev = qtd;
++		qtd = fotg210_qtd_alloc(fotg210, flags);
++		if (unlikely(!qtd))
++			goto cleanup;
++		qtd->urb = urb;
++		qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
++		list_add_tail(&qtd->qtd_list, head);
++
++		/* for zero length DATA stages, STATUS is always IN */
++		if (len == 0)
++			token |= (1 /* "in" */ << 8);
++	}
++
++	/*
++	 * data transfer stage:  buffer setup
++	 */
++	i = urb->num_mapped_sgs;
++	if (len > 0 && i > 0) {
++		sg = urb->sg;
++		buf = sg_dma_address(sg);
++
++		/* urb->transfer_buffer_length may be smaller than the
++		 * size of the scatterlist (or vice versa)
++		 */
++		this_sg_len = min_t(int, sg_dma_len(sg), len);
++	} else {
++		sg = NULL;
++		buf = urb->transfer_dma;
++		this_sg_len = len;
++	}
++
++	if (is_input)
++		token |= (1 /* "in" */ << 8);
++	/* else it's already initted to "out" pid (0 << 8) */
++
++	maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
++
++	/*
++	 * buffer gets wrapped in one or more qtds;
++	 * last one may be "short" (including zero len)
++	 * and may serve as a control status ack
++	 */
++	for (;;) {
++		int this_qtd_len;
++
++		this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token,
++				maxpacket);
++		this_sg_len -= this_qtd_len;
++		len -= this_qtd_len;
++		buf += this_qtd_len;
++
++		/*
++		 * short reads advance to a "magic" dummy instead of the next
++		 * qtd ... that forces the queue to stop, for manual cleanup.
++		 * (this will usually be overridden later.)
++		 */
++		if (is_input)
++			qtd->hw_alt_next = fotg210->async->hw->hw_alt_next;
++
++		/* qh makes control packets use qtd toggle; maybe switch it */
++		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
++			token ^= QTD_TOGGLE;
++
++		if (likely(this_sg_len <= 0)) {
++			if (--i <= 0 || len <= 0)
++				break;
++			sg = sg_next(sg);
++			buf = sg_dma_address(sg);
++			this_sg_len = min_t(int, sg_dma_len(sg), len);
++		}
++
++		qtd_prev = qtd;
++		qtd = fotg210_qtd_alloc(fotg210, flags);
++		if (unlikely(!qtd))
++			goto cleanup;
++		qtd->urb = urb;
++		qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
++		list_add_tail(&qtd->qtd_list, head);
++	}
++
++	/*
++	 * unless the caller requires manual cleanup after short reads,
++	 * have the alt_next mechanism keep the queue running after the
++	 * last data qtd (the only one, for control and most other cases).
++	 */
++	if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
++				|| usb_pipecontrol(urb->pipe)))
++		qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
++
++	/*
++	 * control requests may need a terminating data "status" ack;
++	 * other OUT ones may need a terminating short packet
++	 * (zero length).
++	 */
++	if (likely(urb->transfer_buffer_length != 0)) {
++		int	one_more = 0;
++
++		if (usb_pipecontrol(urb->pipe)) {
++			one_more = 1;
++			token ^= 0x0100;	/* "in" <--> "out"  */
++			token |= QTD_TOGGLE;	/* force DATA1 */
++		} else if (usb_pipeout(urb->pipe)
++				&& (urb->transfer_flags & URB_ZERO_PACKET)
++				&& !(urb->transfer_buffer_length % maxpacket)) {
++			one_more = 1;
++		}
++		if (one_more) {
++			qtd_prev = qtd;
++			qtd = fotg210_qtd_alloc(fotg210, flags);
++			if (unlikely(!qtd))
++				goto cleanup;
++			qtd->urb = urb;
++			qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
++			list_add_tail(&qtd->qtd_list, head);
++
++			/* never any data in such packets */
++			qtd_fill(fotg210, qtd, 0, 0, token, 0);
++		}
++	}
++
++	/* by default, enable interrupt on urb completion */
++	if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
++		qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC);
++	return head;
++
++cleanup:
++	qtd_list_free(fotg210, urb, head);
++	return NULL;
++}
++
++/*-------------------------------------------------------------------------*/
++/*
++ * Would be best to create all qh's from config descriptors,
++ * when each interface/altsetting is established.  Unlink
++ * any previous qh and cancel its urbs first; endpoints are
++ * implicitly reset then (data toggle too).
++ * That'd mean updating how usbcore talks to HCDs. (2.7?)
++*/
++
++
++/*
++ * Each QH holds a qtd list; a QH is used for everything except iso.
++ *
++ * For interrupt urbs, the scheduler must set the microframe scheduling
++ * mask(s) each time the QH gets scheduled.  For highspeed, that's
++ * just one microframe in the s-mask.  For split interrupt transactions
++ * there are additional complications: c-mask, maybe FSTNs.
++ */
++static struct fotg210_qh *
++qh_make(
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	gfp_t			flags
++) {
++	struct fotg210_qh		*qh = fotg210_qh_alloc(fotg210, flags);
++	u32			info1 = 0, info2 = 0;
++	int			is_input, type;
++	int			maxp = 0;
++	struct usb_tt		*tt = urb->dev->tt;
++	struct fotg210_qh_hw	*hw;
++
++	if (!qh)
++		return qh;
++
++	/*
++	 * init endpoint/device data for this QH
++	 */
++	info1 |= usb_pipeendpoint(urb->pipe) << 8;
++	info1 |= usb_pipedevice(urb->pipe) << 0;
++
++	is_input = usb_pipein(urb->pipe);
++	type = usb_pipetype(urb->pipe);
++	maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input);
++
++	/* 1024 byte maxpacket is a hardware ceiling.  High bandwidth
++	 * acts like up to 3KB, but is built from smaller packets.
++	 */
++	if (max_packet(maxp) > 1024) {
++		fotg210_dbg(fotg210, "bogus qh maxpacket %d\n",
++			    max_packet(maxp));
++		goto done;
++	}
++
++	/* Compute interrupt scheduling parameters just once, and save.
++	 * - allowing for high bandwidth, how many nsec/uframe are used?
++	 * - split transactions need a second CSPLIT uframe; same question
++	 * - splits also need a schedule gap (for full/low speed I/O)
++	 * - qh has a polling interval
++	 *
++	 * For control/bulk requests, the HC or TT handles these.
++	 */
++	if (type == PIPE_INTERRUPT) {
++		qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
++				is_input, 0,
++				hb_mult(maxp) * max_packet(maxp)));
++		qh->start = NO_FRAME;
++
++		if (urb->dev->speed == USB_SPEED_HIGH) {
++			qh->c_usecs = 0;
++			qh->gap_uf = 0;
++
++			qh->period = urb->interval >> 3;
++			if (qh->period == 0 && urb->interval != 1) {
++				/* NOTE interval 2 or 4 uframes could work.
++				 * But interval 1 scheduling is simpler, and
++				 * includes high bandwidth.
++				 */
++				urb->interval = 1;
++			} else if (qh->period > fotg210->periodic_size) {
++				qh->period = fotg210->periodic_size;
++				urb->interval = qh->period << 3;
++			}
++		} else {
++			int		think_time;
++
++			/* gap is f(FS/LS transfer times) */
++			qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
++					is_input, 0, maxp) / (125 * 1000);
++
++			/* FIXME this just approximates SPLIT/CSPLIT times */
++			if (is_input) {		/* SPLIT, gap, CSPLIT+DATA */
++				qh->c_usecs = qh->usecs + HS_USECS(0);
++				qh->usecs = HS_USECS(1);
++			} else {		/* SPLIT+DATA, gap, CSPLIT */
++				qh->usecs += HS_USECS(1);
++				qh->c_usecs = HS_USECS(0);
++			}
++
++			think_time = tt ? tt->think_time : 0;
++			qh->tt_usecs = NS_TO_US(think_time +
++					usb_calc_bus_time(urb->dev->speed,
++					is_input, 0, max_packet(maxp)));
++			qh->period = urb->interval;
++			if (qh->period > fotg210->periodic_size) {
++				qh->period = fotg210->periodic_size;
++				urb->interval = qh->period;
++			}
++		}
++	}
++
++	/* support for tt scheduling, and access to toggles */
++	qh->dev = urb->dev;
++
++	/* using TT? */
++	switch (urb->dev->speed) {
++	case USB_SPEED_LOW:
++		info1 |= QH_LOW_SPEED;
++		/* FALL THROUGH */
++
++	case USB_SPEED_FULL:
++		/* EPS 0 means "full" */
++		if (type != PIPE_INTERRUPT)
++			info1 |= (FOTG210_TUNE_RL_TT << 28);
++		if (type == PIPE_CONTROL) {
++			info1 |= QH_CONTROL_EP;		/* for TT */
++			info1 |= QH_TOGGLE_CTL;		/* toggle from qtd */
++		}
++		info1 |= maxp << 16;
++
++		info2 |= (FOTG210_TUNE_MULT_TT << 30);
++
++		/* Some Freescale processors have an erratum in which the
++		 * port number in the queue head was 0..N-1 instead of 1..N.
++		 */
++		if (fotg210_has_fsl_portno_bug(fotg210))
++			info2 |= (urb->dev->ttport-1) << 23;
++		else
++			info2 |= urb->dev->ttport << 23;
++
++		/* set the address of the TT; for TDI's integrated
++		 * root hub tt, leave it zeroed.
++		 */
++		if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub)
++			info2 |= tt->hub->devnum << 16;
++
++		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
++
++		break;
++
++	case USB_SPEED_HIGH:		/* no TT involved */
++		info1 |= QH_HIGH_SPEED;
++		if (type == PIPE_CONTROL) {
++			info1 |= (FOTG210_TUNE_RL_HS << 28);
++			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
++			info1 |= QH_TOGGLE_CTL;	/* toggle from qtd */
++			info2 |= (FOTG210_TUNE_MULT_HS << 30);
++		} else if (type == PIPE_BULK) {
++			info1 |= (FOTG210_TUNE_RL_HS << 28);
++			/* The USB spec says that high speed bulk endpoints
++			 * always use 512 byte maxpacket.  But some device
++			 * vendors decided to ignore that, and MSFT is happy
++			 * to help them do so.  So now people expect to use
++			 * such nonconformant devices with Linux too; sigh.
++			 */
++			info1 |= max_packet(maxp) << 16;
++			info2 |= (FOTG210_TUNE_MULT_HS << 30);
++		} else {		/* PIPE_INTERRUPT */
++			info1 |= max_packet(maxp) << 16;
++			info2 |= hb_mult(maxp) << 30;
++		}
++		break;
++	default:
++		fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev,
++			urb->dev->speed);
++done:
++		qh_destroy(fotg210, qh);
++		return NULL;
++	}
++
++	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
++
++	/* init as live, toggle clear, advance to dummy */
++	qh->qh_state = QH_STATE_IDLE;
++	hw = qh->hw;
++	hw->hw_info1 = cpu_to_hc32(fotg210, info1);
++	hw->hw_info2 = cpu_to_hc32(fotg210, info2);
++	qh->is_out = !is_input;
++	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
++	qh_refresh(fotg210, qh);
++	return qh;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void enable_async(struct fotg210_hcd *fotg210)
++{
++	if (fotg210->async_count++)
++		return;
++
++	/* Stop waiting to turn off the async schedule */
++	fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC);
++
++	/* Don't start the schedule until ASS is 0 */
++	fotg210_poll_ASS(fotg210);
++	turn_on_io_watchdog(fotg210);
++}
++
++static void disable_async(struct fotg210_hcd *fotg210)
++{
++	if (--fotg210->async_count)
++		return;
++
++	/* The async schedule and async_unlink list are supposed to be empty */
++	WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink);
++
++	/* Don't turn off the schedule until ASS is 1 */
++	fotg210_poll_ASS(fotg210);
++}
++
++/* move qh (and its qtds) onto async queue; maybe enable queue.  */
++
++static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{
++	__hc32		dma = QH_NEXT(fotg210, qh->qh_dma);
++	struct fotg210_qh	*head;
++
++	/* Don't link a QH if there's a Clear-TT-Buffer pending */
++	if (unlikely(qh->clearing_tt))
++		return;
++
++	WARN_ON(qh->qh_state != QH_STATE_IDLE);
++
++	/* clear halt and/or toggle; and maybe recover from silicon quirk */
++	qh_refresh(fotg210, qh);
++
++	/* splice right after start */
++	head = fotg210->async;
++	qh->qh_next = head->qh_next;
++	qh->hw->hw_next = head->hw->hw_next;
++	wmb();
++
++	head->qh_next.qh = qh;
++	head->hw->hw_next = dma;
++
++	qh->xacterrs = 0;
++	qh->qh_state = QH_STATE_LINKED;
++	/* qtd completions reported later by interrupt */
++
++	enable_async(fotg210);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * For control/bulk/interrupt, return QH with these TDs appended.
++ * Allocates and initializes the QH if necessary.
++ * Returns null if it can't allocate a QH it needs to.
++ * If the QH has TDs (urbs) already, that's great.
++ */
++static struct fotg210_qh *qh_append_tds(
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	struct list_head	*qtd_list,
++	int			epnum,
++	void			**ptr
++)
++{
++	struct fotg210_qh		*qh = NULL;
++	__hc32			qh_addr_mask = cpu_to_hc32(fotg210, 0x7f);
++
++	qh = (struct fotg210_qh *) *ptr;
++	if (unlikely(qh == NULL)) {
++		/* can't sleep here, we have fotg210->lock... */
++		qh = qh_make(fotg210, urb, GFP_ATOMIC);
++		*ptr = qh;
++	}
++	if (likely(qh != NULL)) {
++		struct fotg210_qtd	*qtd;
++
++		if (unlikely(list_empty(qtd_list)))
++			qtd = NULL;
++		else
++			qtd = list_entry(qtd_list->next, struct fotg210_qtd,
++					qtd_list);
++
++		/* control qh may need patching ... */
++		if (unlikely(epnum == 0)) {
++			/* usb_reset_device() briefly reverts to address 0 */
++			if (usb_pipedevice(urb->pipe) == 0)
++				qh->hw->hw_info1 &= ~qh_addr_mask;
++		}
++
++		/* just one way to queue requests: swap with the dummy qtd.
++		 * only hc or qh_refresh() ever modify the overlay.
++		 */
++		if (likely(qtd != NULL)) {
++			struct fotg210_qtd		*dummy;
++			dma_addr_t		dma;
++			__hc32			token;
++
++			/* to avoid racing the HC, use the dummy td instead of
++			 * the first td of our list (becomes new dummy).  both
++			 * tds stay deactivated until we're done, when the
++			 * HC is allowed to fetch the old dummy (4.10.2).
++			 */
++			token = qtd->hw_token;
++			qtd->hw_token = HALT_BIT(fotg210);
++
++			dummy = qh->dummy;
++
++			dma = dummy->qtd_dma;
++			*dummy = *qtd;
++			dummy->qtd_dma = dma;
++
++			list_del(&qtd->qtd_list);
++			list_add(&dummy->qtd_list, qtd_list);
++			list_splice_tail(qtd_list, &qh->qtd_list);
++
++			fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma);
++			qh->dummy = qtd;
++
++			/* hc must see the new dummy at list end */
++			dma = qtd->qtd_dma;
++			qtd = list_entry(qh->qtd_list.prev,
++					struct fotg210_qtd, qtd_list);
++			qtd->hw_next = QTD_NEXT(fotg210, dma);
++
++			/* let the hc process these next qtds */
++			wmb();
++			dummy->hw_token = token;
++
++			urb->hcpriv = qh;
++		}
++	}
++	return qh;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int
++submit_async(
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	struct list_head	*qtd_list,
++	gfp_t			mem_flags
++) {
++	int			epnum;
++	unsigned long		flags;
++	struct fotg210_qh		*qh = NULL;
++	int			rc;
++
++	epnum = urb->ep->desc.bEndpointAddress;
++
++#ifdef FOTG210_URB_TRACE
++	{
++		struct fotg210_qtd *qtd;
++		qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list);
++		fotg210_dbg(fotg210,
++			 "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
++			 __func__, urb->dev->devpath, urb,
++			 epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
++			 urb->transfer_buffer_length,
++			 qtd, urb->ep->hcpriv);
++	}
++#endif
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
++		rc = -ESHUTDOWN;
++		goto done;
++	}
++	rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
++	if (unlikely(rc))
++		goto done;
++
++	qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
++	if (unlikely(qh == NULL)) {
++		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
++		rc = -ENOMEM;
++		goto done;
++	}
++
++	/* Control/bulk operations through TTs don't need scheduling,
++	 * the HC and TT handle it when the TT has a buffer ready.
++	 */
++	if (likely(qh->qh_state == QH_STATE_IDLE))
++		qh_link_async(fotg210, qh);
++ done:
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	if (unlikely(qh == NULL))
++		qtd_list_free(fotg210, urb, qtd_list);
++	return rc;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void single_unlink_async(struct fotg210_hcd *fotg210,
++				struct fotg210_qh *qh)
++{
++	struct fotg210_qh		*prev;
++
++	/* Add to the end of the list of QHs waiting for the next IAAD */
++	qh->qh_state = QH_STATE_UNLINK;
++	if (fotg210->async_unlink)
++		fotg210->async_unlink_last->unlink_next = qh;
++	else
++		fotg210->async_unlink = qh;
++	fotg210->async_unlink_last = qh;
++
++	/* Unlink it from the schedule */
++	prev = fotg210->async;
++	while (prev->qh_next.qh != qh)
++		prev = prev->qh_next.qh;
++
++	prev->hw->hw_next = qh->hw->hw_next;
++	prev->qh_next = qh->qh_next;
++	if (fotg210->qh_scan_next == qh)
++		fotg210->qh_scan_next = qh->qh_next.qh;
++}
++
++static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested)
++{
++	/*
++	 * Do nothing if an IAA cycle is already running or
++	 * if one will be started shortly.
++	 */
++	if (fotg210->async_iaa || fotg210->async_unlinking)
++		return;
++
++	/* Do all the waiting QHs at once */
++	fotg210->async_iaa = fotg210->async_unlink;
++	fotg210->async_unlink = NULL;
++
++	/* If the controller isn't running, we don't have to wait for it */
++	if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) {
++		if (!nested)		/* Avoid recursion */
++			end_unlink_async(fotg210);
++
++	/* Otherwise start a new IAA cycle */
++	} else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) {
++		/* Make sure the unlinks are all visible to the hardware */
++		wmb();
++
++		fotg210_writel(fotg210, fotg210->command | CMD_IAAD,
++				&fotg210->regs->command);
++		fotg210_readl(fotg210, &fotg210->regs->command);
++		fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG,
++				     true);
++	}
++}
++
++/* the async qh for the qtds being unlinked are now gone from the HC */
++
++static void end_unlink_async(struct fotg210_hcd *fotg210)
++{
++	struct fotg210_qh		*qh;
++
++	/* Process the idle QHs */
++ restart:
++	fotg210->async_unlinking = true;
++	while (fotg210->async_iaa) {
++		qh = fotg210->async_iaa;
++		fotg210->async_iaa = qh->unlink_next;
++		qh->unlink_next = NULL;
++
++		qh->qh_state = QH_STATE_IDLE;
++		qh->qh_next.qh = NULL;
++
++		qh_completions(fotg210, qh);
++		if (!list_empty(&qh->qtd_list) &&
++				fotg210->rh_state == FOTG210_RH_RUNNING)
++			qh_link_async(fotg210, qh);
++		disable_async(fotg210);
++	}
++	fotg210->async_unlinking = false;
++
++	/* Start a new IAA cycle if any QHs are waiting for it */
++	if (fotg210->async_unlink) {
++		start_iaa_cycle(fotg210, true);
++		if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING))
++			goto restart;
++	}
++}
++
++static void unlink_empty_async(struct fotg210_hcd *fotg210)
++{
++	struct fotg210_qh		*qh, *next;
++	bool			stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
++	bool			check_unlinks_later = false;
++
++	/* Unlink all the async QHs that have been empty for a timer cycle */
++	next = fotg210->async->qh_next.qh;
++	while (next) {
++		qh = next;
++		next = qh->qh_next.qh;
++
++		if (list_empty(&qh->qtd_list) &&
++				qh->qh_state == QH_STATE_LINKED) {
++			if (!stopped && qh->unlink_cycle ==
++					fotg210->async_unlink_cycle)
++				check_unlinks_later = true;
++			else
++				single_unlink_async(fotg210, qh);
++		}
++	}
++
++	/* Start a new IAA cycle if any QHs are waiting for it */
++	if (fotg210->async_unlink)
++		start_iaa_cycle(fotg210, false);
++
++	/* QHs that haven't been empty for long enough will be handled later */
++	if (check_unlinks_later) {
++		fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS,
++				     true);
++		++fotg210->async_unlink_cycle;
++	}
++}
++
++/* makes sure the async qh will become idle */
++/* caller must own fotg210->lock */
++
++static void start_unlink_async(struct fotg210_hcd *fotg210,
++			       struct fotg210_qh *qh)
++{
++	/*
++	 * If the QH isn't linked then there's nothing we can do
++	 * unless we were called during a giveback, in which case
++	 * qh_completions() has to deal with it.
++	 */
++	if (qh->qh_state != QH_STATE_LINKED) {
++		if (qh->qh_state == QH_STATE_COMPLETING)
++			qh->needs_rescan = 1;
++		return;
++	}
++
++	single_unlink_async(fotg210, qh);
++	start_iaa_cycle(fotg210, false);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void scan_async(struct fotg210_hcd *fotg210)
++{
++	struct fotg210_qh		*qh;
++	bool			check_unlinks_later = false;
++
++	fotg210->qh_scan_next = fotg210->async->qh_next.qh;
++	while (fotg210->qh_scan_next) {
++		qh = fotg210->qh_scan_next;
++		fotg210->qh_scan_next = qh->qh_next.qh;
++ rescan:
++		/* clean any finished work for this qh */
++		if (!list_empty(&qh->qtd_list)) {
++			int temp;
++
++			/*
++			 * Unlinks could happen here; completion reporting
++			 * drops the lock.  That's why fotg210->qh_scan_next
++			 * always holds the next qh to scan; if the next qh
++			 * gets unlinked then fotg210->qh_scan_next is adjusted
++			 * in single_unlink_async().
++			 */
++			temp = qh_completions(fotg210, qh);
++			if (qh->needs_rescan) {
++				start_unlink_async(fotg210, qh);
++			} else if (list_empty(&qh->qtd_list)
++					&& qh->qh_state == QH_STATE_LINKED) {
++				qh->unlink_cycle = fotg210->async_unlink_cycle;
++				check_unlinks_later = true;
++			} else if (temp != 0)
++				goto rescan;
++		}
++	}
++
++	/*
++	 * Unlink empty entries, reducing DMA usage as well
++	 * as HCD schedule-scanning costs.  Delay for any qh
++	 * we just scanned, there's a not-unusual case that it
++	 * doesn't stay idle for long.
++	 */
++	if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING &&
++			!(fotg210->enabled_hrtimer_events &
++				BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) {
++		fotg210_enable_event(fotg210,
++				     FOTG210_HRTIMER_ASYNC_UNLINKS, true);
++		++fotg210->async_unlink_cycle;
++	}
++}
++/*-------------------------------------------------------------------------*/
++/*
++ * EHCI scheduled transaction support:  interrupt, iso, split iso
++ * These are called "periodic" transactions in the EHCI spec.
++ *
++ * Note that for interrupt transfers, the QH/QTD manipulation is shared
++ * with the "asynchronous" transaction support (control/bulk transfers).
++ * The only real difference is in how interrupt transfers are scheduled.
++ *
++ * For ISO, we make an "iso_stream" head to serve the same role as a QH.
++ * It keeps track of every ITD (or SITD) that's linked, and holds enough
++ * pre-calculated schedule data to make appending to the queue be quick.
++ */
++
++static int fotg210_get_frame(struct usb_hcd *hcd);
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * periodic_next_shadow - return "next" pointer on shadow list
++ * @periodic: host pointer to qh/itd
++ * @tag: hardware tag for type of this record
++ */
++static union fotg210_shadow *
++periodic_next_shadow(struct fotg210_hcd *fotg210,
++		     union fotg210_shadow *periodic, __hc32 tag)
++{
++	switch (hc32_to_cpu(fotg210, tag)) {
++	case Q_TYPE_QH:
++		return &periodic->qh->qh_next;
++	case Q_TYPE_FSTN:
++		return &periodic->fstn->fstn_next;
++	default:
++		return &periodic->itd->itd_next;
++	}
++}
++
++static __hc32 *
++shadow_next_periodic(struct fotg210_hcd *fotg210,
++		     union fotg210_shadow *periodic, __hc32 tag)
++{
++	switch (hc32_to_cpu(fotg210, tag)) {
++	/* our fotg210_shadow.qh is actually software part */
++	case Q_TYPE_QH:
++		return &periodic->qh->hw->hw_next;
++	/* others are hw parts */
++	default:
++		return periodic->hw_next;
++	}
++}
++
++/* caller must hold fotg210->lock */
++static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame,
++			    void *ptr)
++{
++	union fotg210_shadow	*prev_p = &fotg210->pshadow[frame];
++	__hc32			*hw_p = &fotg210->periodic[frame];
++	union fotg210_shadow	here = *prev_p;
++
++	/* find predecessor of "ptr"; hw and shadow lists are in sync */
++	while (here.ptr && here.ptr != ptr) {
++		prev_p = periodic_next_shadow(fotg210, prev_p,
++				Q_NEXT_TYPE(fotg210, *hw_p));
++		hw_p = shadow_next_periodic(fotg210, &here,
++				Q_NEXT_TYPE(fotg210, *hw_p));
++		here = *prev_p;
++	}
++	/* an interrupt entry (at list end) could have been shared */
++	if (!here.ptr)
++		return;
++
++	/* update shadow and hardware lists ... the old "next" pointers
++	 * from ptr may still be in use, the caller updates them.
++	 */
++	*prev_p = *periodic_next_shadow(fotg210, &here,
++			Q_NEXT_TYPE(fotg210, *hw_p));
++
++	*hw_p = *shadow_next_periodic(fotg210, &here,
++				Q_NEXT_TYPE(fotg210, *hw_p));
++}
++
++/* how many of the uframe's 125 usecs are allocated? */
++static unsigned short
++periodic_usecs(struct fotg210_hcd *fotg210, unsigned frame, unsigned uframe)
++{
++	__hc32			*hw_p = &fotg210->periodic[frame];
++	union fotg210_shadow	*q = &fotg210->pshadow[frame];
++	unsigned		usecs = 0;
++	struct fotg210_qh_hw	*hw;
++
++	while (q->ptr) {
++		switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) {
++		case Q_TYPE_QH:
++			hw = q->qh->hw;
++			/* is it in the S-mask? */
++			if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe))
++				usecs += q->qh->usecs;
++			/* ... or C-mask? */
++			if (hw->hw_info2 & cpu_to_hc32(fotg210,
++					1 << (8 + uframe)))
++				usecs += q->qh->c_usecs;
++			hw_p = &hw->hw_next;
++			q = &q->qh->qh_next;
++			break;
++		/* case Q_TYPE_FSTN: */
++		default:
++			/* for "save place" FSTNs, count the relevant INTR
++			 * bandwidth from the previous frame
++			 */
++			if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210))
++				fotg210_dbg(fotg210, "ignoring FSTN cost ...\n");
++
++			hw_p = &q->fstn->hw_next;
++			q = &q->fstn->fstn_next;
++			break;
++		case Q_TYPE_ITD:
++			if (q->itd->hw_transaction[uframe])
++				usecs += q->itd->stream->usecs;
++			hw_p = &q->itd->hw_next;
++			q = &q->itd->itd_next;
++			break;
++		}
++	}
++#ifdef	DEBUG
++	if (usecs > fotg210->uframe_periodic_max)
++		fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n",
++			frame * 8 + uframe, usecs);
++#endif
++	return usecs;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int same_tt(struct usb_device *dev1, struct usb_device *dev2)
++{
++	if (!dev1->tt || !dev2->tt)
++		return 0;
++	if (dev1->tt != dev2->tt)
++		return 0;
++	if (dev1->tt->multi)
++		return dev1->ttport == dev2->ttport;
++	else
++		return 1;
++}
++
++/* return true iff the device's transaction translator is available
++ * for a periodic transfer starting at the specified frame, using
++ * all the uframes in the mask.
++ */
++static int tt_no_collision(
++	struct fotg210_hcd		*fotg210,
++	unsigned		period,
++	struct usb_device	*dev,
++	unsigned		frame,
++	u32			uf_mask
++)
++{
++	if (period == 0)	/* error */
++		return 0;
++
++	/* note bandwidth wastage:  split never follows csplit
++	 * (different dev or endpoint) until the next uframe.
++	 * calling convention doesn't make that distinction.
++	 */
++	for (; frame < fotg210->periodic_size; frame += period) {
++		union fotg210_shadow	here;
++		__hc32			type;
++		struct fotg210_qh_hw	*hw;
++
++		here = fotg210->pshadow[frame];
++		type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]);
++		while (here.ptr) {
++			switch (hc32_to_cpu(fotg210, type)) {
++			case Q_TYPE_ITD:
++				type = Q_NEXT_TYPE(fotg210, here.itd->hw_next);
++				here = here.itd->itd_next;
++				continue;
++			case Q_TYPE_QH:
++				hw = here.qh->hw;
++				if (same_tt(dev, here.qh->dev)) {
++					u32		mask;
++
++					mask = hc32_to_cpu(fotg210,
++							hw->hw_info2);
++					/* "knows" no gap is needed */
++					mask |= mask >> 8;
++					if (mask & uf_mask)
++						break;
++				}
++				type = Q_NEXT_TYPE(fotg210, hw->hw_next);
++				here = here.qh->qh_next;
++				continue;
++			/* case Q_TYPE_FSTN: */
++			default:
++				fotg210_dbg(fotg210,
++					"periodic frame %d bogus type %d\n",
++					frame, type);
++			}
++
++			/* collision or error */
++			return 0;
++		}
++	}
++
++	/* no collision */
++	return 1;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void enable_periodic(struct fotg210_hcd *fotg210)
++{
++	if (fotg210->periodic_count++)
++		return;
++
++	/* Stop waiting to turn off the periodic schedule */
++	fotg210->enabled_hrtimer_events &=
++		~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC);
++
++	/* Don't start the schedule until PSS is 0 */
++	fotg210_poll_PSS(fotg210);
++	turn_on_io_watchdog(fotg210);
++}
++
++static void disable_periodic(struct fotg210_hcd *fotg210)
++{
++	if (--fotg210->periodic_count)
++		return;
++
++	/* Don't turn off the schedule until PSS is 1 */
++	fotg210_poll_PSS(fotg210);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* periodic schedule slots have iso tds (normal or split) first, then a
++ * sparse tree for active interrupt transfers.
++ *
++ * this just links in a qh; caller guarantees uframe masks are set right.
++ * no FSTN support (yet; fotg210 0.96+)
++ */
++static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{
++	unsigned	i;
++	unsigned	period = qh->period;
++
++	dev_dbg(&qh->dev->dev,
++		"link qh%d-%04x/%p start %d [%d/%d us]\n",
++		period, hc32_to_cpup(fotg210, &qh->hw->hw_info2)
++			& (QH_CMASK | QH_SMASK),
++		qh, qh->start, qh->usecs, qh->c_usecs);
++
++	/* high bandwidth, or otherwise every microframe */
++	if (period == 0)
++		period = 1;
++
++	for (i = qh->start; i < fotg210->periodic_size; i += period) {
++		union fotg210_shadow	*prev = &fotg210->pshadow[i];
++		__hc32			*hw_p = &fotg210->periodic[i];
++		union fotg210_shadow	here = *prev;
++		__hc32			type = 0;
++
++		/* skip the iso nodes at list head */
++		while (here.ptr) {
++			type = Q_NEXT_TYPE(fotg210, *hw_p);
++			if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
++				break;
++			prev = periodic_next_shadow(fotg210, prev, type);
++			hw_p = shadow_next_periodic(fotg210, &here, type);
++			here = *prev;
++		}
++
++		/* sorting each branch by period (slow-->fast)
++		 * enables sharing interior tree nodes
++		 */
++		while (here.ptr && qh != here.qh) {
++			if (qh->period > here.qh->period)
++				break;
++			prev = &here.qh->qh_next;
++			hw_p = &here.qh->hw->hw_next;
++			here = *prev;
++		}
++		/* link in this qh, unless some earlier pass did that */
++		if (qh != here.qh) {
++			qh->qh_next = here;
++			if (here.qh)
++				qh->hw->hw_next = *hw_p;
++			wmb();
++			prev->qh = qh;
++			*hw_p = QH_NEXT(fotg210, qh->qh_dma);
++		}
++	}
++	qh->qh_state = QH_STATE_LINKED;
++	qh->xacterrs = 0;
++
++	/* update per-qh bandwidth for usbfs */
++	fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period
++		? ((qh->usecs + qh->c_usecs) / qh->period)
++		: (qh->usecs * 8);
++
++	list_add(&qh->intr_node, &fotg210->intr_qh_list);
++
++	/* maybe enable periodic schedule processing */
++	++fotg210->intr_count;
++	enable_periodic(fotg210);
++}
++
++static void qh_unlink_periodic(struct fotg210_hcd *fotg210,
++			       struct fotg210_qh *qh)
++{
++	unsigned	i;
++	unsigned	period;
++
++	/*
++	 * If qh is for a low/full-speed device, simply unlinking it
++	 * could interfere with an ongoing split transaction.  To unlink
++	 * it safely would require setting the QH_INACTIVATE bit and
++	 * waiting at least one frame, as described in EHCI 4.12.2.5.
++	 *
++	 * We won't bother with any of this.  Instead, we assume that the
++	 * only reason for unlinking an interrupt QH while the current URB
++	 * is still active is to dequeue all the URBs (flush the whole
++	 * endpoint queue).
++	 *
++	 * If rebalancing the periodic schedule is ever implemented, this
++	 * approach will no longer be valid.
++	 */
++
++	/* high bandwidth, or otherwise part of every microframe */
++	period = qh->period;
++	if (!period)
++		period = 1;
++
++	for (i = qh->start; i < fotg210->periodic_size; i += period)
++		periodic_unlink(fotg210, i, qh);
++
++	/* update per-qh bandwidth for usbfs */
++	fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period
++		? ((qh->usecs + qh->c_usecs) / qh->period)
++		: (qh->usecs * 8);
++
++	dev_dbg(&qh->dev->dev,
++		"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
++		qh->period,
++		hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
++		(QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs);
++
++	/* qh->qh_next still "live" to HC */
++	qh->qh_state = QH_STATE_UNLINK;
++	qh->qh_next.ptr = NULL;
++
++	if (fotg210->qh_scan_next == qh)
++		fotg210->qh_scan_next = list_entry(qh->intr_node.next,
++				struct fotg210_qh, intr_node);
++	list_del(&qh->intr_node);
++}
++
++static void start_unlink_intr(struct fotg210_hcd *fotg210,
++			      struct fotg210_qh *qh)
++{
++	/* If the QH isn't linked then there's nothing we can do
++	 * unless we were called during a giveback, in which case
++	 * qh_completions() has to deal with it.
++	 */
++	if (qh->qh_state != QH_STATE_LINKED) {
++		if (qh->qh_state == QH_STATE_COMPLETING)
++			qh->needs_rescan = 1;
++		return;
++	}
++
++	qh_unlink_periodic(fotg210, qh);
++
++	/* Make sure the unlinks are visible before starting the timer */
++	wmb();
++
++	/*
++	 * The EHCI spec doesn't say how long it takes the controller to
++	 * stop accessing an unlinked interrupt QH.  The timer delay is
++	 * 9 uframes; presumably that will be long enough.
++	 */
++	qh->unlink_cycle = fotg210->intr_unlink_cycle;
++
++	/* New entries go at the end of the intr_unlink list */
++	if (fotg210->intr_unlink)
++		fotg210->intr_unlink_last->unlink_next = qh;
++	else
++		fotg210->intr_unlink = qh;
++	fotg210->intr_unlink_last = qh;
++
++	if (fotg210->intr_unlinking)
++		;	/* Avoid recursive calls */
++	else if (fotg210->rh_state < FOTG210_RH_RUNNING)
++		fotg210_handle_intr_unlinks(fotg210);
++	else if (fotg210->intr_unlink == qh) {
++		fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
++				     true);
++		++fotg210->intr_unlink_cycle;
++	}
++}
++
++static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{
++	struct fotg210_qh_hw	*hw = qh->hw;
++	int			rc;
++
++	qh->qh_state = QH_STATE_IDLE;
++	hw->hw_next = FOTG210_LIST_END(fotg210);
++
++	qh_completions(fotg210, qh);
++
++	/* reschedule QH iff another request is queued */
++	if (!list_empty(&qh->qtd_list) &&
++	    fotg210->rh_state == FOTG210_RH_RUNNING) {
++		rc = qh_schedule(fotg210, qh);
++
++		/* An error here likely indicates handshake failure
++		 * or no space left in the schedule.  Neither fault
++		 * should happen often ...
++		 *
++		 * FIXME kill the now-dysfunctional queued urbs
++		 */
++		if (rc != 0)
++			fotg210_err(fotg210, "can't reschedule qh %p, err %d\n",
++					qh, rc);
++	}
++
++	/* maybe turn off periodic schedule */
++	--fotg210->intr_count;
++	disable_periodic(fotg210);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int check_period(
++	struct fotg210_hcd *fotg210,
++	unsigned	frame,
++	unsigned	uframe,
++	unsigned	period,
++	unsigned	usecs
++) {
++	int		claimed;
++
++	/* complete split running into next frame?
++	 * given FSTN support, we could sometimes check...
++	 */
++	if (uframe >= 8)
++		return 0;
++
++	/* convert "usecs we need" to "max already claimed" */
++	usecs = fotg210->uframe_periodic_max - usecs;
++
++	/* we "know" 2 and 4 uframe intervals were rejected; so
++	 * for period 0, check _every_ microframe in the schedule.
++	 */
++	if (unlikely(period == 0)) {
++		do {
++			for (uframe = 0; uframe < 7; uframe++) {
++				claimed = periodic_usecs(fotg210, frame,
++							 uframe);
++				if (claimed > usecs)
++					return 0;
++			}
++		} while ((frame += 1) < fotg210->periodic_size);
++
++	/* just check the specified uframe, at that period */
++	} else {
++		do {
++			claimed = periodic_usecs(fotg210, frame, uframe);
++			if (claimed > usecs)
++				return 0;
++		} while ((frame += period) < fotg210->periodic_size);
++	}
++
++	/* success! */
++	return 1;
++}
++
++static int check_intr_schedule(
++	struct fotg210_hcd		*fotg210,
++	unsigned		frame,
++	unsigned		uframe,
++	const struct fotg210_qh	*qh,
++	__hc32			*c_maskp
++)
++{
++	int		retval = -ENOSPC;
++	u8		mask = 0;
++
++	if (qh->c_usecs && uframe >= 6)		/* FSTN territory? */
++		goto done;
++
++	if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs))
++		goto done;
++	if (!qh->c_usecs) {
++		retval = 0;
++		*c_maskp = 0;
++		goto done;
++	}
++
++	/* Make sure this tt's buffer is also available for CSPLITs.
++	 * We pessimize a bit; probably the typical full speed case
++	 * doesn't need the second CSPLIT.
++	 *
++	 * NOTE:  both SPLIT and CSPLIT could be checked in just
++	 * one smart pass...
++	 */
++	mask = 0x03 << (uframe + qh->gap_uf);
++	*c_maskp = cpu_to_hc32(fotg210, mask << 8);
++
++	mask |= 1 << uframe;
++	if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) {
++		if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1,
++					qh->period, qh->c_usecs))
++			goto done;
++		if (!check_period(fotg210, frame, uframe + qh->gap_uf,
++					qh->period, qh->c_usecs))
++			goto done;
++		retval = 0;
++	}
++done:
++	return retval;
++}
++
++/* "first fit" scheduling policy used the first time through,
++ * or when the previous schedule slot can't be re-used.
++ */
++static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
++{
++	int		status;
++	unsigned	uframe;
++	__hc32		c_mask;
++	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
++	struct fotg210_qh_hw	*hw = qh->hw;
++
++	qh_refresh(fotg210, qh);
++	hw->hw_next = FOTG210_LIST_END(fotg210);
++	frame = qh->start;
++
++	/* reuse the previous schedule slots, if we can */
++	if (frame < qh->period) {
++		uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK);
++		status = check_intr_schedule(fotg210, frame, --uframe,
++				qh, &c_mask);
++	} else {
++		uframe = 0;
++		c_mask = 0;
++		status = -ENOSPC;
++	}
++
++	/* else scan the schedule to find a group of slots such that all
++	 * uframes have enough periodic bandwidth available.
++	 */
++	if (status) {
++		/* "normal" case, uframing flexible except with splits */
++		if (qh->period) {
++			int		i;
++
++			for (i = qh->period; status && i > 0; --i) {
++				frame = ++fotg210->random_frame % qh->period;
++				for (uframe = 0; uframe < 8; uframe++) {
++					status = check_intr_schedule(fotg210,
++							frame, uframe, qh,
++							&c_mask);
++					if (status == 0)
++						break;
++				}
++			}
++
++		/* qh->period == 0 means every uframe */
++		} else {
++			frame = 0;
++			status = check_intr_schedule(fotg210, 0, 0, qh,
++						     &c_mask);
++		}
++		if (status)
++			goto done;
++		qh->start = frame;
++
++		/* reset S-frame and (maybe) C-frame masks */
++		hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK));
++		hw->hw_info2 |= qh->period
++			? cpu_to_hc32(fotg210, 1 << uframe)
++			: cpu_to_hc32(fotg210, QH_SMASK);
++		hw->hw_info2 |= c_mask;
++	} else
++		fotg210_dbg(fotg210, "reused qh %p schedule\n", qh);
++
++	/* stuff into the periodic schedule */
++	qh_link_periodic(fotg210, qh);
++done:
++	return status;
++}
++
++static int intr_submit(
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	struct list_head	*qtd_list,
++	gfp_t			mem_flags
++) {
++	unsigned		epnum;
++	unsigned long		flags;
++	struct fotg210_qh		*qh;
++	int			status;
++	struct list_head	empty;
++
++	/* get endpoint and transfer/schedule data */
++	epnum = urb->ep->desc.bEndpointAddress;
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++
++	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
++		status = -ESHUTDOWN;
++		goto done_not_linked;
++	}
++	status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
++	if (unlikely(status))
++		goto done_not_linked;
++
++	/* get qh and force any scheduling errors */
++	INIT_LIST_HEAD(&empty);
++	qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv);
++	if (qh == NULL) {
++		status = -ENOMEM;
++		goto done;
++	}
++	if (qh->qh_state == QH_STATE_IDLE) {
++		status = qh_schedule(fotg210, qh);
++		if (status)
++			goto done;
++	}
++
++	/* then queue the urb's tds to the qh */
++	qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
++	BUG_ON(qh == NULL);
++
++	/* ... update usbfs periodic stats */
++	fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++;
++
++done:
++	if (unlikely(status))
++		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
++done_not_linked:
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	if (status)
++		qtd_list_free(fotg210, urb, qtd_list);
++
++	return status;
++}
++
++static void scan_intr(struct fotg210_hcd *fotg210)
++{
++	struct fotg210_qh		*qh;
++
++	list_for_each_entry_safe(qh, fotg210->qh_scan_next,
++				 &fotg210->intr_qh_list, intr_node) {
++ rescan:
++		/* clean any finished work for this qh */
++		if (!list_empty(&qh->qtd_list)) {
++			int temp;
++
++			/*
++			 * Unlinks could happen here; completion reporting
++			 * drops the lock.  That's why fotg210->qh_scan_next
++			 * always holds the next qh to scan; if the next qh
++			 * gets unlinked then fotg210->qh_scan_next is adjusted
++			 * in qh_unlink_periodic().
++			 */
++			temp = qh_completions(fotg210, qh);
++			if (unlikely(qh->needs_rescan ||
++					(list_empty(&qh->qtd_list) &&
++						qh->qh_state == QH_STATE_LINKED)))
++				start_unlink_intr(fotg210, qh);
++			else if (temp != 0)
++				goto rescan;
++		}
++	}
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* fotg210_iso_stream ops work with both ITD and SITD */
++
++static struct fotg210_iso_stream *
++iso_stream_alloc(gfp_t mem_flags)
++{
++	struct fotg210_iso_stream *stream;
++
++	stream = kzalloc(sizeof(*stream), mem_flags);
++	if (likely(stream != NULL)) {
++		INIT_LIST_HEAD(&stream->td_list);
++		INIT_LIST_HEAD(&stream->free_list);
++		stream->next_uframe = -1;
++	}
++	return stream;
++}
++
++static void
++iso_stream_init(
++	struct fotg210_hcd		*fotg210,
++	struct fotg210_iso_stream	*stream,
++	struct usb_device	*dev,
++	int			pipe,
++	unsigned		interval
++)
++{
++	u32			buf1;
++	unsigned		epnum, maxp;
++	int			is_input;
++	long			bandwidth;
++	unsigned 		multi;
++
++	/*
++	 * this might be a "high bandwidth" highspeed endpoint,
++	 * as encoded in the ep descriptor's wMaxPacket field
++	 */
++	epnum = usb_pipeendpoint(pipe);
++	is_input = usb_pipein(pipe) ? USB_DIR_IN : 0;
++	maxp = usb_maxpacket(dev, pipe, !is_input);
++	if (is_input)
++		buf1 = (1 << 11);
++	else
++		buf1 = 0;
++
++	maxp = max_packet(maxp);
++	multi = hb_mult(maxp);
++	buf1 |= maxp;
++	maxp *= multi;
++
++	stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum);
++	stream->buf1 = cpu_to_hc32(fotg210, buf1);
++	stream->buf2 = cpu_to_hc32(fotg210, multi);
++
++	/* usbfs wants to report the average usecs per frame tied up
++	 * when transfers on this endpoint are scheduled ...
++	 */
++	if (dev->speed == USB_SPEED_FULL) {
++		interval <<= 3;
++		stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed,
++				is_input, 1, maxp));
++		stream->usecs /= 8;
++	} else {
++		stream->highspeed = 1;
++		stream->usecs = HS_USECS_ISO(maxp);
++	}
++	bandwidth = stream->usecs * 8;
++	bandwidth /= interval;
++
++	stream->bandwidth = bandwidth;
++	stream->udev = dev;
++	stream->bEndpointAddress = is_input | epnum;
++	stream->interval = interval;
++	stream->maxp = maxp;
++}
++
++static struct fotg210_iso_stream *
++iso_stream_find(struct fotg210_hcd *fotg210, struct urb *urb)
++{
++	unsigned		epnum;
++	struct fotg210_iso_stream	*stream;
++	struct usb_host_endpoint *ep;
++	unsigned long		flags;
++
++	epnum = usb_pipeendpoint(urb->pipe);
++	if (usb_pipein(urb->pipe))
++		ep = urb->dev->ep_in[epnum];
++	else
++		ep = urb->dev->ep_out[epnum];
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++	stream = ep->hcpriv;
++
++	if (unlikely(stream == NULL)) {
++		stream = iso_stream_alloc(GFP_ATOMIC);
++		if (likely(stream != NULL)) {
++			ep->hcpriv = stream;
++			stream->ep = ep;
++			iso_stream_init(fotg210, stream, urb->dev, urb->pipe,
++					urb->interval);
++		}
++
++	/* if dev->ep[epnum] is a QH, hw is set */
++	} else if (unlikely(stream->hw != NULL)) {
++		fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n",
++			urb->dev->devpath, epnum,
++			usb_pipein(urb->pipe) ? "in" : "out");
++		stream = NULL;
++	}
++
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	return stream;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* fotg210_iso_sched ops can be ITD-only or SITD-only */
++
++static struct fotg210_iso_sched *
++iso_sched_alloc(unsigned packets, gfp_t mem_flags)
++{
++	struct fotg210_iso_sched	*iso_sched;
++	int			size = sizeof(*iso_sched);
++
++	size += packets * sizeof(struct fotg210_iso_packet);
++	iso_sched = kzalloc(size, mem_flags);
++	if (likely(iso_sched != NULL))
++		INIT_LIST_HEAD(&iso_sched->td_list);
++
++	return iso_sched;
++}
++
++static inline void
++itd_sched_init(
++	struct fotg210_hcd		*fotg210,
++	struct fotg210_iso_sched	*iso_sched,
++	struct fotg210_iso_stream	*stream,
++	struct urb		*urb
++)
++{
++	unsigned	i;
++	dma_addr_t	dma = urb->transfer_dma;
++
++	/* how many uframes are needed for these transfers */
++	iso_sched->span = urb->number_of_packets * stream->interval;
++
++	/* figure out per-uframe itd fields that we'll need later
++	 * when we fit new itds into the schedule.
++	 */
++	for (i = 0; i < urb->number_of_packets; i++) {
++		struct fotg210_iso_packet	*uframe = &iso_sched->packet[i];
++		unsigned		length;
++		dma_addr_t		buf;
++		u32			trans;
++
++		length = urb->iso_frame_desc[i].length;
++		buf = dma + urb->iso_frame_desc[i].offset;
++
++		trans = FOTG210_ISOC_ACTIVE;
++		trans |= buf & 0x0fff;
++		if (unlikely(((i + 1) == urb->number_of_packets))
++				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
++			trans |= FOTG210_ITD_IOC;
++		trans |= length << 16;
++		uframe->transaction = cpu_to_hc32(fotg210, trans);
++
++		/* might need to cross a buffer page within a uframe */
++		uframe->bufp = (buf & ~(u64)0x0fff);
++		buf += length;
++		if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff))))
++			uframe->cross = 1;
++	}
++}
++
++static void
++iso_sched_free(
++	struct fotg210_iso_stream	*stream,
++	struct fotg210_iso_sched	*iso_sched
++)
++{
++	if (!iso_sched)
++		return;
++	/* caller must hold fotg210->lock!*/
++	list_splice(&iso_sched->td_list, &stream->free_list);
++	kfree(iso_sched);
++}
++
++static int
++itd_urb_transaction(
++	struct fotg210_iso_stream	*stream,
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	gfp_t			mem_flags
++)
++{
++	struct fotg210_itd		*itd;
++	dma_addr_t		itd_dma;
++	int			i;
++	unsigned		num_itds;
++	struct fotg210_iso_sched	*sched;
++	unsigned long		flags;
++
++	sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
++	if (unlikely(sched == NULL))
++		return -ENOMEM;
++
++	itd_sched_init(fotg210, sched, stream, urb);
++
++	if (urb->interval < 8)
++		num_itds = 1 + (sched->span + 7) / 8;
++	else
++		num_itds = urb->number_of_packets;
++
++	/* allocate/init ITDs */
++	spin_lock_irqsave(&fotg210->lock, flags);
++	for (i = 0; i < num_itds; i++) {
++
++		/*
++		 * Use iTDs from the free list, but not iTDs that may
++		 * still be in use by the hardware.
++		 */
++		if (likely(!list_empty(&stream->free_list))) {
++			itd = list_first_entry(&stream->free_list,
++					struct fotg210_itd, itd_list);
++			if (itd->frame == fotg210->now_frame)
++				goto alloc_itd;
++			list_del(&itd->itd_list);
++			itd_dma = itd->itd_dma;
++		} else {
++ alloc_itd:
++			spin_unlock_irqrestore(&fotg210->lock, flags);
++			itd = dma_pool_alloc(fotg210->itd_pool, mem_flags,
++					&itd_dma);
++			spin_lock_irqsave(&fotg210->lock, flags);
++			if (!itd) {
++				iso_sched_free(stream, sched);
++				spin_unlock_irqrestore(&fotg210->lock, flags);
++				return -ENOMEM;
++			}
++		}
++
++		memset(itd, 0, sizeof(*itd));
++		itd->itd_dma = itd_dma;
++		list_add(&itd->itd_list, &sched->td_list);
++	}
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++
++	/* temporarily store schedule info in hcpriv */
++	urb->hcpriv = sched;
++	urb->error_count = 0;
++	return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static inline int
++itd_slot_ok(
++	struct fotg210_hcd		*fotg210,
++	u32			mod,
++	u32			uframe,
++	u8			usecs,
++	u32			period
++)
++{
++	uframe %= period;
++	do {
++		/* can't commit more than uframe_periodic_max usec */
++		if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7)
++				> (fotg210->uframe_periodic_max - usecs))
++			return 0;
++
++		/* we know urb->interval is 2^N uframes */
++		uframe += period;
++	} while (uframe < mod);
++	return 1;
++}
++
++/*
++ * This scheduler plans almost as far into the future as it has actual
++ * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
++ * "as small as possible" to be cache-friendlier.)  That limits the size
++ * transfers you can stream reliably; avoid more than 64 msec per urb.
++ * Also avoid queue depths of less than fotg210's worst irq latency (affected
++ * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
++ * and other factors); or more than about 230 msec total (for portability,
++ * given FOTG210_TUNE_FLS and the slop).  Or, write a smarter scheduler!
++ */
++
++#define SCHEDULE_SLOP	80	/* microframes */
++
++static int
++iso_stream_schedule(
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	struct fotg210_iso_stream	*stream
++)
++{
++	u32			now, next, start, period, span;
++	int			status;
++	unsigned		mod = fotg210->periodic_size << 3;
++	struct fotg210_iso_sched	*sched = urb->hcpriv;
++
++	period = urb->interval;
++	span = sched->span;
++
++	if (span > mod - SCHEDULE_SLOP) {
++		fotg210_warn(fotg210, "iso request %p too long\n", urb);
++		status = -EFBIG;
++		goto fail;
++	}
++
++	now = fotg210_read_frame_index(fotg210) & (mod - 1);
++
++	/* Typical case: reuse current schedule, stream is still active.
++	 * Hopefully there are no gaps from the host falling behind
++	 * (irq delays etc), but if there are we'll take the next
++	 * slot in the schedule, implicitly assuming URB_ISO_ASAP.
++	 */
++	if (likely(!list_empty(&stream->td_list))) {
++		u32	excess;
++
++		/* For high speed devices, allow scheduling within the
++		 * isochronous scheduling threshold.  For full speed devices
++		 * and Intel PCI-based controllers, don't (work around for
++		 * Intel ICH9 bug).
++		 */
++		if (!stream->highspeed && fotg210->fs_i_thresh)
++			next = now + fotg210->i_thresh;
++		else
++			next = now;
++
++		/* Fell behind (by up to twice the slop amount)?
++		 * We decide based on the time of the last currently-scheduled
++		 * slot, not the time of the next available slot.
++		 */
++		excess = (stream->next_uframe - period - next) & (mod - 1);
++		if (excess >= mod - 2 * SCHEDULE_SLOP)
++			start = next + excess - mod + period *
++					DIV_ROUND_UP(mod - excess, period);
++		else
++			start = next + excess + period;
++		if (start - now >= mod) {
++			fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
++					urb, start - now - period, period,
++					mod);
++			status = -EFBIG;
++			goto fail;
++		}
++	}
++
++	/* need to schedule; when's the next (u)frame we could start?
++	 * this is bigger than fotg210->i_thresh allows; scheduling itself
++	 * isn't free, the slop should handle reasonably slow cpus.  it
++	 * can also help high bandwidth if the dma and irq loads don't
++	 * jump until after the queue is primed.
++	 */
++	else {
++		int done = 0;
++		start = SCHEDULE_SLOP + (now & ~0x07);
++
++		/* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
++
++		/* find a uframe slot with enough bandwidth.
++		 * Early uframes are more precious because full-speed
++		 * iso IN transfers can't use late uframes,
++		 * and therefore they should be allocated last.
++		 */
++		next = start;
++		start += period;
++		do {
++			start--;
++			/* check schedule: enough space? */
++			if (itd_slot_ok(fotg210, mod, start,
++					stream->usecs, period))
++				done = 1;
++		} while (start > next && !done);
++
++		/* no room in the schedule */
++		if (!done) {
++			fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n",
++				urb, now, now + mod);
++			status = -ENOSPC;
++			goto fail;
++		}
++	}
++
++	/* Tried to schedule too far into the future? */
++	if (unlikely(start - now + span - period
++				>= mod - 2 * SCHEDULE_SLOP)) {
++		fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
++				urb, start - now, span - period,
++				mod - 2 * SCHEDULE_SLOP);
++		status = -EFBIG;
++		goto fail;
++	}
++
++	stream->next_uframe = start & (mod - 1);
++
++	/* report high speed start in uframes; full speed, in frames */
++	urb->start_frame = stream->next_uframe;
++	if (!stream->highspeed)
++		urb->start_frame >>= 3;
++
++	/* Make sure scan_isoc() sees these */
++	if (fotg210->isoc_count == 0)
++		fotg210->next_frame = now >> 3;
++	return 0;
++
++ fail:
++	iso_sched_free(stream, sched);
++	urb->hcpriv = NULL;
++	return status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static inline void
++itd_init(struct fotg210_hcd *fotg210, struct fotg210_iso_stream *stream,
++		struct fotg210_itd *itd)
++{
++	int i;
++
++	/* it's been recently zeroed */
++	itd->hw_next = FOTG210_LIST_END(fotg210);
++	itd->hw_bufp[0] = stream->buf0;
++	itd->hw_bufp[1] = stream->buf1;
++	itd->hw_bufp[2] = stream->buf2;
++
++	for (i = 0; i < 8; i++)
++		itd->index[i] = -1;
++
++	/* All other fields are filled when scheduling */
++}
++
++static inline void
++itd_patch(
++	struct fotg210_hcd		*fotg210,
++	struct fotg210_itd		*itd,
++	struct fotg210_iso_sched	*iso_sched,
++	unsigned		index,
++	u16			uframe
++)
++{
++	struct fotg210_iso_packet	*uf = &iso_sched->packet[index];
++	unsigned		pg = itd->pg;
++
++	uframe &= 0x07;
++	itd->index[uframe] = index;
++
++	itd->hw_transaction[uframe] = uf->transaction;
++	itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12);
++	itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0);
++	itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32));
++
++	/* iso_frame_desc[].offset must be strictly increasing */
++	if (unlikely(uf->cross)) {
++		u64	bufp = uf->bufp + 4096;
++
++		itd->pg = ++pg;
++		itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0);
++		itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32));
++	}
++}
++
++static inline void
++itd_link(struct fotg210_hcd *fotg210, unsigned frame, struct fotg210_itd *itd)
++{
++	union fotg210_shadow	*prev = &fotg210->pshadow[frame];
++	__hc32			*hw_p = &fotg210->periodic[frame];
++	union fotg210_shadow	here = *prev;
++	__hc32			type = 0;
++
++	/* skip any iso nodes which might belong to previous microframes */
++	while (here.ptr) {
++		type = Q_NEXT_TYPE(fotg210, *hw_p);
++		if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
++			break;
++		prev = periodic_next_shadow(fotg210, prev, type);
++		hw_p = shadow_next_periodic(fotg210, &here, type);
++		here = *prev;
++	}
++
++	itd->itd_next = here;
++	itd->hw_next = *hw_p;
++	prev->itd = itd;
++	itd->frame = frame;
++	wmb();
++	*hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD);
++}
++
++/* fit urb's itds into the selected schedule slot; activate as needed */
++static void itd_link_urb(
++	struct fotg210_hcd		*fotg210,
++	struct urb		*urb,
++	unsigned		mod,
++	struct fotg210_iso_stream	*stream
++)
++{
++	int			packet;
++	unsigned		next_uframe, uframe, frame;
++	struct fotg210_iso_sched	*iso_sched = urb->hcpriv;
++	struct fotg210_itd		*itd;
++
++	next_uframe = stream->next_uframe & (mod - 1);
++
++	if (unlikely(list_empty(&stream->td_list))) {
++		fotg210_to_hcd(fotg210)->self.bandwidth_allocated
++				+= stream->bandwidth;
++		fotg210_vdbg(fotg210,
++			"schedule devp %s ep%d%s-iso period %d start %d.%d\n",
++			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
++			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
++			urb->interval,
++			next_uframe >> 3, next_uframe & 0x7);
++	}
++
++	/* fill iTDs uframe by uframe */
++	for (packet = 0, itd = NULL; packet < urb->number_of_packets;) {
++		if (itd == NULL) {
++			/* ASSERT:  we have all necessary itds */
++
++			/* ASSERT:  no itds for this endpoint in this uframe */
++
++			itd = list_entry(iso_sched->td_list.next,
++					struct fotg210_itd, itd_list);
++			list_move_tail(&itd->itd_list, &stream->td_list);
++			itd->stream = stream;
++			itd->urb = urb;
++			itd_init(fotg210, stream, itd);
++		}
++
++		uframe = next_uframe & 0x07;
++		frame = next_uframe >> 3;
++
++		itd_patch(fotg210, itd, iso_sched, packet, uframe);
++
++		next_uframe += stream->interval;
++		next_uframe &= mod - 1;
++		packet++;
++
++		/* link completed itds into the schedule */
++		if (((next_uframe >> 3) != frame)
++				|| packet == urb->number_of_packets) {
++			itd_link(fotg210, frame & (fotg210->periodic_size - 1),
++				 itd);
++			itd = NULL;
++		}
++	}
++	stream->next_uframe = next_uframe;
++
++	/* don't need that schedule data any more */
++	iso_sched_free(stream, iso_sched);
++	urb->hcpriv = NULL;
++
++	++fotg210->isoc_count;
++	enable_periodic(fotg210);
++}
++
++#define	ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\
++		  FOTG210_ISOC_XACTERR)
++
++/* Process and recycle a completed ITD.  Return true iff its urb completed,
++ * and hence its completion callback probably added things to the hardware
++ * schedule.
++ *
++ * Note that we carefully avoid recycling this descriptor until after any
++ * completion callback runs, so that it won't be reused quickly.  That is,
++ * assuming (a) no more than two urbs per frame on this endpoint, and also
++ * (b) only this endpoint's completions submit URBs.  It seems some silicon
++ * corrupts things if you reuse completed descriptors very quickly...
++ */
++static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
++{
++	struct urb				*urb = itd->urb;
++	struct usb_iso_packet_descriptor	*desc;
++	u32					t;
++	unsigned				uframe;
++	int					urb_index = -1;
++	struct fotg210_iso_stream			*stream = itd->stream;
++	struct usb_device			*dev;
++	bool					retval = false;
++
++	/* for each uframe with a packet */
++	for (uframe = 0; uframe < 8; uframe++) {
++		if (likely(itd->index[uframe] == -1))
++			continue;
++		urb_index = itd->index[uframe];
++		desc = &urb->iso_frame_desc[urb_index];
++
++		t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]);
++		itd->hw_transaction[uframe] = 0;
++
++		/* report transfer status */
++		if (unlikely(t & ISO_ERRS)) {
++			urb->error_count++;
++			if (t & FOTG210_ISOC_BUF_ERR)
++				desc->status = usb_pipein(urb->pipe)
++					? -ENOSR  /* hc couldn't read */
++					: -ECOMM; /* hc couldn't write */
++			else if (t & FOTG210_ISOC_BABBLE)
++				desc->status = -EOVERFLOW;
++			else /* (t & FOTG210_ISOC_XACTERR) */
++				desc->status = -EPROTO;
++
++			/* HC need not update length with this error */
++			if (!(t & FOTG210_ISOC_BABBLE)) {
++				desc->actual_length =
++					fotg210_itdlen(urb, desc, t);
++				urb->actual_length += desc->actual_length;
++			}
++		} else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) {
++			desc->status = 0;
++			desc->actual_length = fotg210_itdlen(urb, desc, t);
++			urb->actual_length += desc->actual_length;
++		} else {
++			/* URB was too late */
++			desc->status = -EXDEV;
++		}
++	}
++
++	/* handle completion now? */
++	if (likely((urb_index + 1) != urb->number_of_packets))
++		goto done;
++
++	/* ASSERT: it's really the last itd for this urb
++	list_for_each_entry (itd, &stream->td_list, itd_list)
++		BUG_ON (itd->urb == urb);
++	 */
++
++	/* give urb back to the driver; completion often (re)submits */
++	dev = urb->dev;
++	fotg210_urb_done(fotg210, urb, 0);
++	retval = true;
++	urb = NULL;
++
++	--fotg210->isoc_count;
++	disable_periodic(fotg210);
++
++	if (unlikely(list_is_singular(&stream->td_list))) {
++		fotg210_to_hcd(fotg210)->self.bandwidth_allocated
++				-= stream->bandwidth;
++		fotg210_vdbg(fotg210,
++			"deschedule devp %s ep%d%s-iso\n",
++			dev->devpath, stream->bEndpointAddress & 0x0f,
++			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
++	}
++
++done:
++	itd->urb = NULL;
++
++	/* Add to the end of the free list for later reuse */
++	list_move_tail(&itd->itd_list, &stream->free_list);
++
++	/* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
++	if (list_empty(&stream->td_list)) {
++		list_splice_tail_init(&stream->free_list,
++				&fotg210->cached_itd_list);
++		start_free_itds(fotg210);
++	}
++
++	return retval;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
++	gfp_t mem_flags)
++{
++	int			status = -EINVAL;
++	unsigned long		flags;
++	struct fotg210_iso_stream	*stream;
++
++	/* Get iso_stream head */
++	stream = iso_stream_find(fotg210, urb);
++	if (unlikely(stream == NULL)) {
++		fotg210_err(fotg210, "can't get iso stream\n");
++		return -ENOMEM;
++	}
++	if (unlikely(urb->interval != stream->interval &&
++		      fotg210_port_speed(fotg210, 0) ==
++				USB_PORT_STAT_HIGH_SPEED)) {
++			fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n",
++				stream->interval, urb->interval);
++			goto done;
++	}
++
++#ifdef FOTG210_URB_TRACE
++	fotg210_dbg(fotg210,
++		"%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n",
++		__func__, urb->dev->devpath, urb,
++		usb_pipeendpoint(urb->pipe),
++		usb_pipein(urb->pipe) ? "in" : "out",
++		urb->transfer_buffer_length,
++		urb->number_of_packets, urb->interval,
++		stream);
++#endif
++
++	/* allocate ITDs w/o locking anything */
++	status = itd_urb_transaction(stream, fotg210, urb, mem_flags);
++	if (unlikely(status < 0)) {
++		fotg210_dbg(fotg210, "can't init itds\n");
++		goto done;
++	}
++
++	/* schedule ... need to lock */
++	spin_lock_irqsave(&fotg210->lock, flags);
++	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
++		status = -ESHUTDOWN;
++		goto done_not_linked;
++	}
++	status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
++	if (unlikely(status))
++		goto done_not_linked;
++	status = iso_stream_schedule(fotg210, urb, stream);
++	if (likely(status == 0))
++		itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream);
++	else
++		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
++ done_not_linked:
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++ done:
++	return status;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void scan_isoc(struct fotg210_hcd *fotg210)
++{
++	unsigned	uf, now_frame, frame;
++	unsigned	fmask = fotg210->periodic_size - 1;
++	bool		modified, live;
++
++	/*
++	 * When running, scan from last scan point up to "now"
++	 * else clean up by scanning everything that's left.
++	 * Touches as few pages as possible:  cache-friendly.
++	 */
++	if (fotg210->rh_state >= FOTG210_RH_RUNNING) {
++		uf = fotg210_read_frame_index(fotg210);
++		now_frame = (uf >> 3) & fmask;
++		live = true;
++	} else  {
++		now_frame = (fotg210->next_frame - 1) & fmask;
++		live = false;
++	}
++	fotg210->now_frame = now_frame;
++
++	frame = fotg210->next_frame;
++	for (;;) {
++		union fotg210_shadow	q, *q_p;
++		__hc32			type, *hw_p;
++
++restart:
++		/* scan each element in frame's queue for completions */
++		q_p = &fotg210->pshadow[frame];
++		hw_p = &fotg210->periodic[frame];
++		q.ptr = q_p->ptr;
++		type = Q_NEXT_TYPE(fotg210, *hw_p);
++		modified = false;
++
++		while (q.ptr != NULL) {
++			switch (hc32_to_cpu(fotg210, type)) {
++			case Q_TYPE_ITD:
++				/* If this ITD is still active, leave it for
++				 * later processing ... check the next entry.
++				 * No need to check for activity unless the
++				 * frame is current.
++				 */
++				if (frame == now_frame && live) {
++					rmb();
++					for (uf = 0; uf < 8; uf++) {
++						if (q.itd->hw_transaction[uf] &
++							    ITD_ACTIVE(fotg210))
++							break;
++					}
++					if (uf < 8) {
++						q_p = &q.itd->itd_next;
++						hw_p = &q.itd->hw_next;
++						type = Q_NEXT_TYPE(fotg210,
++							q.itd->hw_next);
++						q = *q_p;
++						break;
++					}
++				}
++
++				/* Take finished ITDs out of the schedule
++				 * and process them:  recycle, maybe report
++				 * URB completion.  HC won't cache the
++				 * pointer for much longer, if at all.
++				 */
++				*q_p = q.itd->itd_next;
++				*hw_p = q.itd->hw_next;
++				type = Q_NEXT_TYPE(fotg210, q.itd->hw_next);
++				wmb();
++				modified = itd_complete(fotg210, q.itd);
++				q = *q_p;
++				break;
++			default:
++				fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n",
++					type, frame, q.ptr);
++				/* FALL THROUGH */
++			case Q_TYPE_QH:
++			case Q_TYPE_FSTN:
++				/* End of the iTDs and siTDs */
++				q.ptr = NULL;
++				break;
++			}
++
++			/* assume completion callbacks modify the queue */
++			if (unlikely(modified && fotg210->isoc_count > 0))
++				goto restart;
++		}
++
++		/* Stop when we have reached the current frame */
++		if (frame == now_frame)
++			break;
++		frame = (frame + 1) & fmask;
++	}
++	fotg210->next_frame = now_frame;
++}
++/*-------------------------------------------------------------------------*/
++/*
++ * Display / Set uframe_periodic_max
++ */
++static ssize_t show_uframe_periodic_max(struct device *dev,
++					struct device_attribute *attr,
++					char *buf)
++{
++	struct fotg210_hcd		*fotg210;
++	int			n;
++
++	fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
++	n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max);
++	return n;
++}
++
++
++static ssize_t store_uframe_periodic_max(struct device *dev,
++					struct device_attribute *attr,
++					const char *buf, size_t count)
++{
++	struct fotg210_hcd		*fotg210;
++	unsigned		uframe_periodic_max;
++	unsigned		frame, uframe;
++	unsigned short		allocated_max;
++	unsigned long		flags;
++	ssize_t			ret;
++
++	fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
++	if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
++		return -EINVAL;
++
++	if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
++		fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n",
++			     uframe_periodic_max);
++		return -EINVAL;
++	}
++
++	ret = -EINVAL;
++
++	/*
++	 * lock, so that our checking does not race with possible periodic
++	 * bandwidth allocation through submitting new urbs.
++	 */
++	spin_lock_irqsave(&fotg210->lock, flags);
++
++	/*
++	 * for request to decrease max periodic bandwidth, we have to check
++	 * every microframe in the schedule to see whether the decrease is
++	 * possible.
++	 */
++	if (uframe_periodic_max < fotg210->uframe_periodic_max) {
++		allocated_max = 0;
++
++		for (frame = 0; frame < fotg210->periodic_size; ++frame)
++			for (uframe = 0; uframe < 7; ++uframe)
++				allocated_max = max(allocated_max,
++						    periodic_usecs(fotg210, frame, uframe));
++
++		if (allocated_max > uframe_periodic_max) {
++			fotg210_info(fotg210,
++				"cannot decrease uframe_periodic_max becase "
++				"periodic bandwidth is already allocated "
++				"(%u > %u)\n",
++				allocated_max, uframe_periodic_max);
++			goto out_unlock;
++		}
++	}
++
++	/* increasing is always ok */
++
++	fotg210_info(fotg210, "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n",
++		     100 * uframe_periodic_max/125, uframe_periodic_max);
++
++	if (uframe_periodic_max != 100)
++		fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n");
++
++	fotg210->uframe_periodic_max = uframe_periodic_max;
++	ret = count;
++
++out_unlock:
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	return ret;
++}
++
++static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max,
++		   store_uframe_periodic_max);
++
++static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
++{
++	struct device	*controller = fotg210_to_hcd(fotg210)->self.controller;
++	int	i = 0;
++
++	if (i)
++		goto out;
++
++	i = device_create_file(controller, &dev_attr_uframe_periodic_max);
++out:
++	return i;
++}
++
++static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
++{
++	struct device	*controller = fotg210_to_hcd(fotg210)->self.controller;
++
++	device_remove_file(controller, &dev_attr_uframe_periodic_max);
++}
++/*-------------------------------------------------------------------------*/
++
++/* On some systems, leaving remote wakeup enabled prevents system shutdown.
++ * The firmware seems to think that powering off is a wakeup event!
++ * This routine turns off remote wakeup and everything else, on all ports.
++ */
++static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210)
++{
++	u32 __iomem *status_reg = &fotg210->regs->port_status;
++
++	fotg210_writel(fotg210, PORT_RWC_BITS, status_reg);
++}
++
++/*
++ * Halt HC, turn off all ports, and let the BIOS use the companion controllers.
++ * Must be called with interrupts enabled and the lock not held.
++ */
++static void fotg210_silence_controller(struct fotg210_hcd *fotg210)
++{
++	fotg210_halt(fotg210);
++
++	spin_lock_irq(&fotg210->lock);
++	fotg210->rh_state = FOTG210_RH_HALTED;
++	fotg210_turn_off_all_ports(fotg210);
++	spin_unlock_irq(&fotg210->lock);
++}
++
++/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc).
++ * This forcibly disables dma and IRQs, helping kexec and other cases
++ * where the next system software may expect clean state.
++ */
++static void fotg210_shutdown(struct usb_hcd *hcd)
++{
++	struct fotg210_hcd	*fotg210 = hcd_to_fotg210(hcd);
++
++	spin_lock_irq(&fotg210->lock);
++	fotg210->shutdown = true;
++	fotg210->rh_state = FOTG210_RH_STOPPING;
++	fotg210->enabled_hrtimer_events = 0;
++	spin_unlock_irq(&fotg210->lock);
++
++	fotg210_silence_controller(fotg210);
++
++	hrtimer_cancel(&fotg210->hrtimer);
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * fotg210_work is called from some interrupts, timers, and so on.
++ * it calls driver completion functions, after dropping fotg210->lock.
++ */
++static void fotg210_work(struct fotg210_hcd *fotg210)
++{
++	/* another CPU may drop fotg210->lock during a schedule scan while
++	 * it reports urb completions.  this flag guards against bogus
++	 * attempts at re-entrant schedule scanning.
++	 */
++	if (fotg210->scanning) {
++		fotg210->need_rescan = true;
++		return;
++	}
++	fotg210->scanning = true;
++
++ rescan:
++	fotg210->need_rescan = false;
++	if (fotg210->async_count)
++		scan_async(fotg210);
++	if (fotg210->intr_count > 0)
++		scan_intr(fotg210);
++	if (fotg210->isoc_count > 0)
++		scan_isoc(fotg210);
++	if (fotg210->need_rescan)
++		goto rescan;
++	fotg210->scanning = false;
++
++	/* the IO watchdog guards against hardware or driver bugs that
++	 * misplace IRQs, and should let us run completely without IRQs.
++	 * such lossage has been observed on both VT6202 and VT8235.
++	 */
++	turn_on_io_watchdog(fotg210);
++}
++
++/*
++ * Called when the fotg210_hcd module is removed.
++ */
++static void fotg210_stop(struct usb_hcd *hcd)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++
++	fotg210_info(fotg210, "stop\n");
++
++	/* no more interrupts ... */
++
++	spin_lock_irq(&fotg210->lock);
++	fotg210->enabled_hrtimer_events = 0;
++	spin_unlock_irq(&fotg210->lock);
++
++	fotg210_quiesce(fotg210);
++	fotg210_silence_controller(fotg210);
++	fotg210_reset(fotg210);
++
++	hrtimer_cancel(&fotg210->hrtimer);
++	remove_sysfs_files(fotg210);
++	remove_debug_files(fotg210);
++
++	/* root hub is shut down separately (first, when possible) */
++	spin_lock_irq(&fotg210->lock);
++	end_free_itds(fotg210);
++	spin_unlock_irq(&fotg210->lock);
++	fotg210_mem_cleanup(fotg210);
++
++#ifdef	FOTG210_STATS
++	fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
++		fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa,
++		fotg210->stats.lost_iaa);
++	fotg210_dbg(fotg210, "complete %ld unlink %ld\n",
++		fotg210->stats.complete, fotg210->stats.unlink);
++#endif
++
++	dbg_status(fotg210, "fotg210_stop completed",
++		    fotg210_readl(fotg210, &fotg210->regs->status));
++}
++
++/* one-time init, only for memory state */
++static int fotg210_init(struct usb_hcd *hcd)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	u32			temp;
++	int			retval;
++	u32			hcc_params;
++	struct fotg210_qh_hw	*hw;
++
++	spin_lock_init(&fotg210->lock);
++
++	/*
++	 * keep io watchdog by default, those good HCDs could turn off it later
++	 */
++	fotg210->need_io_watchdog = 1;
++
++	hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
++	fotg210->hrtimer.function = fotg210_hrtimer_func;
++	fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
++
++	hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
++
++	/*
++	 * by default set standard 80% (== 100 usec/uframe) max periodic
++	 * bandwidth as required by USB 2.0
++	 */
++	fotg210->uframe_periodic_max = 100;
++
++	/*
++	 * hw default: 1K periodic list heads, one per frame.
++	 * periodic_size can shrink by USBCMD update if hcc_params allows.
++	 */
++	fotg210->periodic_size = DEFAULT_I_TDPS;
++	INIT_LIST_HEAD(&fotg210->intr_qh_list);
++	INIT_LIST_HEAD(&fotg210->cached_itd_list);
++
++	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
++		/* periodic schedule size can be smaller than default */
++		switch (FOTG210_TUNE_FLS) {
++		case 0:
++			fotg210->periodic_size = 1024;
++			break;
++		case 1:
++			fotg210->periodic_size = 512;
++			break;
++		case 2:
++			fotg210->periodic_size = 256;
++			break;
++		default:
++			BUG();
++		}
++	}
++	retval = fotg210_mem_init(fotg210, GFP_KERNEL);
++	if (retval < 0)
++		return retval;
++
++	/* controllers may cache some of the periodic schedule ... */
++	fotg210->i_thresh = 2;
++
++	/*
++	 * dedicate a qh for the async ring head, since we couldn't unlink
++	 * a 'real' qh without stopping the async schedule [4.8].  use it
++	 * as the 'reclamation list head' too.
++	 * its dummy is used in hw_alt_next of many tds, to prevent the qh
++	 * from automatically advancing to the next td after short reads.
++	 */
++	fotg210->async->qh_next.qh = NULL;
++	hw = fotg210->async->hw;
++	hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma);
++	hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD);
++	hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
++	hw->hw_qtd_next = FOTG210_LIST_END(fotg210);
++	fotg210->async->qh_state = QH_STATE_LINKED;
++	hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma);
++
++	/* clear interrupt enables, set irq latency */
++	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
++		log2_irq_thresh = 0;
++	temp = 1 << (16 + log2_irq_thresh);
++	if (HCC_CANPARK(hcc_params)) {
++		/* HW default park == 3, on hardware that supports it (like
++		 * NVidia and ALI silicon), maximizes throughput on the async
++		 * schedule by avoiding QH fetches between transfers.
++		 *
++		 * With fast usb storage devices and NForce2, "park" seems to
++		 * make problems:  throughput reduction (!), data errors...
++		 */
++		if (park) {
++			park = min_t(unsigned, park, 3);
++			temp |= CMD_PARK;
++			temp |= park << 8;
++		}
++		fotg210_dbg(fotg210, "park %d\n", park);
++	}
++	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
++		/* periodic schedule size can be smaller than default */
++		temp &= ~(3 << 2);
++		temp |= (FOTG210_TUNE_FLS << 2);
++	}
++	fotg210->command = temp;
++
++	/* Accept arbitrarily long scatter-gather lists */
++	if (!(hcd->driver->flags & HCD_LOCAL_MEM))
++		hcd->self.sg_tablesize = ~0;
++	return 0;
++}
++
++/* start HC running; it's halted, fotg210_init() has been run (once) */
++static int fotg210_run(struct usb_hcd *hcd)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	u32			temp;
++	u32			hcc_params;
++
++	hcd->uses_new_polling = 1;
++
++	/* EHCI spec section 4.1 */
++
++	fotg210_writel(fotg210, fotg210->periodic_dma,
++		       &fotg210->regs->frame_list);
++	fotg210_writel(fotg210, (u32)fotg210->async->qh_dma,
++		       &fotg210->regs->async_next);
++
++	/*
++	 * hcc_params controls whether fotg210->regs->segment must (!!!)
++	 * be used; it constrains QH/ITD/SITD and QTD locations.
++	 * pci_pool consistent memory always uses segment zero.
++	 * streaming mappings for I/O buffers, like pci_map_single(),
++	 * can return segments above 4GB, if the device allows.
++	 *
++	 * NOTE:  the dma mask is visible through dma_supported(), so
++	 * drivers can pass this info along ... like NETIF_F_HIGHDMA,
++	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
++	 * host side drivers though.
++	 */
++	hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
++
++	/*
++	 * Philips, Intel, and maybe others need CMD_RUN before the
++	 * root hub will detect new devices (why?); NEC doesn't
++	 */
++	fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
++	fotg210->command |= CMD_RUN;
++	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
++	dbg_cmd(fotg210, "init", fotg210->command);
++
++	/*
++	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
++	 * are explicitly handed to companion controller(s), so no TT is
++	 * involved with the root hub.  (Except where one is integrated,
++	 * and there's no companion controller unless maybe for USB OTG.)
++	 *
++	 * Turning on the CF flag will transfer ownership of all ports
++	 * from the companions to the EHCI controller.  If any of the
++	 * companions are in the middle of a port reset at the time, it
++	 * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
++	 * guarantees that no resets are in progress.  After we set CF,
++	 * a short delay lets the hardware catch up; new resets shouldn't
++	 * be started before the port switching actions could complete.
++	 */
++	down_write(&ehci_cf_port_reset_rwsem);
++	fotg210->rh_state = FOTG210_RH_RUNNING;
++	/* unblock posted writes */
++	fotg210_readl(fotg210, &fotg210->regs->command);
++	msleep(5);
++	up_write(&ehci_cf_port_reset_rwsem);
++	fotg210->last_periodic_enable = ktime_get_real();
++
++	temp = HC_VERSION(fotg210,
++			  fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
++	fotg210_info(fotg210,
++		"USB %x.%x started, EHCI %x.%02x\n",
++		((fotg210->sbrn & 0xf0)>>4), (fotg210->sbrn & 0x0f),
++		temp >> 8, temp & 0xff);
++
++	fotg210_writel(fotg210, INTR_MASK,
++		    &fotg210->regs->intr_enable); /* Turn On Interrupts */
++
++	/* GRR this is run-once init(), being done every time the HC starts.
++	 * So long as they're part of class devices, we can't do it init()
++	 * since the class device isn't created that early.
++	 */
++	create_debug_files(fotg210);
++	create_sysfs_files(fotg210);
++
++	return 0;
++}
++
++static int fotg210_setup(struct usb_hcd *hcd)
++{
++	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
++	int retval;
++
++	dbg_hcs_params(fotg210, "reset");
++	dbg_hcc_params(fotg210, "reset");
++
++	/* cache this readonly data; minimize chip reads */
++	fotg210->hcs_params = fotg210_readl(fotg210,
++					    &fotg210->caps->hcs_params);
++
++	fotg210->sbrn = HCD_USB2;
++
++	/* data structure init */
++	retval = fotg210_init(hcd);
++	if (retval)
++		return retval;
++
++	retval = fotg210_halt(fotg210);
++	if (retval)
++		return retval;
++
++	fotg210_reset(fotg210);
++
++	return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static irqreturn_t fotg210_irq(struct usb_hcd *hcd)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	u32			status, masked_status, pcd_status = 0, cmd;
++	int			bh;
++	char			*str_ptr;
++
++	str_ptr = (char *) hcd->self.bus_name;
++	spin_lock(&fotg210->lock);
++
++#ifdef CONFIG_USB_FOTG210_OTG
++	/* check if host mode */
++	status = fotg210_readl(fotg210, &fotg210->regs->otgcsr);
++	if (status & OTGCSR_CROLE) {	//peripheral mode
++		spin_unlock(&fotg210->lock);
++		return IRQ_NONE;
++	}
++#endif
++
++	status = fotg210_readl(fotg210, &fotg210->regs->status);
++
++	/* e.g. cardbus physical eject */
++	if (status == ~(u32) 0) {
++		fotg210_info(fotg210, "device removed\n");
++		goto dead;
++	}
++
++	/*
++	 * We don't use STS_FLR, but some controllers don't like it to
++	 * remain on, so mask it out along with the other status bits.
++	 */
++	masked_status = status & (INTR_MASK | STS_FLR);
++
++	/* Shared IRQ? */
++	if (!masked_status ||
++	    unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) {
++		spin_unlock(&fotg210->lock);
++		return IRQ_NONE;
++	}
++
++	/* clear (just) interrupts */
++	fotg210_writel(fotg210, masked_status, &fotg210->regs->status);
++	cmd = fotg210_readl(fotg210, &fotg210->regs->command);
++	bh = 0;
++
++#ifdef	VERBOSE_DEBUG
++	/* unrequested/ignored: Frame List Rollover */
++	dbg_status(fotg210, "irq", status);
++#endif
++
++	/* INT, ERR, and IAA interrupt rates can be throttled */
++
++	/* normal [4.15.1.2] or error [4.15.1.1] completion */
++	if (likely((status & (STS_INT|STS_ERR)) != 0)) {
++		if (likely((status & STS_ERR) == 0))
++			COUNT(fotg210->stats.normal);
++		else
++			COUNT(fotg210->stats.error);
++		bh = 1;
++	}
++
++	/* complete the unlinking of some qh [4.15.2.3] */
++	if (status & STS_IAA) {
++
++		/* Turn off the IAA watchdog */
++		fotg210->enabled_hrtimer_events &=
++			~BIT(FOTG210_HRTIMER_IAA_WATCHDOG);
++
++		/*
++		 * Mild optimization: Allow another IAAD to reset the
++		 * hrtimer, if one occurs before the next expiration.
++		 * In theory we could always cancel the hrtimer, but
++		 * tests show that about half the time it will be reset
++		 * for some other event anyway.
++		 */
++		if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG)
++			++fotg210->next_hrtimer_event;
++
++		/* guard against (alleged) silicon errata */
++		if (cmd & CMD_IAAD)
++			fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
++		if (fotg210->async_iaa) {
++			COUNT(fotg210->stats.iaa);
++			end_unlink_async(fotg210);
++		} else
++			fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
++	}
++
++	/* remote wakeup [4.3.1] */
++	if (status & STS_PCD) {
++		int pstatus;
++		u32 __iomem *status_reg = &fotg210->regs->port_status;
++
++		/* kick root hub later */
++		pcd_status = status;
++
++		/* resume root hub? */
++		if (fotg210->rh_state == FOTG210_RH_SUSPENDED)
++			usb_hcd_resume_root_hub(hcd);
++
++		/* When device disconnect, fotg210 HW will clear RUN bit and
++		 * assert port change interrupt. We enable RUN bit here.
++		 */
++		if (!(cmd & CMD_RUN)) {
++			writel(readl(&fotg210->regs->command) | CMD_RUN, &fotg210->regs->command);
++			handshake(fotg210, &fotg210->regs->status,
++				STS_HALT, 0, 16 * 125);	
++		}
++
++		pstatus = fotg210_readl(fotg210, status_reg);
++
++		if (test_bit(0, &fotg210->suspended_ports) &&
++				((pstatus & PORT_RESUME) ||
++					!(pstatus & PORT_SUSPEND)) &&
++				(pstatus & PORT_PE) &&
++				fotg210->reset_done[0] == 0) {
++
++			/* start 20 msec resume signaling from this port,
++			 * and make khubd collect PORT_STAT_C_SUSPEND to
++			 * stop that signaling.  Use 5 ms extra for safety,
++			 * like usb_port_resume() does.
++			 */
++			fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25);
++			set_bit(0, &fotg210->resuming_ports);
++			fotg210_info(fotg210, "port 1 remote wakeup\n");
++			mod_timer(&hcd->rh_timer, fotg210->reset_done[0]);
++		}
++	}
++
++	/* PCI errors [4.15.2.4] */
++	if (unlikely((status & STS_FATAL) != 0)) {
++		fotg210_err(fotg210, "fatal error\n");
++		dbg_cmd(fotg210, "fatal", cmd);
++		dbg_status(fotg210, "fatal", status);
++
++		//fotg210 fatal recovery sequence
++		if (strncmp(str_ptr,"fotg210",7) == 0) {
++			u32 ori_cmd = readl(&fotg210->regs->command);
++			u32 ori_int = readl(&fotg210->regs->intr_enable);
++			u32 temp;
++
++			//set port reset
++			writel(PORT_RESET, &fotg210->regs->port_status);
++			mdelay(45);
++			//set HC_RESET
++			writel(CMD_RESET, &fotg210->regs->command);
++			handshake(fotg210, &fotg210->regs->command,
++				CMD_RESET, 0, 250 * 1000);
++
++			/* re-init operational registers */
++			fotg210_writel(fotg210, fotg210->periodic_dma, &fotg210->regs->frame_list);
++			fotg210_writel(fotg210, (u32) fotg210->async->qh_dma, &fotg210->regs->async_next);
++
++			writel(ori_cmd, &fotg210->regs->command);
++			mdelay(5);
++			writel(ori_cmd | CMD_RUN, &fotg210->regs->command);
++			writel(ori_int, &fotg210->regs->intr_enable);
++			temp = readl(&fotg210->regs->port_status);
++			writel(temp & ~PORT_RESET, &fotg210->regs->port_status);
++
++			printk("  fatal recovery OK!\n");
++		}
++		else {
++dead:
++		usb_hc_died(hcd);
++
++		/* Don't let the controller do anything more */
++		fotg210->shutdown = true;
++		fotg210->rh_state = FOTG210_RH_STOPPING;
++		fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
++		fotg210_writel(fotg210, fotg210->command,
++			       &fotg210->regs->command);
++		fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
++		fotg210_handle_controller_death(fotg210);
++
++		/* Handle completions when the controller stops */
++		bh = 0;
++		}
++	}
++
++	if (bh)
++		fotg210_work(fotg210);
++	spin_unlock(&fotg210->lock);
++	if (pcd_status)
++		usb_hcd_poll_rh_status(hcd);
++	return IRQ_HANDLED;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * non-error returns are a promise to giveback() the urb later
++ * we drop ownership so next owner (or urb unlink) can get it
++ *
++ * urb + dev is in hcd.self.controller.urb_list
++ * we're queueing TDs onto software and hardware lists
++ *
++ * hcd-specific init for hcpriv hasn't been done yet
++ *
++ * NOTE:  control, bulk, and interrupt share the same code to append TDs
++ * to a (possibly active) QH, and the same QH scanning code.
++ */
++static int fotg210_urb_enqueue(
++	struct usb_hcd	*hcd,
++	struct urb	*urb,
++	gfp_t		mem_flags
++) {
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	struct list_head	qtd_list;
++
++	INIT_LIST_HEAD(&qtd_list);
++
++	switch (usb_pipetype(urb->pipe)) {
++	case PIPE_CONTROL:
++		/* qh_completions() code doesn't handle all the fault cases
++		 * in multi-TD control transfers.  Even 1KB is rare anyway.
++		 */
++		if (urb->transfer_buffer_length > (16 * 1024))
++			return -EMSGSIZE;
++		/* FALLTHROUGH */
++	/* case PIPE_BULK: */
++	default:
++		if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
++			return -ENOMEM;
++		return submit_async(fotg210, urb, &qtd_list, mem_flags);
++
++	case PIPE_INTERRUPT:
++		if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
++			return -ENOMEM;
++		return intr_submit(fotg210, urb, &qtd_list, mem_flags);
++
++	case PIPE_ISOCHRONOUS:
++		return itd_submit(fotg210, urb, mem_flags);
++	}
++}
++
++/* remove from hardware lists
++ * completions normally happen asynchronously
++ */
++
++static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	struct fotg210_qh		*qh;
++	unsigned long		flags;
++	int			rc;
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
++	if (rc)
++		goto done;
++
++	switch (usb_pipetype(urb->pipe)) {
++	/* case PIPE_CONTROL: */
++	/* case PIPE_BULK:*/
++	default:
++		qh = (struct fotg210_qh *) urb->hcpriv;
++		if (!qh)
++			break;
++		switch (qh->qh_state) {
++		case QH_STATE_LINKED:
++		case QH_STATE_COMPLETING:
++			start_unlink_async(fotg210, qh);
++			break;
++		case QH_STATE_UNLINK:
++		case QH_STATE_UNLINK_WAIT:
++			/* already started */
++			break;
++		case QH_STATE_IDLE:
++			/* QH might be waiting for a Clear-TT-Buffer */
++			qh_completions(fotg210, qh);
++			break;
++		}
++		break;
++
++	case PIPE_INTERRUPT:
++		qh = (struct fotg210_qh *) urb->hcpriv;
++		if (!qh)
++			break;
++		switch (qh->qh_state) {
++		case QH_STATE_LINKED:
++		case QH_STATE_COMPLETING:
++			start_unlink_intr(fotg210, qh);
++			break;
++		case QH_STATE_IDLE:
++			qh_completions(fotg210, qh);
++			break;
++		default:
++			fotg210_dbg(fotg210, "bogus qh %p state %d\n",
++					qh, qh->qh_state);
++			goto done;
++		}
++		break;
++
++	case PIPE_ISOCHRONOUS:
++		/* itd... */
++
++		/* wait till next completion, do it then. */
++		/* completion irqs can wait up to 1024 msec, */
++		break;
++	}
++done:
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++	return rc;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* bulk qh holds the data toggle */
++
++static void
++fotg210_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	unsigned long		flags;
++	struct fotg210_qh		*qh, *tmp;
++
++	/* ASSERT:  any requests/urbs are being unlinked */
++	/* ASSERT:  nobody can be submitting urbs for this any more */
++
++rescan:
++	spin_lock_irqsave(&fotg210->lock, flags);
++	qh = ep->hcpriv;
++	if (!qh)
++		goto done;
++
++	/* endpoints can be iso streams.  for now, we don't
++	 * accelerate iso completions ... so spin a while.
++	 */
++	if (qh->hw == NULL) {
++		struct fotg210_iso_stream	*stream = ep->hcpriv;
++
++		if (!list_empty(&stream->td_list))
++			goto idle_timeout;
++
++		/* BUG_ON(!list_empty(&stream->free_list)); */
++		kfree(stream);
++		goto done;
++	}
++
++	if (fotg210->rh_state < FOTG210_RH_RUNNING)
++		qh->qh_state = QH_STATE_IDLE;
++	switch (qh->qh_state) {
++	case QH_STATE_LINKED:
++	case QH_STATE_COMPLETING:
++		for (tmp = fotg210->async->qh_next.qh;
++				tmp && tmp != qh;
++				tmp = tmp->qh_next.qh)
++			continue;
++		/* periodic qh self-unlinks on empty, and a COMPLETING qh
++		 * may already be unlinked.
++		 */
++		if (tmp)
++			start_unlink_async(fotg210, qh);
++		/* FALL THROUGH */
++	case QH_STATE_UNLINK:		/* wait for hw to finish? */
++	case QH_STATE_UNLINK_WAIT:
++idle_timeout:
++		spin_unlock_irqrestore(&fotg210->lock, flags);
++		schedule_timeout_uninterruptible(1);
++		goto rescan;
++	case QH_STATE_IDLE:		/* fully unlinked */
++		if (qh->clearing_tt)
++			goto idle_timeout;
++		if (list_empty(&qh->qtd_list)) {
++			qh_destroy(fotg210, qh);
++			break;
++		}
++		/* else FALL THROUGH */
++	default:
++		/* caller was supposed to have unlinked any requests;
++		 * that's not our job.  just leak this memory.
++		 */
++		fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n",
++			qh, ep->desc.bEndpointAddress, qh->qh_state,
++			list_empty(&qh->qtd_list) ? "" : "(has tds)");
++		break;
++	}
++ done:
++	ep->hcpriv = NULL;
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++}
++
++static void
++fotg210_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	struct fotg210_qh		*qh;
++	int			eptype = usb_endpoint_type(&ep->desc);
++	int			epnum = usb_endpoint_num(&ep->desc);
++	int			is_out = usb_endpoint_dir_out(&ep->desc);
++	unsigned long		flags;
++
++	if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
++		return;
++
++	spin_lock_irqsave(&fotg210->lock, flags);
++	qh = ep->hcpriv;
++
++	/* For Bulk and Interrupt endpoints we maintain the toggle state
++	 * in the hardware; the toggle bits in udev aren't used at all.
++	 * When an endpoint is reset by usb_clear_halt() we must reset
++	 * the toggle bit in the QH.
++	 */
++	if (qh) {
++		usb_settoggle(qh->dev, epnum, is_out, 0);
++		if (!list_empty(&qh->qtd_list)) {
++			WARN_ONCE(1, "clear_halt for a busy endpoint\n");
++		} else if (qh->qh_state == QH_STATE_LINKED ||
++				qh->qh_state == QH_STATE_COMPLETING) {
++
++			/* The toggle value in the QH can't be updated
++			 * while the QH is active.  Unlink it now;
++			 * re-linking will call qh_refresh().
++			 */
++			if (eptype == USB_ENDPOINT_XFER_BULK)
++				start_unlink_async(fotg210, qh);
++			else
++				start_unlink_intr(fotg210, qh);
++		}
++	}
++	spin_unlock_irqrestore(&fotg210->lock, flags);
++}
++
++static int fotg210_get_frame(struct usb_hcd *hcd)
++{
++	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
++	return (fotg210_read_frame_index(fotg210) >> 3) %
++		fotg210->periodic_size;
++}
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef CONFIG_USB_OTG
++static int fotg210_start_port_reset(struct usb_hcd *hcd, unsigned port)
++{
++	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
++	u32 status;
++
++	if (!port)
++		return -EINVAL;
++
++	port--;
++
++	/* start port reset before HNP protocol time out */
++	status = readl(&fotg210->regs->port_status);
++	if (!(status & PORT_CONNECT))
++		return -ENODEV;
++
++	/* khubd will finish the reset later */
++	writel(PORT_RESET |
++	       (status & ~(PORT_CSC | PORT_PEC)),
++	       &fotg210->regs->port_status);
++
++	return 0;
++}
++#else
++#define fotg210_start_port_reset	NULL
++#endif /* CONFIG_USB_OTG */
++
++
++/*
++ * The EHCI in ChipIdea HDRC cannot be a separate module or device,
++ * because its registers (and irq) are shared between host/gadget/otg
++ * functions  and in order to facilitate role switching we cannot
++ * give the fotg210 driver exclusive access to those.
++ */
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_LICENSE("GPL");
++
++static const struct hc_driver fotg210_hc_driver = {
++	.description 		= hcd_name,
++	.product_desc 		= "Faraday USB2.0 Host Controller",
++	.hcd_priv_size 		= sizeof(struct fotg210_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq 			= fotg210_irq,
++	.flags 			= HCD_MEMORY | HCD_USB2,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.reset 			= fotg210_setup,
++	.start 			= fotg210_run,
++	.stop 			= fotg210_stop,
++	.shutdown 		= fotg210_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue 		= fotg210_urb_enqueue,
++	.urb_dequeue 		= fotg210_urb_dequeue,
++	.endpoint_disable 	= fotg210_endpoint_disable,
++	.endpoint_reset 	= fotg210_endpoint_reset,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number 	= fotg210_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data 	= fotg210_hub_status_data,
++	.hub_control 		= fotg210_hub_control,
++	.bus_suspend 		= fotg210_bus_suspend,
++	.bus_resume 		= fotg210_bus_resume,
++	.start_port_reset	= fotg210_start_port_reset,
++	.relinquish_port 	= fotg210_relinquish_port,
++	.port_handed_over 	= fotg210_port_handed_over,
++
++	.clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete,
++};
++
++static void fotg210_host_init(struct fotg210_hcd *fotg210)
++{
++	u32 value;
++
++	fotg210_writel(fotg210, GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
++		&fotg210->regs->gmir);
++
++	value = fotg210_readl(fotg210, &fotg210->regs->otgcsr);
++	value &= ~OTGCSR_A_BUS_DROP;
++	value |= OTGCSR_A_BUS_REQ;
++	fotg210_writel(fotg210, value, &fotg210->regs->otgcsr);
++}
++
++/**
++ * fotg210_hcd_probe - initialize faraday FOTG210 HCDs
++ *
++ * Allocates basic resources for this USB host controller, and
++ * then invokes the start() method for the HCD associated with it
++ * through the hotplug entry's driver_data.
++ */
++static int fotg210_hcd_probe(struct platform_device *pdev)
++{
++	struct device			*dev = &pdev->dev;
++	struct usb_hcd 			*hcd;
++	struct resource			*res;
++	int 				irq;
++	int 				retval = -ENODEV;
++	struct fotg210_hcd 		*fotg210;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	pdev->dev.power.power_state = PMSG_ON;
++
++	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++	if (!res) {
++		dev_err(dev,
++			"Found HC with no IRQ. Check %s setup!\n",
++			dev_name(dev));
++		return -ENODEV;
++	}
++
++	irq = res->start;
++
++	hcd = usb_create_hcd(&fotg210_hc_driver, dev,
++			dev_name(dev));
++	if (!hcd) {
++		dev_err(dev, "failed to create hcd with err %d\n", retval);
++		retval = -ENOMEM;
++		goto fail_create_hcd;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!res) {
++		dev_err(dev,
++			"Found HC with no register addr. Check %s setup!\n",
++			dev_name(dev));
++		retval = -ENODEV;
++		goto fail_request_resource;
++	}
++
++	hcd->rsrc_start = res->start;
++	hcd->rsrc_len = resource_size(res);
++	hcd->has_tt = 1;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
++				fotg210_hc_driver.description)) {
++		dev_err(dev, "controller already in use\n");
++		retval = -EBUSY;
++		goto fail_request_resource;
++	}
++
++	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
++	if (!res) {
++		dev_err(dev,
++			"Found HC with no register addr. Check %s setup!\n",
++			dev_name(dev));
++		retval = -ENODEV;
++		goto fail_request_resource;
++	}
++
++	hcd->regs = ioremap_nocache(res->start, resource_size(res));
++	if (hcd->regs == NULL) {
++		dev_err(dev, "error mapping memory\n");
++		retval = -EFAULT;
++		goto fail_ioremap;
++	}
++
++	fotg210 = hcd_to_fotg210(hcd);
++
++	fotg210->caps = hcd->regs;
++	fotg210->regs = (void __iomem *)fotg210->caps +
++	    HC_LENGTH(fotg210, fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
++
++#ifdef CONFIG_USB_FOTG210_OTG
++	fotg210->transceiver = otg_get_transceiver();
++	if (!fotg210->transceiver) {
++		dev_err(dev, "can't find otg transceiver\n");
++		retval = -ENODEV;
++		goto fail_add_hcd;
++	}
++
++	retval = otg_set_host(fotg210->transceiver, &hcd->self);
++	if (retval < 0) {
++		dev_err(dev, "can't register with otg transceiver\n");
++		if (fotg210->transceiver)
++			otg_put_transceiver(fotg210->transceiver);
++		goto fail_add_hcd;
++	}
++#else
++	fotg210_host_init(fotg210);
++#endif
++
++	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
++	if (retval) {
++		dev_err(dev, "failed to add hcd with err %d\n", retval);
++		goto fail_add_hcd;
++	}
++
++	return retval;
++
++fail_add_hcd:
++	iounmap(hcd->regs);
++fail_ioremap:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++fail_request_resource:
++	usb_put_hcd(hcd);
++fail_create_hcd:
++	dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
++	return retval;
++}
++
++/**
++ * fotg210_hcd_remove - shutdown processing for EHCI HCDs
++ * @dev: USB Host Controller being removed
++ *
++ */
++static int fotg210_hcd_remove(struct platform_device *pdev)
++{
++	struct usb_hcd *hcd = platform_get_drvdata(pdev);
++	struct fotg210_hcd *fotg210;
++
++	if (!hcd)
++		return 0;
++
++	fotg210 = hcd_to_fotg210(hcd);
++	if (fotg210->transceiver) {
++		otg_set_host(fotg210->transceiver, NULL);
++		otg_put_transceiver(fotg210->transceiver);
++	}
++
++	usb_remove_hcd(hcd);
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++	platform_set_drvdata(pdev, NULL);
++
++	return 0;
++}
++
++static struct platform_driver fotg210_hcd_driver = {
++	.driver = {
++		.name   = "fotg210-hcd",
++	},
++	.probe  = fotg210_hcd_probe,
++	.remove = fotg210_hcd_remove,
++};
++
++static int __init fotg210_hcd_init(void)
++{
++	int retval = 0;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
++	set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
++	if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
++			test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
++		pr_warn(KERN_WARNING "Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");
++
++	pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd\n",
++		 hcd_name,
++		 sizeof(struct fotg210_qh), sizeof(struct fotg210_qtd),
++		 sizeof(struct fotg210_itd));
++
++#ifdef DEBUG
++	fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
++	if (!fotg210_debug_root) {
++		retval = -ENOENT;
++		goto err_debug;
++	}
++#endif
++
++	retval = platform_driver_register(&fotg210_hcd_driver);
++	if (retval < 0)
++		goto clean;
++	return retval;
++
++	platform_driver_unregister(&fotg210_hcd_driver);
++clean:
++#ifdef DEBUG
++	debugfs_remove(fotg210_debug_root);
++	fotg210_debug_root = NULL;
++err_debug:
++#endif
++	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
++	return retval;
++}
++module_init(fotg210_hcd_init);
++
++static void __exit fotg210_hcd_cleanup(void)
++{
++	platform_driver_unregister(&fotg210_hcd_driver);
++#ifdef DEBUG
++	debugfs_remove(fotg210_debug_root);
++#endif
++	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
++}
++module_exit(fotg210_hcd_cleanup);
+diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
+new file mode 100644
+index 00000000..959ec3f8
+--- /dev/null
++++ b/drivers/usb/host/fotg210.h
+@@ -0,0 +1,886 @@
++/*
++ * Definition of EHCI
++ *
++ * Refer to ehci.h and ehci_def.h
++ *
++ * Copyright (c) 2001-2002 by David Brownell
++ *
++ * Definition of fotg210 by Faraday Tech.
++ *
++ * Copyright (c) 2012 by Yuan-Hsin Chen
++ *
++ * 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.
++ */
++
++/* definitions used for the EHCI driver */
++
++/*
++ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
++ * __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
++ * the host controller implementation.
++ *
++ * To facilitate the strongest possible byte-order checking from "sparse"
++ * and so on, we use __leXX unless that's not practical.
++ */
++#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
++typedef __u32 __bitwise __hc32;
++typedef __u16 __bitwise __hc16;
++#else
++#define __hc32	__le32
++#define __hc16	__le16
++#endif
++
++/* statistics can be kept for tuning/monitoring */
++struct ehci_stats {
++	/* irq usage */
++	unsigned long		normal;
++	unsigned long		error;
++	unsigned long		reclaim;
++	unsigned long		lost_iaa;
++
++	/* termination of urbs from core */
++	unsigned long		complete;
++	unsigned long		unlink;
++};
++
++/* ehci_hcd->lock guards shared data against other CPUs:
++ *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
++ *   usb_host_endpoint: hcpriv
++ *   ehci_qh:	qh_next, qtd_list
++ *   ehci_qtd:	qtd_list
++ *
++ * Also, hold this lock when talking to HC registers or
++ * when updating hw_* fields in shared qh/qtd/... structures.
++ */
++
++#define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
++
++enum ehci_rh_state {
++	EHCI_RH_HALTED,
++	EHCI_RH_SUSPENDED,
++	EHCI_RH_RUNNING
++};
++
++struct ehci_hcd {			/* one per controller */
++	/* glue to PCI and HCD framework */
++	struct ehci_caps __iomem *caps;
++	struct ehci_regs __iomem *regs;
++	struct ehci_dbg_port __iomem *debug;
++
++	__u32			hcs_params;	/* cached register copy */
++	spinlock_t		lock;
++	enum ehci_rh_state	rh_state;
++
++	/* async schedule support */
++	struct ehci_qh		*async;
++	struct ehci_qh		*dummy;		/* For AMD quirk use */
++	struct ehci_qh		*reclaim;
++	struct ehci_qh		*qh_scan_next;
++	unsigned		scanning:1;
++
++	/* periodic schedule support */
++#define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
++	unsigned		periodic_size;
++	__hc32			*periodic;	/* hw periodic table */
++	dma_addr_t		periodic_dma;
++	unsigned		i_thresh;	/* uframes HC might cache */
++
++	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
++	int			next_uframe;	/* scan periodic, start here */
++	unsigned		periodic_sched;	/* periodic activity count */
++	unsigned		uframe_periodic_max; /* max periodic time per uframe */
++
++
++	/* list of itds & sitds completed while clock_frame was still active */
++	struct list_head	cached_itd_list;
++	struct list_head	cached_sitd_list;
++	unsigned		clock_frame;
++
++	/* per root hub port */
++	unsigned long		reset_done[EHCI_MAX_ROOT_PORTS];
++
++	/* bit vectors (one bit per port) */
++	unsigned long		bus_suspended;		/* which ports were
++			already suspended at the start of a bus suspend */
++	unsigned long		companion_ports;	/* which ports are
++			dedicated to the companion controller */
++	unsigned long		owned_ports;		/* which ports are
++			owned by the companion during a bus suspend */
++	unsigned long		port_c_suspend;		/* which ports have
++			the change-suspend feature turned on */
++	unsigned long		suspended_ports;	/* which ports are
++			suspended */
++
++	/* per-HC memory pools (could be per-bus, but ...) */
++	struct dma_pool		*qh_pool;	/* qh per active urb */
++	struct dma_pool		*qtd_pool;	/* one or more per qh */
++	struct dma_pool		*itd_pool;	/* itd per iso urb */
++	struct dma_pool		*sitd_pool;	/* sitd per split iso urb */
++
++	struct timer_list	iaa_watchdog;
++	struct timer_list	watchdog;
++	unsigned long		actions;
++	unsigned		periodic_stamp;
++	unsigned		random_frame;
++	unsigned long		next_statechange;
++	ktime_t			last_periodic_enable;
++	u32			command;
++
++	/* SILICON QUIRKS */
++	unsigned		no_selective_suspend:1;
++	unsigned		has_fsl_port_bug:1; /* FreeScale */
++	unsigned		big_endian_mmio:1;
++	unsigned		big_endian_desc:1;
++	unsigned		big_endian_capbase:1;
++	unsigned		has_amcc_usb23:1;
++	unsigned		need_io_watchdog:1;
++	unsigned		broken_periodic:1;
++	unsigned		amd_pll_fix:1;
++	unsigned		fs_i_thresh:1;	/* Intel iso scheduling */
++	unsigned		use_dummy_qh:1;	/* AMD Frame List table quirk*/
++	unsigned		has_synopsys_hc_bug:1; /* Synopsys HC */
++	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */
++
++	/* required for usb32 quirk */
++	#define OHCI_CTRL_HCFS          (3 << 6)
++	#define OHCI_USB_OPER           (2 << 6)
++	#define OHCI_USB_SUSPEND        (3 << 6)
++
++	#define OHCI_HCCTRL_OFFSET      0x4
++	#define OHCI_HCCTRL_LEN         0x4
++	__hc32			*ohci_hcctrl_reg;
++	unsigned		has_hostpc:1;
++	unsigned		has_lpm:1;  /* support link power management */
++	unsigned		has_ppcd:1; /* support per-port change bits */
++	u8			sbrn;		/* packed release number */
++
++	/* irq statistics */
++#ifdef EHCI_STATS
++	struct ehci_stats	stats;
++#	define COUNT(x) do { (x)++; } while (0)
++#else
++#	define COUNT(x) do {} while (0)
++#endif
++
++	/* debug files */
++#ifdef DEBUG
++	struct dentry		*debug_dir;
++#endif
++	/*
++	 * OTG controllers and transceivers need software interaction
++	 */
++	struct otg_transceiver	*transceiver;
++};
++
++/* convert between an HCD pointer and the corresponding EHCI_HCD */
++static inline struct ehci_hcd *hcd_to_ehci(struct usb_hcd *hcd)
++{
++	return (struct ehci_hcd *)(hcd->hcd_priv);
++}
++static inline struct usb_hcd *ehci_to_hcd(struct ehci_hcd *ehci)
++{
++	return container_of((void *) ehci, struct usb_hcd, hcd_priv);
++}
++
++
++static inline void
++iaa_watchdog_start(struct ehci_hcd *ehci)
++{
++	WARN_ON(timer_pending(&ehci->iaa_watchdog));
++	mod_timer(&ehci->iaa_watchdog,
++			jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
++}
++
++static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
++{
++	del_timer(&ehci->iaa_watchdog);
++}
++
++enum ehci_timer_action {
++	TIMER_IO_WATCHDOG,
++	TIMER_ASYNC_SHRINK,
++	TIMER_ASYNC_OFF,
++};
++
++static inline void
++timer_action_done(struct ehci_hcd *ehci, enum ehci_timer_action action)
++{
++	clear_bit(action, &ehci->actions);
++}
++
++static void free_cached_lists(struct ehci_hcd *ehci);
++
++#define	QTD_NEXT(ehci, dma)	cpu_to_hc32(ehci, (u32)dma)
++
++/*
++ * EHCI Specification 0.95 Section 3.5
++ * QTD: describe data transfer components (buffer, direction, ...)
++ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
++ *
++ * These are associated only with "QH" (Queue Head) structures,
++ * used with control, bulk, and interrupt transfers.
++ */
++struct ehci_qtd {
++	/* first part defined by EHCI spec */
++	__hc32			hw_next;	/* see EHCI 3.5.1 */
++	__hc32			hw_alt_next;    /* see EHCI 3.5.2 */
++	__hc32			hw_token;       /* see EHCI 3.5.3 */
++#define	QTD_TOGGLE	(1 << 31)	/* data toggle */
++#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
++#define	QTD_IOC		(1 << 15)	/* interrupt on complete */
++#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
++#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
++#define	QTD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
++#define	QTD_STS_HALT	(1 << 6)	/* halted on error */
++#define	QTD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
++#define	QTD_STS_BABBLE	(1 << 4)	/* device was babbling (qtd halted) */
++#define	QTD_STS_XACT	(1 << 3)	/* device gave illegal response */
++#define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
++#define	QTD_STS_STS	(1 << 1)	/* split transaction state */
++#define	QTD_STS_PING	(1 << 0)	/* issue PING? */
++
++#define ACTIVE_BIT(ehci)	cpu_to_hc32(ehci, QTD_STS_ACTIVE)
++#define HALT_BIT(ehci)		cpu_to_hc32(ehci, QTD_STS_HALT)
++#define STATUS_BIT(ehci)	cpu_to_hc32(ehci, QTD_STS_STS)
++
++	__hc32			hw_buf[5];        /* see EHCI 3.5.4 */
++	__hc32			hw_buf_hi[5];        /* Appendix B */
++
++	/* the rest is HCD-private */
++	dma_addr_t		qtd_dma;		/* qtd address */
++	struct list_head	qtd_list;		/* sw qtd list */
++	struct urb		*urb;			/* qtd's urb */
++	size_t			length;			/* length of buffer */
++} __attribute__ ((aligned(32)));
++
++/* mask NakCnt+T in qh->hw_alt_next */
++#define QTD_MASK(ehci)	(cpu_to_hc32(ehci, ~0x1f))
++
++#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
++
++/* type tag from {qh,itd,sitd,fstn}->hw_next */
++#define Q_NEXT_TYPE(ehci, dma)	((dma) & cpu_to_hc32(ehci, 3 << 1))
++
++/*
++ * Now the following defines are not converted using the
++ * cpu_to_le32() macro anymore, since we have to support
++ * "dynamic" switching between be and le support, so that the driver
++ * can be used on one system with SoC EHCI controller using big-endian
++ * descriptors as well as a normal little-endian PCI EHCI controller.
++ */
++/* values for that type tag */
++#define Q_TYPE_ITD	(0 << 1)
++#define Q_TYPE_QH	(1 << 1)
++#define Q_TYPE_SITD	(2 << 1)
++#define Q_TYPE_FSTN	(3 << 1)
++
++/* next async queue entry, or pointer to interrupt/periodic QH */
++#define QH_NEXT(ehci, dma)	(cpu_to_hc32(ehci, (((u32)dma)&~0x01f)|Q_TYPE_QH))
++
++/* for periodic/async schedules and qtd lists, mark end of list */
++#define EHCI_LIST_END(ehci)	cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
++
++/*
++ * Entries in periodic shadow table are pointers to one of four kinds
++ * of data structure.  That's dictated by the hardware; a type tag is
++ * encoded in the low bits of the hardware's periodic schedule.  Use
++ * Q_NEXT_TYPE to get the tag.
++ *
++ * For entries in the async schedule, the type tag always says "qh".
++ */
++union ehci_shadow {
++	struct ehci_qh		*qh;		/* Q_TYPE_QH */
++	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
++	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
++	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
++	__hc32			*hw_next;	/* (all types) */
++	void			*ptr;
++};
++
++/*
++ * EHCI Specification 0.95 Section 3.6
++ * QH: describes control/bulk/interrupt endpoints
++ * See Fig 3-7 "Queue Head Structure Layout".
++ *
++ * These appear in both the async and (for interrupt) periodic schedules.
++ */
++
++/* first part defined by EHCI spec */
++struct ehci_qh_hw {
++	__hc32			hw_next;	/* see EHCI 3.6.1 */
++	__hc32			hw_info1;       /* see EHCI 3.6.2 */
++#define	QH_HEAD		0x00008000
++	__hc32			hw_info2;        /* see EHCI 3.6.2 */
++#define	QH_SMASK	0x000000ff
++#define	QH_CMASK	0x0000ff00
++#define	QH_HUBADDR	0x007f0000
++#define	QH_HUBPORT	0x3f800000
++#define	QH_MULT		0xc0000000
++	__hc32			hw_current;	/* qtd list - see EHCI 3.6.4 */
++
++	/* qtd overlay (hardware parts of a struct ehci_qtd) */
++	__hc32			hw_qtd_next;
++	__hc32			hw_alt_next;
++	__hc32			hw_token;
++	__hc32			hw_buf[5];
++	__hc32			hw_buf_hi[5];
++} __attribute__ ((aligned(32)));
++
++struct ehci_qh {
++	struct ehci_qh_hw	*hw;
++	/* the rest is HCD-private */
++	dma_addr_t		qh_dma;		/* address of qh */
++	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
++	struct list_head	qtd_list;	/* sw qtd list */
++	struct ehci_qtd		*dummy;
++	struct ehci_qh		*reclaim;	/* next to reclaim */
++
++	struct ehci_hcd		*ehci;
++	unsigned long		unlink_time;
++
++	/*
++	 * Do NOT use atomic operations for QH refcounting. On some CPUs
++	 * (PPC7448 for example), atomic operations cannot be performed on
++	 * memory that is cache-inhibited (i.e. being used for DMA).
++	 * Spinlocks are used to protect all QH fields.
++	 */
++	u32			refcount;
++	unsigned		stamp;
++
++	u8			needs_rescan;	/* Dequeue during giveback */
++	u8			qh_state;
++#define	QH_STATE_LINKED		1		/* HC sees this */
++#define	QH_STATE_UNLINK		2		/* HC may still see this */
++#define	QH_STATE_IDLE		3		/* HC doesn't see this */
++#define	QH_STATE_UNLINK_WAIT	4		/* LINKED and on reclaim q */
++#define	QH_STATE_COMPLETING	5		/* don't touch token.HALT */
++
++	u8			xacterrs;	/* XactErr retry counter */
++#define	QH_XACTERR_MAX		32		/* XactErr retry limit */
++
++	/* periodic schedule info */
++	u8			usecs;		/* intr bandwidth */
++	u8			gap_uf;		/* uframes split/csplit gap */
++	u8			c_usecs;	/* ... split completion bw */
++	u16			tt_usecs;	/* tt downstream bandwidth */
++	unsigned short		period;		/* polling interval */
++	unsigned short		start;		/* where polling starts */
++#define NO_FRAME ((unsigned short)~0)			/* pick new start */
++
++	struct usb_device	*dev;		/* access to TT */
++	unsigned		is_out:1;	/* bulk or intr OUT */
++	unsigned		clearing_tt:1;	/* Clear-TT-Buf in progress */
++};
++
++/* description of one iso transaction (up to 3 KB data if highspeed) */
++struct ehci_iso_packet {
++	/* These will be copied to iTD when scheduling */
++	u64			bufp;		/* itd->hw_bufp{,_hi}[pg] |= */
++	__hc32			transaction;	/* itd->hw_transaction[i] |= */
++	u8			cross;		/* buf crosses pages */
++	/* for full speed OUT splits */
++	u32			buf1;
++};
++
++/* temporary schedule data for packets from iso urbs (both speeds)
++ * each packet is one logical usb transaction to the device (not TT),
++ * beginning at stream->next_uframe
++ */
++struct ehci_iso_sched {
++	struct list_head	td_list;
++	unsigned		span;
++	struct ehci_iso_packet	packet[0];
++};
++
++/*
++ * ehci_iso_stream - groups all (s)itds for this endpoint.
++ * acts like a qh would, if EHCI had them for ISO.
++ */
++struct ehci_iso_stream {
++	/* first field matches ehci_hq, but is NULL */
++	struct ehci_qh_hw	*hw;
++
++	u32			refcount;
++	u8			bEndpointAddress;
++	u8			highspeed;
++	struct list_head	td_list;	/* queued itds/sitds */
++	struct list_head	free_list;	/* list of unused itds/sitds */
++	struct usb_device	*udev;
++	struct usb_host_endpoint *ep;
++
++	/* output of (re)scheduling */
++	int			next_uframe;
++	__hc32			splits;
++
++	/* the rest is derived from the endpoint descriptor,
++	 * trusting urb->interval == f(epdesc->bInterval) and
++	 * including the extra info for hw_bufp[0..2]
++	 */
++	u8			usecs, c_usecs;
++	u16			interval;
++	u16			tt_usecs;
++	u16			maxp;
++	u16			raw_mask;
++	unsigned		bandwidth;
++
++	/* This is used to initialize iTD's hw_bufp fields */
++	__hc32			buf0;
++	__hc32			buf1;
++	__hc32			buf2;
++
++	/* this is used to initialize sITD's tt info */
++	__hc32			address;
++};
++
++/*
++ * EHCI Specification 0.95 Section 3.3
++ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
++ *
++ * Schedule records for high speed iso xfers
++ */
++struct ehci_itd {
++	/* first part defined by EHCI spec */
++	__hc32			hw_next;           /* see EHCI 3.3.1 */
++	__hc32			hw_transaction[8]; /* see EHCI 3.3.2 */
++#define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
++#define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
++#define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
++#define EHCI_ISOC_XACTERR       (1<<28)        /* XactErr - transaction error */
++#define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x0fff)
++#define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
++
++#define ITD_ACTIVE(ehci)	cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
++
++	__hc32			hw_bufp[7];	/* see EHCI 3.3.3 */
++	__hc32			hw_bufp_hi[7];	/* Appendix B */
++
++	/* the rest is HCD-private */
++	dma_addr_t		itd_dma;	/* for this itd */
++	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
++
++	struct urb		*urb;
++	struct ehci_iso_stream	*stream;	/* endpoint's queue */
++	struct list_head	itd_list;	/* list of stream's itds */
++
++	/* any/all hw_transactions here may be used by that urb */
++	unsigned		frame;		/* where scheduled */
++	unsigned		pg;
++	unsigned		index[8];	/* in urb->iso_frame_desc */
++} __attribute__ ((aligned(64)));
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * EHCI Specification 0.95 Section 3.4
++ * siTD, aka split-transaction isochronous Transfer Descriptor
++ *       ... describe full speed iso xfers through TT in hubs
++ * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
++ */
++struct ehci_sitd {
++	/* first part defined by EHCI spec */
++	__hc32			hw_next;
++/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
++	__hc32			hw_fullspeed_ep;	/* EHCI table 3-9 */
++	__hc32			hw_uframe;		/* EHCI table 3-10 */
++	__hc32			hw_results;		/* EHCI table 3-11 */
++#define	SITD_IOC	(1 << 31)	/* interrupt on completion */
++#define	SITD_PAGE	(1 << 30)	/* buffer 0/1 */
++#define	SITD_LENGTH(x)	(0x3ff & ((x)>>16))
++#define	SITD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
++#define	SITD_STS_ERR	(1 << 6)	/* error from TT */
++#define	SITD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
++#define	SITD_STS_BABBLE	(1 << 4)	/* device was babbling */
++#define	SITD_STS_XACT	(1 << 3)	/* illegal IN response */
++#define	SITD_STS_MMF	(1 << 2)	/* incomplete split transaction */
++#define	SITD_STS_STS	(1 << 1)	/* split transaction state */
++
++#define SITD_ACTIVE(ehci)	cpu_to_hc32(ehci, SITD_STS_ACTIVE)
++
++	__hc32			hw_buf[2];		/* EHCI table 3-12 */
++	__hc32			hw_backpointer;		/* EHCI table 3-13 */
++	__hc32			hw_buf_hi[2];		/* Appendix B */
++
++	/* the rest is HCD-private */
++	dma_addr_t		sitd_dma;
++	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
++
++	struct urb		*urb;
++	struct ehci_iso_stream	*stream;	/* endpoint's queue */
++	struct list_head	sitd_list;	/* list of stream's sitds */
++	unsigned		frame;
++	unsigned		index;
++} __attribute__ ((aligned(32)));
++
++/*
++ * EHCI Specification 0.96 Section 3.7
++ * Periodic Frame Span Traversal Node (FSTN)
++ *
++ * Manages split interrupt transactions (using TT) that span frame boundaries
++ * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
++ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
++ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
++ */
++struct ehci_fstn {
++	__hc32			hw_next;	/* any periodic q entry */
++	__hc32			hw_prev;	/* qh or EHCI_LIST_END */
++
++	/* the rest is HCD-private */
++	dma_addr_t		fstn_dma;
++	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
++} __attribute__ ((aligned(32)));
++
++/* Prepare the PORTSC wakeup flags during controller suspend/resume */
++
++#define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup)	\
++		ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup);
++
++#define ehci_prepare_ports_for_controller_resume(ehci)			\
++		ehci_adjust_port_wakeup_flags(ehci, false, false);
++
++#ifdef CONFIG_PPC_83xx
++/* Some Freescale processors have an erratum in which the TT
++ * port number in the queue head was 0..N-1 instead of 1..N.
++ */
++#define	ehci_has_fsl_portno_bug(e)		((e)->has_fsl_port_bug)
++#else
++#define	ehci_has_fsl_portno_bug(e)		(0)
++#endif
++
++/*
++ * While most USB host controllers implement their registers in
++ * little-endian format, a minority (celleb companion chip) implement
++ * them in big endian format.
++ *
++ * This attempts to support either format at compile time without a
++ * runtime penalty, or both formats with the additional overhead
++ * of checking a flag bit.
++ *
++ * ehci_big_endian_capbase is a special quirk for controllers that
++ * implement the HC capability registers as separate registers and not
++ * as fields of a 32-bit register.
++ */
++
++#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
++#define ehci_big_endian_mmio(e)		((e)->big_endian_mmio)
++#define ehci_big_endian_capbase(e)	((e)->big_endian_capbase)
++#else
++#define ehci_big_endian_mmio(e)		0
++#define ehci_big_endian_capbase(e)	0
++#endif
++
++/*
++ * Big-endian read/write functions are arch-specific.
++ * Other arches can be added if/when they're needed.
++ */
++#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX)
++#define readl_be(addr)		__raw_readl((__force unsigned *)addr)
++#define writel_be(val, addr)	__raw_writel(val, (__force unsigned *)addr)
++#endif
++
++static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
++			__u32 __iomem *regs)
++{
++#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
++	return ehci_big_endian_mmio(ehci) ?
++		readl_be(regs) :
++		readl(regs);
++#else
++	return readl(regs);
++#endif
++}
++
++static inline void ehci_writel(const struct ehci_hcd *ehci,
++		const unsigned int val, __u32 __iomem *regs)
++{
++#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
++	ehci_big_endian_mmio(ehci) ?
++		writel_be(val, regs) :
++		writel(val, regs);
++#else
++	writel(val, regs);
++#endif
++}
++
++/*
++ * On certain ppc-44x SoC there is a HW issue, that could only worked around with
++ * explicit suspend/operate of OHCI. This function hereby makes sense only on that arch.
++ * Other common bits are dependent on has_amcc_usb23 quirk flag.
++ */
++#ifdef CONFIG_44x
++static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
++{
++	u32 hc_control;
++
++	hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS);
++	if (operational)
++		hc_control |= OHCI_USB_OPER;
++	else
++		hc_control |= OHCI_USB_SUSPEND;
++
++	writel_be(hc_control, ehci->ohci_hcctrl_reg);
++	(void) readl_be(ehci->ohci_hcctrl_reg);
++}
++#else
++static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
++{ }
++#endif
++
++/*
++ * The AMCC 440EPx not only implements its EHCI registers in big-endian
++ * format, but also its DMA data structures (descriptors).
++ *
++ * EHCI controllers accessed through PCI work normally (little-endian
++ * everywhere), so we won't bother supporting a BE-only mode for now.
++ */
++/* cpu to ehci */
++static inline __hc32 cpu_to_hc32(const struct ehci_hcd *ehci, const u32 x)
++{
++	return cpu_to_le32(x);
++}
++
++/* ehci to cpu */
++static inline u32 hc32_to_cpu(const struct ehci_hcd *ehci, const __hc32 x)
++{
++	return le32_to_cpu(x);
++}
++
++static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 *x)
++{
++	return le32_to_cpup(x);
++}
++
++#ifndef DEBUG
++#define STUB_DEBUG_FILES
++#endif	/* DEBUG */
++
++/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
++
++/* Section 2.2 Host Controller Capability Registers */
++struct ehci_caps {
++	/* these fields are specified as 8 and 16 bit registers,
++	 * but some hosts can't perform 8 or 16 bit PCI accesses.
++	 */
++	u32		hc_capbase;
++#define HC_LENGTH(p)		((p)&0x00ff)	/* bits 7:0 */
++#define HC_VERSION(p)		(((p)>>16)&0xffff)	/* bits 31:16 */
++	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
++#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
++#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
++#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
++#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
++#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */
++#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */
++#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
++
++	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
++#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
++#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
++#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
++#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
++#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
++#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
++	u8		portroute[8];	 /* nibbles for routing - offset 0xC */
++} __attribute__ ((packed));
++
++/* Section 2.3 Host Controller Operational Registers */
++struct ehci_regs {
++
++	/* USBCMD: offset 0x00 */
++	u32		command;
++/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
++#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
++#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
++#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
++#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
++#define CMD_ASE		(1<<5)		/* async schedule enable */
++#define CMD_PSE		(1<<4)		/* periodic schedule enable */
++/* 3:2 is periodic frame list size */
++#define CMD_RESET	(1<<1)		/* reset HC not bus */
++#define CMD_RUN		(1<<0)		/* start/stop HC */
++
++	/* USBSTS: offset 0x04 */
++	u32		status;
++#define STS_ASS		(1<<15)		/* Async Schedule Status */
++#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
++#define STS_RECL	(1<<13)		/* Reclamation */
++#define STS_HALT	(1<<12)		/* Not running (any reason) */
++/* some bits reserved */
++	/* these STS_* flags are also intr_enable bits (USBINTR) */
++#define STS_IAA		(1<<5)		/* Interrupted on async advance */
++#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
++#define STS_FLR		(1<<3)		/* frame list rolled over */
++#define STS_PCD		(1<<2)		/* port change detect */
++#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
++#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
++
++	/* USBINTR: offset 0x08 */
++	u32		intr_enable;
++
++	/* FRINDEX: offset 0x0C */
++	u32		frame_index;	/* current microframe number */
++	/* CTRLDSSEGMENT: offset 0x10 */
++	u32		segment;	/* address bits 63:32 if needed */
++	/* PERIODICLISTBASE: offset 0x14 */
++	u32		frame_list;	/* points to periodic list */
++	/* ASYNCLISTADDR: offset 0x18 */
++	u32		async_next;	/* address of next async queue head */
++
++	/* missed on Faraday controller */
++	/* u32		reserved[9]; */
++
++	/* CONFIGFLAG: offset 0x40 */
++	u32		configured_flag;
++#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
++
++	/* PORTSC: offset 0x20 (0x44) */
++	u32		port_status[0];	/* up to N_PORTS */
++/* 31:23 reserved */
++#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
++#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
++#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
++/* 19:16 for port testing */
++#define PORT_TEST_PKT	(0x4<<16)	/* Port Test Control - packet test */
++#define PORT_LED_OFF	(0<<14)
++#define PORT_LED_AMBER	(1<<14)
++#define PORT_LED_GREEN	(2<<14)
++#define PORT_LED_MASK	(3<<14)
++#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
++#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
++#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))	/* USB 1.1 device */
++/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
++/* 9 reserved */
++#define PORT_RESET	(1<<8)		/* reset port */
++#define PORT_SUSPEND	(1<<7)		/* suspend port */
++#define PORT_RESUME	(1<<6)		/* resume it */
++#define PORT_OCC	(1<<5)		/* over current change */
++#define PORT_OC		(1<<4)		/* over current active */
++#define PORT_PEC	(1<<3)		/* port enable change */
++#define PORT_PE		(1<<2)		/* port enable */
++#define PORT_CSC	(1<<1)		/* connect status change */
++#define PORT_CONNECT	(1<<0)		/* device connected */
++#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
++} __attribute__ ((packed));
++
++#define USBMODE		0x68		/* USB Device mode */
++#define USBMODE_SDIS	(1<<3)		/* Stream disable */
++#define USBMODE_BE	(1<<2)		/* BE/LE endianness select */
++#define USBMODE_CM_HC	(3<<0)		/* host controller mode */
++#define USBMODE_CM_IDLE	(0<<0)		/* idle state */
++
++/* Moorestown has some non-standard registers, partially due to the fact that
++ * its EHCI controller has both TT and LPM support. HOSTPCx are extentions to
++ * PORTSCx
++ */
++#define HOSTPC0		0x84		/* HOSTPC extension */
++#define HOSTPC_PHCD	(1<<22)		/* Phy clock disable */
++#define HOSTPC_PSPD	(3<<25)		/* Port speed detection */
++#define USBMODE_EX	0xc8		/* USB Device mode extension */
++#define USBMODE_EX_VBPS	(1<<5)		/* VBus Power Select On */
++#define USBMODE_EX_HC	(3<<0)		/* host controller mode */
++#define TXFILLTUNING	0x24		/* TX FIFO Tuning register */
++#define TXFIFO_DEFAULT	(8<<16)		/* FIFO burst threshold 8 */
++
++/* Appendix C, Debug port ... intended for use with special "debug devices"
++ * that can help if there's no serial console.  (nonstandard enumeration.)
++ */
++struct ehci_dbg_port {
++	u32	control;
++#define DBGP_OWNER	(1<<30)
++#define DBGP_ENABLED	(1<<28)
++#define DBGP_DONE	(1<<16)
++#define DBGP_INUSE	(1<<10)
++#define DBGP_ERRCODE(x)	(((x)>>7)&0x07)
++#	define DBGP_ERR_BAD	1
++#	define DBGP_ERR_SIGNAL	2
++#define DBGP_ERROR	(1<<6)
++#define DBGP_GO		(1<<5)
++#define DBGP_OUT	(1<<4)
++#define DBGP_LEN(x)	(((x)>>0)&0x0f)
++	u32	pids;
++#define DBGP_PID_GET(x)		(((x)>>16)&0xff)
++#define DBGP_PID_SET(data, tok)	(((data)<<8)|(tok))
++	u32	data03;
++	u32	data47;
++	u32	address;
++#define DBGP_EPADDR(dev, ep)	(((dev)<<8)|(ep))
++} __attribute__ ((packed));
++
++#ifdef CONFIG_EARLY_PRINTK_DBGP
++#include <linux/init.h>
++extern int __init early_dbgp_init(char *s);
++extern struct console early_dbgp_console;
++#endif /* CONFIG_EARLY_PRINTK_DBGP */
++
++#ifdef CONFIG_EARLY_PRINTK_DBGP
++/* Call backs from ehci host driver to ehci debug driver */
++extern int dbgp_external_startup(void);
++extern int dbgp_reset_prep(void);
++#else
++static inline int dbgp_reset_prep(void)
++{
++	return 1;
++}
++static inline int dbgp_external_startup(void)
++{
++	return -1;
++}
++#endif
++
++static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
++{
++	return ehci_readl(ehci, &ehci->regs->frame_index);
++}
++
++/*
++ * Some EHCI controllers have a Transaction Translator built into the
++ * root hub. This is a non-standard feature.  Each controller will need
++ * to add code to the following inline functions, and call them as
++ * needed (mostly in root hub code).
++ */
++
++#define	ehci_is_TDI(e)			(ehci_to_hcd(e)->has_tt)
++
++#define FOTG210_OTGCSR		0x80
++#define OTGCSR_A_BUS_REQ	0x10
++#define OTGCSR_A_BUS_DROP	0x20
++#define OTGCSR_HOST_SPD_TYP	0xC000000
++
++#define FOTG210_GMIR		0xC4
++#define GMIR_INT_POLARITY	0x8 /*Active High*/
++#define GMIR_MHC_INT		0x4
++#define GMIR_MOTG_INT		0x2
++#define GMIR_MDEV_INT		0x1
++
++/* Returns the speed of a device attached to a port on the root hub. */
++static inline unsigned int
++ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
++{
++	u32 __iomem *reg_ptr;
++	u32 tmp;
++
++	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->caps) +
++		FOTG210_OTGCSR);
++	tmp = readl(reg_ptr);
++	tmp = (tmp & OTGCSR_HOST_SPD_TYP) >> 22;
++
++	if (tmp == 2)
++		return USB_PORT_STAT_HIGH_SPEED;
++	else if (tmp == 1)
++		return USB_PORT_STAT_LOW_SPEED;
++	else if (tmp == 0)
++		return 0;
++	else
++		return USB_PORT_STAT_HIGH_SPEED;
++}
+diff --git a/drivers/usb/host/fotg2xx-config.h b/drivers/usb/host/fotg2xx-config.h
+new file mode 100644
+index 00000000..fe02a8c6
+--- /dev/null
++++ b/drivers/usb/host/fotg2xx-config.h
+@@ -0,0 +1,94 @@
++
++/*******************************************************************************
++ * Module name: config.h
++ *
++ * The information contained herein is confidential property of Company.
++ * The user, copying, transfer or disclosure of such information is
++ * prohibited except by express written agreement with Company.
++ *
++ * Module Description:
++ *  Port from kernel_tree/include/Linux/config.h
++ *  macro definition for configuration of platform and
++ *  compiler (DEBUG macros)
++ *
++ ******************************************************************************/
++
++#ifndef FOTG2XX_CONFIG_H_CHK
++#define FOTG2XX_CONFIG_H_CHK
++
++#ifdef CONFIG_GM_FOTG2XX_MODULE
++#define CONFIG_GM_FOTG2XX
++#endif
++
++/* Define the number of OTG devices in SoC*/
++#if defined(CONFIG_PLATFORM_GM8126) || defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++#define FOTG_DEV_NR 1
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8210)
++#define FOTG_DEV_NR 3
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8287)
++#define FOTG_DEV_NR 2
++#endif
++
++/* Define this const macro will disable any cod0e which is used to recover HW issue */
++//#define REMOVE_COVERHW	1
++
++/* =======================================================*/
++/* OTG application related macro definitions              */
++/* =======================================================*/
++#define CONFIG_OTG
++
++/* =======================================================*/
++//Please only define following macros if you need to cover PHY issues
++//#define CONFIG_711MA_PHY		/* For 711MA to enable hc to cover full speed reset issue */
++/* =======================================================*/
++
++
++////////////////////////////////////////
++#ifdef CONFIG_GM_FUSBH200
++#undef  CONFIG_OTG
++#define FUSBH200_REGBASE   USB_FUSBH200_VA_BASE
++#define FUSBH200_IRQ       USB_FUSBH200_IRQ
++#endif
++
++/* ======================================================*/
++/* DEBUG fucniton macro definitions                      */
++/* ======================================================*/
++//#define SHOW_MSG
++//#define DEBUG
++//#define CONFIG_DEBUG
++//#define CONFIG_USB_DEBUG
++//#define VERBOSE_DEBUG
++//#define KERNEL_DEBUG
++#ifndef CONFIG_GM_FOTG2XX
++#ifdef VERBOSE_DEBUG
++#define OHCI_VERBOSE_DEBUG  //Enable Verbose debug, dump more details
++#endif
++#else
++#ifdef VERBOSE_DEBUG
++#define EHCI_VERBOSE_DEBUG  //Enable Verbose debug, dump more details
++#endif
++#endif
++
++#ifdef SHOW_MSG
++#define msg	printk
++#else
++#define msg(format,...) do {} while (0)
++#endif
++
++#if defined(CONFIG_GM_FOTG2XX_INFO) || defined(CONFIG_GM_FUSBH200_INFO)
++#define fotg2xx_dbg(format, ...) printk(KERN_INFO " "format, __VA_ARGS__ )
++#else
++#define fotg2xx_dbg(format, ...) do {} while (0)
++#endif
++
++#ifdef KERNEL_DEBUG
++#define kdbg dbg
++#else
++#define kdbg(format, ...) do {} while (0)
++#endif
++
++#endif  /* FOTG2XX-CONFIG_H_CHK */
+diff --git a/drivers/usb/host/fotg2xx-ehci-macro.h b/drivers/usb/host/fotg2xx-ehci-macro.h
+new file mode 100644
+index 00000000..c93a6542
+--- /dev/null
++++ b/drivers/usb/host/fotg2xx-ehci-macro.h
+@@ -0,0 +1,125 @@
++#ifndef FOTG2XX_EHCI_MACRO_H_CHK
++#define FOTG2XX_EHCI_MACRO_H_CHK
++
++#include "fotg2xx-config.h"
++#include <asm/io.h>
++/*-------------------------------------------------------------------------*/
++
++#define H200_NAME "FUSBH200"
++#define OTG2XX_NAME "FOTG2XX"
++
++void fotg200_handle_irq(int irq);
++
++#if defined(CONFIG_GM_FOTG2XX)
++  /* FOTG2XX Global Controller Register Macro Definition */
++  //<1>.Macro volatile
++  #define mwOTG20Port(reg,bOffset)	            *((volatile u32 __force *)((u32)reg|bOffset))
++  #define mwOTG20Bit_Rd(reg,bByte,wBitNum)            (mwOTG20Port(reg,bByte)&wBitNum)
++  #define mwOTG20Bit_Set(reg,bByte,wBitNum)           (mwOTG20Port(reg,bByte)|=wBitNum)
++  #define mwOTG20Bit_Clr(reg,bByte,wBitNum)           (mwOTG20Port(reg,bByte)&=~wBitNum)
++  // 0x0C0(Interrupt Status)
++  #define mwOTG20_Interrupt_Status_HOST_Rd(x)       (mwOTG20Bit_Rd(x,0xC0,0x00000004))
++  #define mwOTG20_Interrupt_Status_HOST_Clr(x)	   (mwOTG20Port(x,0xC0)= 0x00000004)
++
++  // 0x0C4(Interrupt Mask)
++  #define mwOTG20_Interrupt_Mask_HOST_Clr(x)	    mwOTG20Bit_Clr(x,0xC4,0x00000004)
++
++  //0x100(Device Controller Registers(Address = 100h~1FFh) )
++  #define mwPeri20_Control_ChipEnable_Set(x)         mwOTG20Bit_Set(x,0x100,BIT5)
++  #define mwPeri20_Control_HALFSPEEDEnable_Set(x)    mwOTG20Bit_Set(x,0x100,BIT1)
++  #define mwPeri20_Control_HALFSPEEDEnable_Clr(x)    mwOTG20Bit_Clr(x,0x100,BIT1)
++  #define mwPeri20_Control_ForceDeviceFS_Set(x)    mwOTG20Bit_Set(x,0x100,BIT9)
++  #define mwPeri20_Control_ForceDeviceFS_Clr(x)    mwOTG20Bit_Clr(x,0x100,BIT9)
++  //0x80 <OTG Controller Register>
++  #define mwOTG20_Control_ForceFullSpeed_Set(x)      mwOTG20Bit_Set(x,0x80,BIT12)
++  #define mwOTG20_Control_ForceHighSpeed_Set(x)      (mwOTG20Bit_Set(x,0x80,BIT14))
++  #define mwOTG20_Control_ForceFullSpeed_Clr(x)      mwOTG20Bit_Clr(x,0x80,BIT12)
++  #define mwOTG20_Control_ForceHighSpeed_Clr(x)      (mwOTG20Bit_Clr(x,0x80,BIT14))
++
++  #ifdef CONFIG_711MA_PHY
++     // Cover 711MA PHY (Full speed reset issue)
++     #define mwOTG20_Control_COVER_FS_PHY_Reset_Set(x)  mwOTG20Bit_Set(x,0x80,BIT28)
++     #define mwOTG20_Control_COVER_FS_PHY_Reset_Clr(x)  mwOTG20Bit_Clr(x,0x80,BIT28)
++  #endif
++#endif /* CONFIG_GM_FOTG2XX */
++
++#ifdef CONFIG_GM_FUSBH200
++  /* FOTG2XX Global Controller Register Macro Definition */
++  //<1>.Macro volatile
++  #define mwH20Port(reg,bOffset)               *((volatile u32 __force *)((u32)reg | bOffset))
++  #define mwH20Bit_Rd(x,bByte,wBitNum)            (mwH20Port(x,bByte)&wBitNum)
++  #define mwH20Bit_Set(x,bByte,wBitNum)           (mwH20Port(x,bByte)|=wBitNum)
++  #define mwH20Bit_Clr(x,bByte,wBitNum)           (mwH20Port(x,bByte)&=~wBitNum)
++
++  // 0x40(Bus Monitor Control/Status)
++  #define mwH20_Control_VBUS_FLT_SEL_Set(x)          mwH20Bit_Set(x,0x40,BIT0)
++  #define mwH20_Control_VBUS_FLT_SEL_Clr(x)          mwH20Bit_Clr(x,0x40,BIT0)
++  #define mwH20_Control_HDISCON_FLT_SEL_Set(x)       mwH20Bit_Set(x,0x40,BIT1)
++  #define mwH20_Control_HDISCON_FLT_SEL_Clr(x)       mwH20Bit_Clr(x,0x40,BIT1)
++  #define mwH20_Control_HALFSPEEDEnable_Set(x)       mwH20Bit_Set(x,0x40,BIT2)
++  #define mwH20_Control_HALFSPEEDEnable_Clr(x)       mwH20Bit_Clr(x,0x40,BIT2)
++  #define mwH20_Interrupt_OutPut_High_Set(x)         mwH20Bit_Set(x,0x40,BIT3)
++  #define mwH20_Interrupt_OutPut_High_Clr(x)         mwH20Bit_Clr(x,0x40,BIT3)
++  #define mwH20_Control_VBUS_OFF_Set(x)              mwH20Bit_Set(x,0x40,BIT4)
++  #define mwH20_Control_VBUS_OFF_Clr(x)              mwH20Bit_Clr(x,0x40,BIT4)
++  #define mwH20_Control_Phy_Reset_Set(x)             mwH20Bit_Set(x,0x40,BIT5)
++  #define mwH20_Control_Phy_Reset_Clr(x)             mwH20Bit_Clr(x,0x40,BIT5)
++  #define mwH20_Control_ForceFullSpeed_Set(x)        mwH20Bit_Set(x,0x40,BIT7)
++  #define mwH20_Control_ForceHighSpeed_Set(x)        mwH20Bit_Set(x,0x40,BIT6)
++  #define mwH20_Control_ForceFullSpeed_Clr(x)        mwH20Bit_Clr(x,0x40,BIT7)
++  #define mwH20_Control_ForceHighSpeed_Clr(x)        mwH20Bit_Clr(x,0x40,BIT6)
++  #define mwH20_Control_VBUS_VLD_Rd(x)               mwH20Bit_Rd(x,0x40,BIT8)
++  #define mwH20_Control_HOST_SPD_TYP_Rd(x)           mwH20Bit_Rd(x,0x40,(BIT9|BIT10))
++  #ifdef CONFIG_711MA_PHY
++     // Cover 711MA PHY (Full speed reset issue)
++     #define mwH20_Control_COVER_FS_PHY_Reset_Set(x)    mwH20Bit_Set(x,0x40,BIT12)
++     #define mwH20_Control_COVER_FS_PHY_Reset_Clr(x)    mwH20Bit_Clr(x,0x40,BIT12)
++  #endif
++
++  // 0x044(Bus Monitor Interrupt Status)
++  #define mwH20_Int_Status_BM_DMA_ERROR_Rd(x)       mwH20Bit_Rd(x,0x44,0x00000010)
++  #define mwH20_Int_Status_BM_DMA_CMPLT_Rd(x)       mwH20Bit_Rd(x,0x44,0x00000008)
++  #define mwH20_Int_Status_BM_DPLGRMV_Rd(x)         mwH20Bit_Rd(x,0x44,0x00000004)
++  #define mwH20_Int_Status_BM_OVC_Rd(x)             mwH20Bit_Rd(x,0x44,0x00000002)
++  #define mwH20_Int_Status_BM_VBUS_ERR_Rd(x)        mwH20Bit_Rd(x,0x44,0x00000001)
++  #define mwH20_Int_Status_BM_DMA_ERROR_Clr(x)      (mwH20Port(x,0x44)= 0x00000010)
++  #define mwH20_Int_Status_BM_DMA_CMPLT_Clr(x)      (mwH20Port(x,0x44)= 0x00000008)
++  #define mwH20_Int_Status_BM_DPLGRMV_Clr(x)        (mwH20Port(x,0x44)= 0x00000004)
++  #define mwH20_Int_Status_BM_OVC_Clr(x)            (mwH20Port(x,0x44)= 0x00000002)
++  #define mwH20_Int_Status_BM_VBUS_ERR_Clr(x)       (mwH20Port(x,0x44)= 0x00000001)
++  // 0x048(Bus Monitor Interrupt Enable)
++  #define mwH20_Int_BM_DMA_ERROR_En(x)              mwH20Bit_Set(x,0x48,0x00000010)
++  #define mwH20_Int_BM_DMA_CMPLT_En(x)              mwH20Bit_Set(x,0x48,0x00000008)
++  #define mwH20_Int_BM_BPLGRMV_En(x)                mwH20Bit_Set(x,0x48,0x00000004)
++  #define mwH20_Int_BM_OVC_En(x)                    mwH20Bit_Set(x,0x48,0x00000002)
++  #define mwH20_Int_BM_VBUS_ERR_En(x)               mwH20Bit_Set(x,0x48,0x00000001)
++  #define mwH20_Int_BM_DMA_ERROR_Dis(x)             mwH20Bit_Clr(x,0x48,0x00000010)
++  #define mwH20_Int_BM_DMA_CMPLT_Dis(x)             mwH20Bit_Clr(x,0x48,0x00000008)
++  #define mwH20_Int_BM_DPLGRMV_Dis(x)               mwH20Bit_Clr(x,0x48,0x00000004)
++  #define mwH20_Int_BM_OVC_Dis(x)                   mwH20Bit_Clr(x,0x48,0x00000002)
++  #define mwH20_Int_BM_VBUS_ERR_Dis(x)              mwH20Bit_Clr(x,0x48,0x00000001)
++  #define mwH20_Int_BM_DMA_ERROR_Rd(x)              mwH20Bit_Rd(x,0x48,0x00000010)
++  #define mwH20_Int_BM_DMA_CMPLT_Rd(x)              mwH20Bit_Rd(x,0x48,0x00000008)
++  #define mwH20_Int_BM_BPLGRMV_Rd(x)                mwH20Bit_Rd(x,0x48,0x00000004)
++  #define mwH20_Int_BM_OVC_Rd(x)                    mwH20Bit_Rd(x,0x48,0x00000002)
++  #define mwH20_Int_BM_VBUS_ERR_Rd(x)               mwH20Bit_Rd(x,0x48,0x00000001)
++	// 0x50(Test)
++  #define mwH20_Test_TST_JSTA_Set(x)                mwH20Bit_Set(x,0x50,BIT0)
++  #define mwH20_Test_TST_JSTA_Clr(x)                mwH20Bit_Clr(x,0x50,BIT0)
++  #define mwH20_Test_TST_KSTA_Set(x)                mwH20Bit_Set(x,0x50,BIT1)
++  #define mwH20_Test_TST_KSTA_Clr(x)                mwH20Bit_Clr(x,0x50,BIT1)
++  #define mwH20_Test_TST_PKT_Set(x)                 mwH20Bit_Set(x,0x50,BIT2)
++  #define mwH20_Test_TST_PKT_Clr(x)                 mwH20Bit_Clr(x,0x50,BIT2)
++  #define mwH20_Test_TST_MOD_Set(x)                 mwH20Bit_Set(x,0x50,BIT3)
++  #define mwH20_Test_TST_MOD_Clr(x)                 mwH20Bit_Clr(x,0x50,BIT3)
++  #define mwH20_Test_TST_LOOPBK_Set(x)              mwH20Bit_Set(x,0x50,BIT4)
++  #define mwH20_Test_TST_LOOPBK_Clr(x)              mwH20Bit_Clr(x,0x50,BIT4)
++  // 0x54(Vendor Specific I/O Control Register)
++  #define mwH20_Test_VCTL_Rd(x)                     mwH20Bit_Rd(x,0x50,0x0000001F)
++  #define mwH20_Test_VCTL_Set(x,Value)               mwH20Bit_Set(x,0x50,Value)
++  #define mwH20_Test_VCTLOAD_N_Set(x)               mwH20Bit_Set(x,0x50,BIT5)
++  #define mwH20_Test_VCTLOAD_N_Clr(x)               mwH20Bit_Clr(x,0x50,BIT5)
++
++#endif /* CONFIG_GM_FUSBH200 */
++
++#endif
+diff --git a/drivers/usb/host/fotg2xx_opt-macro.h b/drivers/usb/host/fotg2xx_opt-macro.h
+new file mode 100644
+index 00000000..b99ec51f
+--- /dev/null
++++ b/drivers/usb/host/fotg2xx_opt-macro.h
+@@ -0,0 +1,212 @@
++//////////////////////////////////////////////////////////////////////////////
++//  File name: OTGController.h
++//  Company: GM Tech. Corp.
++//  Description: 1.Define Data Type
++//               2.Define for Bulk
++//               3.Define Macro
++///////////////////////////////////////////////////////////////////////////////
++
++#include "fotg2xx-config.h"
++#include <linux/usb.h>
++#include <linux/usb/gadget.h>
++
++#ifndef FOTG2XX_GADGET_MACRO_H_CHK
++#define FOTG2XX_GADGET_MACRO_H_CHK
++
++#if defined(CONFIG_GM_FOTG2XX)
++#define mbFOTGPort(reg, bOffset)	*((volatile u8 *) ( ((u32)reg+0x80) | bOffset))
++#define mwFOTGPort(reg, bOffset)	*((volatile u16 *) ( ((u32)reg+0x80) | bOffset))
++#define mdwFOTGPort(reg, bOffset)	*((volatile u32 __force *)( (u32)(reg+0x80) | bOffset))
++#define mdwPort(portbase,bOffset)	*((volatile u32 __force *) ( (u32)portbase | bOffset))
++#endif
++
++
++#define BIT0	                 0x00000001
++#define BIT1	                 0x00000002
++#define BIT2	                 0x00000004
++#define BIT3	                 0x00000008
++#define BIT4	                 0x00000010
++#define BIT5	                 0x00000020
++#define BIT6	                 0x00000040
++#define BIT7	                 0x00000080
++#define BIT8	                 0x00000100
++#define BIT9	                 0x00000200
++#define BIT10	                 0x00000400
++#define BIT11	                 0x00000800
++#define BIT12	                 0x00001000
++#define BIT13	                 0x00002000
++#define BIT14	                 0x00004000
++#define BIT15	                 0x00008000
++#define BIT16	                 0x00010000
++#define BIT17	                 0x00020000
++#define BIT18	                 0x00040000
++#define BIT19	                 0x00080000
++#define BIT20	                 0x00100000
++#define BIT21	                 0x00200000
++#define BIT22	                 0x00400000
++#define BIT23	                 0x00800000
++#define BIT24	                 0x01000000
++#define BIT25	                 0x02000000
++#define BIT26	                 0x04000000
++#define BIT27	                 0x08000000
++#define BIT28	                 0x10000000
++#define BIT29	                 0x20000000
++#define BIT30	                 0x40000000
++#define BIT31	                 0x80000000
++
++//=================== 1.OTG Condition Setting ==========================================
++#define   OTGC_ENABLE     //If Only peripheral => Please disable this item
++#define   OTGC_A_SRP_RESPONSE_TYPE  A_SRP_RESP_TYPE_VBUS  //A_SRP_RESP_TYPE_DATA_LINE
++#define   OTGC_Device_Not_Support_Then_Return 1
++
++//=================== 2.Define Macro ==================================================
++#define mwOTG20_stop_host(x)    mwOTG20Bit_Clr(x,0x10,BIT0)
++#define mwOTG20_start_host(x)   mwOTG20Bit_Set(x,0x10,BIT0)
++#define mwOTG20_b_conn_Rd(x)    mwOTG20Bit_Rd(x,0x30,BIT0)
++#define mwOTG20_reset_Set(x)    mwOTG20Bit_Set(x,0x30,BIT8)
++#define mwOTG20_reset_Clr(x)    mwOTG20Bit_Clr(x,0x30,BIT8)
++#define mwOTG20_porten_Set(x)   mwOTG20Bit_Set(x,0x30,BIT2)
++#define mwOTG20_porten_Clr(x)   mwOTG20Bit_Clr(x,0x30,BIT2)
++#define mwOTG20_suspend_Set(x)  mwOTG20Bit_Set(x,0x30,BIT7)
++#define mwOTG20_suspend_Clr(x)  mwOTG20Bit_Clr(x,0x30,BIT7)
++
++//Offset:0x000(OTG Control/Status Register) => Suppose Word-Read & Word-Write
++//~B
++#define mdwOTGC_Control_B_BUS_REQ_Rd(reg)         (mdwFOTGPort(reg,0x00)& BIT0)
++#define mdwOTGC_Control_B_BUS_REQ_Set(reg)        (mdwFOTGPort(reg,0x00) |=  BIT0)
++#define mdwOTGC_Control_B_BUS_REQ_Clr(reg)        (mdwFOTGPort(reg,0x00) &=  (~BIT0))
++
++#define mdwOTGC_Control_B_HNP_EN_Rd(reg)          (mdwFOTGPort(reg,0x00)& BIT1)
++#define mdwOTGC_Control_B_HNP_EN_Set(reg)         (mdwFOTGPort(reg,0x00) |=  BIT1)
++#define mdwOTGC_Control_B_HNP_EN_Clr(reg)         (mdwFOTGPort(reg,0x00) &=  (~BIT1))
++
++#define mdwOTGC_Control_B_DSCHG_VBUS_Rd(reg)      (mdwFOTGPort(reg,0x00)& BIT2)
++#define mdwOTGC_Control_B_DSCHG_VBUS_Set(reg)     (mdwFOTGPort(reg,0x00) |=  BIT2)
++#define mdwOTGC_Control_B_DSCHG_VBUS_Clr(reg)     (mdwFOTGPort(reg,0x00) &=  (~BIT2))
++
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_USB_GADGET_DUALSPEED)
++#define mdwOTGC_Control_A_SRP_RESP_TYPE_Rd(reg)    (mdwFOTGPort(reg,0x00)& BIT8)
++#define mdwOTGC_Control_A_SRP_RESP_TYPE_Set(reg)   (mdwFOTGPort(reg,0x00) |=  BIT8)
++#define mdwOTGC_Control_A_SRP_RESP_TYPE_Clr(reg)   (mdwFOTGPort(reg,0x00) &=  (~BIT8))
++
++#define mdwOTGC_Control_A_SRP_DET_EN_Rd(reg)        (mdwFOTGPort(reg,0x00)& BIT7)
++#define mdwOTGC_Control_A_SRP_DET_EN_Set(reg)       (mdwFOTGPort(reg,0x00) |=  BIT7)
++#define mdwOTGC_Control_A_SRP_DET_EN_Clr(reg)       (mdwFOTGPort(reg,0x00) &=  (~BIT7))
++#endif
++
++#define mdwOTGC_Control_A_SET_B_HNP_EN_Rd(reg)     (mdwFOTGPort(reg,0x00)& BIT6)
++#define mdwOTGC_Control_A_SET_B_HNP_EN_Set(reg)    (mdwFOTGPort(reg,0x00) |=  BIT6)
++#define mdwOTGC_Control_A_SET_B_HNP_EN_Clr(reg)    (mdwFOTGPort(reg,0x00) &=  (~BIT6))
++
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_USB_GADGET_DUALSPEED)
++#define mdwOTGC_Control_A_BUS_DROP_Rd(reg)     (mdwFOTGPort(reg,0x00)& BIT5)
++#define mdwOTGC_Control_A_BUS_DROP_Set(reg)    (mdwFOTGPort(reg,0x00) |=  BIT5)
++#define mdwOTGC_Control_A_BUS_DROP_Clr(reg)    (mdwFOTGPort(reg,0x00) &=  (~BIT5))
++#define mdwOTGC_Control_A_BUS_REQ_Rd(reg)      (mdwFOTGPort(reg,0x00)& BIT4)
++#define mdwOTGC_Control_A_BUS_REQ_Set(reg)     (mdwFOTGPort(reg,0x00) |=  BIT4)
++#define mdwOTGC_Control_A_BUS_REQ_Clr(reg)     (mdwFOTGPort(reg,0x00) &=  (~BIT4))
++#endif
++
++#define mdwOTGC_Control_OTG_Reset_Set(reg)     (mdwFOTGPort(reg,0x00) |=  BIT24)
++#define mdwOTGC_Control_OTG_Reset_Clr(reg)     (mdwFOTGPort(reg,0x00) &=  (~BIT24))
++#define mdwOTGC_Control_PHY_Reset_Set(reg)     (mdwFOTGPort(reg,0x00) |=  BIT15)
++#define mdwOTGC_Control_PHY_Reset_Clr(reg)     (mdwFOTGPort(reg,0x00) &=  (~BIT15))
++#define mdwOTGC_Control_B_SESS_END_Rd(reg)     (mdwFOTGPort(reg,0x00)& BIT16)
++#define mdwOTGC_Control_B_SESS_VLD_Rd(reg)     (mdwFOTGPort(reg,0x00)& BIT17)
++#define mdwOTGC_Control_A_SESS_VLD_Rd(reg)     (mdwFOTGPort(reg,0x00)& BIT18)
++#define mdwOTGC_Control_A_VBUS_VLD_Rd(reg)     (mdwFOTGPort(reg,0x00)& BIT19)
++#define mdwOTGC_Control_CROLE_Rd(reg)          (mdwFOTGPort(reg,0x00)& BIT20)
++#define mdwOTGC_Control_ID_Rd(reg)             (mdwFOTGPort(reg,0x00)& BIT21)
++#define mdwOTGC_Control_Rd(reg)                (mdwFOTGPort(reg,0x00))
++
++#define A_SRP_RESP_TYPE_VBUS                0x00
++#define A_SRP_RESP_TYPE_DATA_LINE           0x10
++
++//Offset:0x004(OTG Interrupt Status Register)
++#define mdwOTGC_INT_STS_Rd(reg)                (mdwFOTGPort(reg,0x04))
++#define mdwOTGC_INT_STS_Clr(reg,wValue)         (mdwFOTGPort(reg,0x04) |= wValue)
++
++#define OTGC_INT_BSRPDN                     BIT0
++#define OTGC_INT_ASRPDET                    BIT4
++#define OTGC_INT_AVBUSERR                   BIT5
++#define OTGC_INT_RLCHG                      BIT8
++#define OTGC_INT_IDCHG                      BIT9
++#define OTGC_INT_OVC                        BIT10
++#define OTGC_INT_BPLGRMV                    BIT11
++#define OTGC_INT_APLGRMV                    BIT12
++
++#define OTGC_INT_A_TYPE   (OTGC_INT_ASRPDET|OTGC_INT_AVBUSERR|OTGC_INT_OVC|OTGC_INT_RLCHG|OTGC_INT_IDCHG|OTGC_INT_BPLGRMV|OTGC_INT_APLGRMV)
++#define OTGC_INT_B_TYPE   (OTGC_INT_BSRPDN|OTGC_INT_AVBUSERR|OTGC_INT_OVC|OTGC_INT_RLCHG|OTGC_INT_IDCHG)
++
++//Offset:0x008(OTG Interrupt Enable Register)
++#define mdwOTGC_INT_Enable_Rd(reg)              (mdwFOTGPort(reg,0x08))
++#define mdwOTGC_INT_Enable_Set(reg,wValue)       (mdwFOTGPort(reg,0x08)|= wValue)
++#define mdwOTGC_INT_Enable_Clr(reg,wValue)       (mdwFOTGPort(reg,0x08)&= (~wValue))
++
++#define mdwOTGC_INT_Enable_BSRPDN_Set(reg)      (mdwFOTGPort(reg,0x08) |=  BIT0)
++#define mdwOTGC_INT_Enable_ASRPDET_Set(reg)     (mdwFOTGPort(reg,0x08) |=  BIT4)
++#define mdwOTGC_INT_Enable_AVBUSERR_Set(reg)    (mdwFOTGPort(reg,0x08) |=  BIT5)
++#define mdwOTGC_INT_Enable_RLCHG_Set(reg)       (mdwFOTGPort(reg,0x08) |=  BIT8)
++#define mdwOTGC_INT_Enable_IDCHG_Set(reg)       (mdwFOTGPort(reg,0x08) |=  BIT9)
++#define mdwOTGC_INT_Enable_OVC_Set(reg)         (mdwFOTGPort(reg,0x08) |=  BIT10)
++#define mdwOTGC_INT_Enable_BPLGRMV_Set(reg)     (mdwFOTGPort(reg,0x08) |=  BIT11)
++#define mdwOTGC_INT_Enable_APLGRMV_Set(reg)     (mdwFOTGPort(reg,0x08) |=  BIT12)
++
++#define mdwOTGC_INT_Enable_BSRPDN_Clr(reg)      (mdwFOTGPort(reg,0x08) &= ~BIT0)
++#define mdwOTGC_INT_Enable_ASRPDET_Clr(reg)     (mdwFOTGPort(reg,0x08) &= ~BIT4)
++#define mdwOTGC_INT_Enable_AVBUSERR_Clr(reg)    (mdwFOTGPort(reg,0x08) &= ~BIT5)
++#define mdwOTGC_INT_Enable_RLCHG_Clr(reg)       (mdwFOTGPort(reg,0x08) &= ~BIT8)
++#define mdwOTGC_INT_Enable_IDCHG_Clr(reg)       (mdwFOTGPort(reg,0x08) &= ~BIT9)
++#define mdwOTGC_INT_Enable_OVC_Clr(reg)         (mdwFOTGPort(reg,0x08) &= ~BIT10)
++#define mdwOTGC_INT_Enable_BPLGRMV_Clr(reg)     (mdwFOTGPort(reg,0x08) &= ~BIT11)
++#define mdwOTGC_INT_Enable_APLGRMV_Clr(reg)     (mdwFOTGPort(reg,0x08) &= ~BIT12)
++
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_USB_GADGET_DUALSPEED)
++// PHY Test Mode Selector register(0x114)
++#define mdwOTGC_UsbUnPLGClr(x)	             (mdwPort(x,0x114) &= ~BIT0)
++#define mdwOTGC_UsbUnPLGSet(x)                (mdwPort(x,0x114) |=  BIT0)
++#define mwOTG20_Interrupt_OutPut_High_Set(x)  (mdwPort(x,0xC4) |= BIT3)
++#define mwOTG20_Interrupt_OutPut_High_Clr(x)  (mdwPort(x,0xC4) &= ~BIT3)
++#endif
++
++#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_USB_GADGET_DUALSPEED)
++//===================3.Define Stricture ==================================================
++#define OTG_ID_A_TYPE 0
++#define OTG_ID_B_TYPE ((u32)1 << 21)
++
++#define OTG_ROLE_HOST 	0
++#define OTG_ROLE_DEVICE ((u32)1 << 20)
++
++/*typedef struct OTGC_STS
++  {
++    volatile int     CurrentRole;            // 0:Host  1:Peripheral
++    u32              wCurrentInterruptMask;
++    volatile u8      bVBUS_Vaild;
++    volatile u8      bDevice_RESET_Received;
++    volatile u8      bDevice_RemoteWakeUp_Received;
++    volatile u8      A_bASRPDET;
++    volatile u8      B_bBSRPDN;
++    volatile u8      A_BPLGRMV;
++    volatile u8      A_APLGRMV;
++    volatile u8      IDCHG;
++    struct usb_otgd  *otgd;
++} OTGC_STS;*/
++
++#define HC_SUSPEND  3
++#define HC_OPER     2
++#define HC_RESUME   1
++#define HC_RESET    0
++
++#define USB_HOST_ROLE     0
++#define USB_DEVICE_ROLE   1
++#define USB_OTG_TYPEA     0
++#define USB_OTG_TYPEB     1
++//Used by power management related funciton (ex. suspend, wake up, etc.)
++#define USB_PWM_SUSPEND   0
++#define USB_OTG_SUSPEND   1
++
++extern u8 OTGH_SET_FEATURE_OTG[];
++//===================4.Define Extern Function ===========================================
++#endif
++
++#endif /* FOTG2XX_GADGET_MACRO_H_CHK */
+diff --git a/drivers/usb/host/fotg2xx_opt.c b/drivers/usb/host/fotg2xx_opt.c
+new file mode 100644
+index 00000000..f17a9ecc
+--- /dev/null
++++ b/drivers/usb/host/fotg2xx_opt.c
+@@ -0,0 +1,828 @@
++/*******************************************************************************
++ * Module name: fotg2xx_opt.c
++ *
++ * Copyright 2009 GM for OTG function
++ * All Rights Reserved.
++ *
++ * The information contained herein is confidential property of Company.
++ * The user, copying, transfer or disclosure of such information is
++ * prohibited except by express written agreement with Company.
++ *
++ * Module Description:
++ *  This OTG dirver for GM FOTG2XX controller
++ *
++ ******************************************************************************/
++#undef DEBUG
++
++#ifdef CONFIG_USB_DEBUG
++#define DEBUG
++#else
++#undef DEBUG
++#endif
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/dmapool.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/reboot.h>
++#include <linux/usb.h>
++#include <linux/usb/otg.h>
++#include <linux/moduleparam.h>
++#include <linux/dma-mapping.h>
++#include <linux/kallsyms.h>
++#include <linux/platform_device.h>
++#include <linux/usb/hcd.h>
++
++#include "fotg2xx-config.h"
++#include "fotg2xx-ehci-macro.h"
++#include "fotg2xx_opt-macro.h"
++#include "../gadget/fotg2xx-peri-macro.h"
++
++#include <asm/byteorder.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/unaligned.h>
++#if defined(CONFIG_PLATFORM_GM8126) || defined(CONFIG_PLATFORM_GM8287) || defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++#include <mach/ftpmu010.h>
++#endif
++#if defined(CONFIG_PLATFORM_GM8210)
++#include <mach/ftpmu010_pcie.h>
++#include <mach/fmem.h>
++#endif
++
++/* PMU register data */
++#if defined(CONFIG_PLATFORM_GM8210)
++static void __iomem *h2x0_va_base;
++static void __iomem *h2x1_va_base;
++static void __iomem *h2x2_va_base;
++#endif
++static int usb_pmu_fd = -1;
++int usb_get_pmu_fd(void)
++{
++	return usb_pmu_fd;
++}
++EXPORT_SYMBOL(usb_get_pmu_fd);
++
++/* Register the reg_off and bit_masks that will be used in the future */
++#if !defined(CONFIG_PLATFORM_GM8210)
++
++static pmuReg_t regUSBArray[] = {
++	/* reg_off,bit_masks,lock_bits,init_val,init_mask */
++#if defined(CONFIG_PLATFORM_GM8126)
++	{0x38, BIT16, BIT16, 0, BIT16},
++	{0xA0, ~0x0, ~0x0, 0x81001, ~0x0}, //OTG control reg.
++#elif defined(CONFIG_PLATFORM_GM8287)
++    {0xC0, 0x7F | BIT19, 0x7F | BIT19, 0x78 | BIT19, 0x7F | BIT19}, /* OTG0, 0x7f equals BIT0~6 */
++    {0xC8, 0x7F | BIT19, 0x7F | BIT19, 0x78 | BIT19, 0x7F | BIT19}, /* OTG1, 0x7f equals BIT0~6 */
++#elif defined(CONFIG_PLATFORM_GM8139)
++    {0xAC, BIT0, BIT0, 0, BIT0},            /* OTG PHY clock */
++    {0xB4, BIT9, BIT9, 0, BIT9},            /* OTG controller clock */
++    {0xC0, ~0x0, ~0x0, 0xff80379, ~0x0},    /* OTG PHY: PCR<2:1>=11, TXSW<1:0>=11, PREEMPS_EN=1, PREEMPS<2:0>=111 */
++#elif defined(CONFIG_PLATFORM_GM8136)
++    {0xAC, BIT0, BIT0, 0, BIT0},            /* OTG PHY clock */
++    {0xB4, BIT9 | BIT16, BIT9 | BIT16, BIT16, BIT9 | BIT16},        /* OTG controller clock, BIT9:OTG0, BIT16:OTG1 */
++    {0xC0, ~0x0, ~0x0, 0xff8037b, ~0x0},    /* OTG PHY: PCR<2:1>=11, TXSW<1:0>=11, PREEMPS_EN=1, PREEMPS<2:0>=111 */
++#endif
++};
++
++#else /* for GM8210 */
++
++static pmuPcieReg_t regOTGArray[] = {
++	/* reg_off,bit_masks,lock_bits,init_val,init_mask */
++#define H2X_APB_BITS (BIT9|BIT10|BIT11|BIT12|BIT13|BIT14|BIT15|BIT16)
++	/* AHBC(BIT10) and OTG0,1,2(BIT6,5,4) clock, 0:enable */
++	{0x30, BIT4|BIT5|BIT6|BIT10, 0, 0, BIT4|BIT5|BIT6|BIT10},
++	{0x34, H2X_APB_BITS, 0, 0, H2X_APB_BITS},
++	/*
++	 * ============== 0x84 is OTG_PHY_CTRL ==============
++	 * init_val = 0x260B3D9E means as follows
++	 * OTG0: |=BIT1|BIT2|BIT3|BIT4|BIT8;&= ~BIT27&~BIT0;
++	 * OTG1: |=BIT10|BIT11|BIT12|BIT13|BIT17;&= ~BIT28&~BIT9;
++	 * OTG2: &= ~BIT18;|= BIT19;
++	 */
++	{0x84, 0xffffffff, 0xffffffff, 0x260B3D9E, 0xffffffff},
++};
++#endif /* else */
++
++#if !defined(CONFIG_PLATFORM_GM8210)
++static pmuRegInfo_t usb_clk_info = {
++	"usb_clk",
++	ARRAY_SIZE(regUSBArray),
++	ATTR_TYPE_NONE,             /* no clock source */
++	regUSBArray
++};
++#else
++static pmuPcieRegInfo_t usb_clk_info = {
++	"usb_clk",
++	ARRAY_SIZE(regOTGArray),
++	ATTR_TYPE_PCIE_NONE,             /* no clock source */
++	regOTGArray
++};
++#endif
++
++
++
++#define hcd_to_ehci(hcd) ((struct ehci_hcd *)(hcd->hcd_priv))
++
++#define a_host_to_b_device(x) { \
++	mwOTG20_stop_host(x); \
++	mdwOTGC_Control_A_BUS_REQ_Clr(x); \
++	mdwOTGC_Control_A_BUS_DROP_Set(x); \
++	mdwPort(x,0x130) &= ~(BIT0|BIT1|BIT2); \
++	mUsbGlobIntEnSet(x); \
++	mUsbUnPLGClr(x); \
++}
++
++#define b_device_to_a_host(x) { \
++	mUsbUnPLGSet(x); \
++	mUsbGlobIntDis(x); \
++	mdwPort(x,0x130) |= (BIT0|BIT1|BIT2); \
++	mdwOTGC_Control_A_BUS_DROP_Clr(x) ; \
++	mdwOTGC_Control_A_BUS_REQ_Set(x); \
++	mwOTG20_start_host(x); \
++}
++
++#define QUEUE_LEN 64
++
++u32 fotg2xx_wCurrentInterruptMask;
++static int last_fotg2xx_id;
++static int last_fotg2xx_role;
++static u32 queue[QUEUE_LEN];
++static u32 queue_in = 0;
++static u32 queue_out = 0;
++
++struct fotg2xx_priv {
++	struct otg_transceiver otg_ctrl;
++	struct work_struct otg_work;
++};
++static struct fotg2xx_priv fotg2xx_data[FOTG_DEV_NR];
++
++u32 get_fotg2xx_va(int num)
++{
++	struct usb_hcd *hcd;
++
++	if (num >= FOTG_DEV_NR)
++		panic("No such FOTG2XX device");
++
++	hcd = bus_to_hcd(fotg2xx_data[num].otg_ctrl.host);
++
++	return (u32)hcd->regs;
++}
++EXPORT_SYMBOL(get_fotg2xx_va);
++
++u32 get_fotg2xx_irq(int num)
++{
++	struct usb_hcd *hcd;
++
++	if (num >= FOTG_DEV_NR)
++		panic("No such FOTG2XX device");
++
++	hcd = bus_to_hcd(fotg2xx_data[num].otg_ctrl.host);
++
++	return hcd->irq;
++}
++EXPORT_SYMBOL(get_fotg2xx_irq);
++
++void fotg200_handle_irq(int irq)
++{
++	u32 wINTStatus;
++	u32 temp;
++	struct usb_hcd *hcd;
++	int i;
++
++	for (i = 0;i < FOTG_DEV_NR;i++) {
++		hcd = bus_to_hcd(fotg2xx_data[i].otg_ctrl.host);
++        if (hcd) {
++            if (hcd->irq == irq)
++                break;
++        } else {
++            panic("%s: No such hcd exists!\n", __func__);
++            return;
++        }
++	}
++
++	wINTStatus = mdwOTGC_INT_STS_Rd(hcd->regs);
++	mdwOTGC_INT_STS_Clr(hcd->regs,OTGC_INT_IDCHG);
++	mdwOTGC_INT_STS_Clr(hcd->regs,wINTStatus);
++	if (wINTStatus) {  // something happen
++		queue[queue_in] = wINTStatus;
++		if (queue_out != queue_in) {
++			// more than one work in the queue, we only do the last one by setting work as "0"
++			temp = queue_out;
++			while (temp != queue_in) {
++				queue[temp] = 0;
++				temp = (temp + 1) % QUEUE_LEN;
++			}
++			queue_out = queue_in;
++		}
++		queue_in = (queue_in + 1) % QUEUE_LEN;
++		schedule_work(&(fotg2xx_data[i].otg_work));
++	}
++}
++EXPORT_SYMBOL_GPL(fotg200_handle_irq);
++
++void OTG_handler(struct work_struct *data)
++{
++	u32 wINTStatus;
++	u32 current_id;
++	unsigned long  flags;
++	u32 temp;
++	struct fotg2xx_priv *priv = container_of(data, struct fotg2xx_priv, otg_work);
++	struct usb_hcd *hcd = bus_to_hcd(priv->otg_ctrl.host);
++
++	if (queue[queue_out] == 0) {  // happen for multiple work
++		printk(" empty OTG work queue %x\n", queue_out);
++		//queue_out = (queue_out + 1) % QUEUE_LEN;
++		return;
++	}
++
++	// in case host mode with connected device
++	// we need to wait host HCD has finished job
++	msleep(20);
++
++	// for HCD recover unfinished URB, we need more time
++	temp = mdwPort(hcd->regs,0x10);
++	while (temp & 0x20) {   // host async still enable
++		msleep(100);
++		temp = mdwPort(hcd->regs,0x10);
++	}
++
++	local_irq_save(flags);
++
++	//printk("+++++++++ %x:%x\n",queue_out,queue[queue_out]);
++	wINTStatus = queue[queue_out];
++	queue_out = (queue_out + 1 ) % QUEUE_LEN;
++	current_id = mdwOTGC_Control_ID_Rd(hcd->regs);
++
++	/* Change ID */
++	if ( (wINTStatus & OTGC_INT_IDCHG) && (last_fotg2xx_id != current_id) ){
++		if ( current_id == OTG_ID_A_TYPE){
++			printk("%s: FOTG2XX is now in Mini-A type %x\n", __func__, 0);
++			last_fotg2xx_id = OTG_ID_A_TYPE;
++			if (mdwOTGC_Control_CROLE_Rd(hcd->regs) == OTG_ROLE_HOST){
++				b_device_to_a_host(hcd->regs);
++				hcd->driver->reset(hcd);  // add for 2.6.21
++				hcd->driver->start(hcd);
++			}
++		} else {
++			printk("%s: FOTG2XX is now in Mini-B type %x\n", __func__, 0);
++			last_fotg2xx_id = OTG_ID_B_TYPE;
++			if (mdwOTGC_Control_CROLE_Rd(hcd->regs) == OTG_ROLE_DEVICE){
++				hcd->driver->stop(hcd);
++                printk("%s: do ID change\n", __func__);
++				a_host_to_b_device(hcd->regs);
++			}
++		}
++		mdwOTGC_INT_STS_Clr(hcd->regs,OTGC_INT_IDCHG);
++	}
++
++	/* Enable Device's HNP */
++	if (priv->otg_ctrl.host->b_hnp_enable == 1 &&  !mdwOTGC_Control_A_SET_B_HNP_EN_Rd(hcd->regs)){
++		//fotg2xx_dbg("fotg200_irq: enable HNP %x\n",0);
++		printk("%s : enable HNP\n", __func__);
++		mdwOTGC_Control_A_SET_B_HNP_EN_Set(hcd->regs);
++	}
++
++	/* Role Change */
++	if (wINTStatus & OTGC_INT_RLCHG) {
++		if ( (mdwOTGC_Control_ID_Rd(hcd->regs) == OTG_ID_A_TYPE)) {
++			printk(" ID-A OTG Role change... %x\n",wINTStatus);
++			if (mdwOTGC_Control_CROLE_Rd(hcd->regs) == OTG_ROLE_HOST){
++				mUsbUnPLGSet(hcd->regs);
++				mUsbGlobIntDis(hcd->regs);
++				mdwPort(hcd->regs,0x130) |= (BIT0|BIT1|BIT2);
++				mwOTG20_start_host(hcd->regs);
++				priv->otg_ctrl.state = OTG_STATE_A_HOST;
++				printk("enter host mode....\n");
++			}
++			else {
++				mwOTG20_stop_host(hcd->regs);
++				mdwOTGC_Control_A_SET_B_HNP_EN_Clr(hcd->regs);
++				mdwPort(hcd->regs,0x130) &= ~(BIT0|BIT1|BIT2);
++				mUsbGlobIntEnSet(hcd->regs);
++				mUsbUnPLGClr(hcd->regs);
++				priv->otg_ctrl.state = OTG_STATE_A_PERIPHERAL;
++				printk("enter device mode....\n");
++			}
++		}
++		else {   // OTG_ID_D_B_TYPE
++			printk(" ID-B OTG Role change... %x\n",wINTStatus);
++			if (mdwOTGC_Control_CROLE_Rd(hcd->regs) == OTG_ROLE_HOST){
++				hcd->state = HC_STATE_RUNNING;
++
++				priv->otg_ctrl.host->is_b_host = 1;
++				mUsbGlobIntDis(hcd->regs);
++				mdwPort(hcd->regs,0x130) |= (BIT0|BIT1|BIT2);
++				mwOTG20_start_host(hcd->regs);
++				mdwOTGC_Control_B_HNP_EN_Clr(hcd->regs);
++				priv->otg_ctrl.state = OTG_STATE_B_HOST;
++				printk("enter host mode....\n");
++			}
++			else {
++				//hcd->driver->stop(hcd);
++				//for(cnt=0;cnt<5000;cnt++) udelay(10);
++				priv->otg_ctrl.host->is_b_host = 0;
++				//mwOTG20_stop_host(hcd->regs);
++				mdwPort(hcd->regs,0x130) &= ~(BIT0|BIT1|BIT2);
++				mUsbGlobIntEnSet(hcd->regs);
++				mUsbUnPLGClr(hcd->regs);
++				priv->otg_ctrl.state = OTG_STATE_B_PERIPHERAL;
++
++				//fotg2xx_show_hc_regs();
++				//fotg2xx_show_otg_regs();
++				printk("enter device mode....\n");
++#ifndef CONFIG_USB_GADGET
++				// John add for in case gadget driver not enabled while using OTG
++				// controller will generate interrupt for suspend, we just to ignore it !!
++				printk("WARNING: Your OTG controller don't know how to act as USB device\n");
++				printk("         Please enable gadget function\n");
++				mdwPort(hcd->regs,0x134) = 0xFFFFFFFF;
++				mdwPort(hcd->regs,0x138) = 0xFFFFFFFF;
++				mdwPort(hcd->regs,0x13C) = 0xFFFFFFFF;
++				mUsbUnPLGSet(hcd->regs);
++#endif
++			}
++		}
++	}
++
++	//<1>.Checking the OTG layer interrupt status
++	if (wINTStatus>0) {
++		if (wINTStatus & OTGC_INT_AVBUSERR)
++			printk("Error --- Interrupt OTGC_INT_AVBUSERR=1... \n");
++		if (wINTStatus & OTGC_INT_OVC)
++			printk("Error --- Attached Device Not Supported: Over Current\n");
++
++		mdwOTGC_INT_STS_Clr(hcd->regs,wINTStatus);
++		if ((fotg2xx_wCurrentInterruptMask & wINTStatus)>0) {
++			printk("%s: re-drive Vbus...\n", __func__);
++			mdwOTGC_Control_A_BUS_REQ_Clr(hcd->regs);
++			mdwOTGC_Control_A_BUS_DROP_Set(hcd->regs);
++			mdwOTGC_Control_A_BUS_DROP_Clr(hcd->regs);
++			mdwOTGC_Control_A_BUS_REQ_Set(hcd->regs);
++		}
++
++		mdwOTGC_INT_STS_Clr(hcd->regs,wINTStatus);
++		//wFOTGPeri_Port(0xC0)|=BIT1;
++	}
++	local_irq_restore(flags);
++	return;
++}
++
++int fotg200_otgd_init(struct platform_device *pdev, struct usb_bus *host, struct usb_gadget *gadget)
++{
++	fotg2xx_data[pdev->id].otg_ctrl.dev = &pdev->dev;
++	fotg2xx_data[pdev->id].otg_ctrl.host = host;
++	fotg2xx_data[pdev->id].otg_ctrl.gadget = gadget;
++
++	printk("FOTG2XX Controller Initialization\n");
++
++	return 0;
++}
++EXPORT_SYMBOL(fotg200_otgd_init);
++
++//=============================================================================
++// OTGC_Init()
++// Description:1.Init the OTG Structure Variable
++//             2.Init the Interrupt register(OTG-Controller layer)
++//             3.Call the OTG_RoleChange function to init the Host/Peripheral
++// input: none
++// output: none
++//=============================================================================
++static void OTGC_Init(struct usb_bus *host)
++{
++	u32 dwTemp;
++	struct usb_hcd *hcd = bus_to_hcd(host);
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++#endif
++
++	//Clear the interrupt status
++	dwTemp=mdwOTGC_INT_STS_Rd(hcd->regs);
++	mdwOTGC_INT_STS_Clr(hcd->regs,dwTemp);
++
++#if defined(CONFIG_PLATFORM_GM8126)
++	ftpmu010_write_reg(usb_pmu_fd, 0xA0, 0, BIT3); //Set to Host Mode
++#elif defined(CONFIG_PLATFORM_GM8210)
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id == FMEM_CPU_FA726 && pci_id == FMEM_PCI_HOST) {
++        switch (hcd->irq) {
++            case USB_FOTG2XX_0_IRQ:
++                /* Configure OTG0 in host mode */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, 0, BIT0);
++                break;
++            case USB_FOTG2XX_1_IRQ:
++                /* Configure OTG1 in host mode */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, 0, BIT9);
++                break;
++            case USB_FOTG2XX_2_IRQ:
++                /* Configure OTG2 in host mode */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, 0, BIT18);
++                break;
++            default:
++                panic("Error OTG IRQ: %d\n", hcd->irq);
++                break;
++        }
++    }
++#elif defined(CONFIG_PLATFORM_GM8287)
++	switch (hcd->irq) {
++		case USB_FOTG2XX_0_IRQ:
++			/* Configure OTG0 in host mode */
++			ftpmu010_write_reg(usb_pmu_fd, 0xC0, 0, BIT2);
++			break;
++		case USB_FOTG2XX_1_IRQ:
++			/* Configure OTG1 in host mode */
++			ftpmu010_write_reg(usb_pmu_fd, 0xC8, 0, BIT2);
++			break;
++		default:
++			panic("Error OTG IRQ: %d\n", hcd->irq);
++			break;
++	}
++#elif defined(CONFIG_PLATFORM_GM8139)
++	ftpmu010_write_reg(usb_pmu_fd, 0xC0, 0, BIT2); //Set to Host Mode
++#elif defined(CONFIG_PLATFORM_GM8136)
++	ftpmu010_write_reg(usb_pmu_fd, 0xC0, 0, BIT2); //Set to Host Mode
++#endif
++
++	//<1>.Read the ID
++	if (mdwOTGC_Control_ID_Rd(hcd->regs) != OTG_ID_A_TYPE){
++		//Change to B Type
++		//<1.1>.Init Variable
++		/*OTG.A_bASRPDET=0;
++		  OTG.B_bBSRPDN=0;
++		  OTG.CurrentRole=USB_DEVICE_ROLE;*/
++		fotg2xx_wCurrentInterruptMask=OTGC_INT_B_TYPE;
++		//<1.2>.Init Interrupt
++		mdwOTGC_INT_Enable_Clr(hcd->regs,OTGC_INT_A_TYPE);
++		mdwOTGC_INT_Enable_Set(hcd->regs,OTGC_INT_B_TYPE);
++		//<1.3>.Init the Peripheral
++		// OTG_RoleChange(USB_DEVICE_ROLE,xceiver);
++		last_fotg2xx_id = OTG_ID_B_TYPE;
++		last_fotg2xx_role =  (OTG_ROLE_HOST | OTG_ROLE_DEVICE) +1;
++	}
++	else {
++		//Changfe to A Type
++		//<2.1>.Init Variable
++		/*OTG.A_bASRPDET=0;
++		  OTG.B_bBSRPDN=0;
++		  OTG.CurrentRole=USB_HOST_ROLE;*/
++		fotg2xx_wCurrentInterruptMask=OTGC_INT_A_TYPE;
++		//<2.2>. Init Interrupt
++		mdwOTGC_INT_Enable_Clr(hcd->regs,OTGC_INT_B_TYPE);
++		mdwOTGC_INT_Enable_Set(hcd->regs,OTGC_INT_A_TYPE);
++		//<2.3>.Init the Host
++		// OTG_RoleChange(USB_HOST_ROLE,xceiver);
++		last_fotg2xx_id = OTG_ID_A_TYPE;
++		last_fotg2xx_role =  (OTG_ROLE_HOST | OTG_ROLE_DEVICE) +1;
++	}
++	//enable role change interrupt
++	*((volatile u32 *)(hcd->regs+0x88)) = 0x721;
++
++	printk(KERN_DEBUG"fotg200 int enable = %x\n", mdwFOTGPort(hcd->regs,0x08));
++}
++
++int fotg200_init(struct device *dev, struct usb_bus *host, struct usb_gadget *gadget)
++{
++	struct usb_hcd *hcd = bus_to_hcd(host);
++
++	queue_in =0;
++	queue_out=0;
++
++	//Disable Device's Group interrupt
++	mdwPort(hcd->regs,0x130) |= (BIT0|BIT1|BIT2);
++
++	//Set unplug to force device to detach to PC
++	mdwOTGC_UsbUnPLGSet(hcd->regs);
++
++#if defined(CONFIG_PLATFORM_GM8126)
++	//Set OTG200 interrupt to high active, ex. A320
++	mwOTG20_Interrupt_OutPut_High_Set(hcd->regs);
++#endif
++
++	//Init OTG module's global variables and registers
++	OTGC_Init(host);
++	//Turn off all OTG interrutp first. It will be turned on when do role change
++	mdwOTGC_INT_Enable_Clr(hcd->regs,0xFFFFFFFF);
++	//OTG.wCurrentInterruptMask = 0x00000000;
++	fotg2xx_wCurrentInterruptMask = OTGC_INT_AVBUSERR|OTGC_INT_OVC;
++	mdwOTGC_INT_Enable_Set(hcd->regs,OTGC_INT_IDCHG | OTGC_INT_AVBUSERR | OTGC_INT_OVC);
++	return 0;
++}
++EXPORT_SYMBOL(fotg200_init);
++
++void ehci_reset_otg_PHY(struct usb_bus *host)
++{
++#ifndef REMOVE_COVERHW
++	struct usb_hcd *hcd = bus_to_hcd(host);
++	//Reset OTG PHY
++	mdwOTGC_Control_PHY_Reset_Set(hcd->regs);
++	udelay(1000);//1000 About 0.2ms
++	mdwOTGC_Control_PHY_Reset_Clr(hcd->regs);
++	printk("Reset Phy %x\n",0);
++#endif
++}
++
++void ehci_reset_OTG(struct usb_bus *host)
++{
++#ifndef REMOVE_COVERHW
++	struct usb_hcd *hcd = bus_to_hcd(host);
++	//Reset OTG controller
++	mdwOTGC_Control_OTG_Reset_Set(hcd->regs);
++	mdwOTGC_Control_OTG_Reset_Clr(hcd->regs);
++#endif
++}
++
++/* Setup FOTG2XX Registers  */
++void init_FOTG2XX_Dev(struct usb_hcd *hcd)
++{
++#if defined(CONFIG_PLATFORM_GM8126)
++	ftpmu010_write_reg(usb_pmu_fd, 0xA0, 0, (BIT0|BIT1|BIT2)<<17);
++	ftpmu010_write_reg(usb_pmu_fd, 0xA0, BIT1<<17, BIT1<<17);       // config reference voltage to 120mV
++	ftpmu010_write_reg(usb_pmu_fd, 0xA0, BIT0, BIT0);               // enable VBUS input
++	ftpmu010_write_reg(usb_pmu_fd, 0xA0, 0, BIT3);                  // set to host mode
++	ftpmu010_write_reg(usb_pmu_fd, 0x38, 0, BIT16);                 // turn on OTG clock
++	ftpmu010_write_reg(usb_pmu_fd, 0xA0, BIT8, BIT8);               // select clock source, 0:12 MHz, 1:30 MHz
++	ftpmu010_write_reg(usb_pmu_fd, 0xA0, BIT9|BIT11, BIT9|BIT11);   // bit9 & bit11 must all be one
++#elif defined(CONFIG_PLATFORM_GM8210)
++	/* Turn on AHBC clock */
++	//ftpmu010_pcie_write_reg(usb_pmu_fd, 0x30, 0, BIT10);
++
++	/* Turn on H2X_APB clock */
++	//ftpmu010_pcie_write_reg(usb_pmu_fd, 0x34, 0, H2X_APB_BITS);
++
++    /* H2X setting:
++	 * bit[6:4] = 0 (read command's pre-fetch number)
++	 * bit[3:2] = 1 (continuous incremental write burst)
++     */
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id == FMEM_CPU_FA726 && pci_id == FMEM_PCI_HOST) {
++        switch (hcd->rsrc_start) {
++            case USB_FOTG2XX_0_PA_BASE:
++                /* Set OTG0 H2X register */
++                writel(readl(h2x0_va_base) & ~BIT3, h2x0_va_base);
++                writel(readl(h2x0_va_base) | BIT2, h2x0_va_base);
++                //======= OTG0 Part======
++                /* BIT2:pllaliv; BIT3:oscouten; BIT8:0=external clock, 1=internal clock */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, BIT2|BIT3|BIT8, BIT2|BIT3|BIT8);
++                /* OTG0 PHY coreclkin. 0: on, 1:off */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, 0, BIT27);
++                /* Disable OTG0 phy POR */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, BIT4, BIT4);
++                /* Configure OTG0 in host mode */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, 0, BIT0);
++                /* Enable OTG0 VBUS input */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, BIT1, BIT1);
++                /* Turn on OTG0 clock */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x30, 0, BIT6);
++                break;
++            case USB_FOTG2XX_1_PA_BASE:
++                /* Set OTG1 H2X register */
++                writel(readl(h2x1_va_base) & ~BIT3, h2x1_va_base);
++                writel(readl(h2x1_va_base) | BIT2, h2x1_va_base);
++                //======= OTG1 Part======
++                /* BIT11:pllaliv; BIT12:oscouten; BIT17:0=external clock, 1=internal clock */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, BIT11|BIT12|BIT17, BIT11|BIT12|BIT17);
++                /* OTG1 PHY coreclkin. 0: on, 1:off */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, 0, BIT28);
++                /* Disable OTG1 phy POR */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, BIT13, BIT13);
++                /* Configure OTG1 in host mode */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, 0, BIT9);
++                /* Enable OTG1 VBUS input */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, BIT10, BIT10);
++                /* Turn on OTG1 clock */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x30, 0, BIT5);
++                break;
++            case USB_FOTG2XX_2_PA_BASE:
++                /* Set OTG2 H2X register */
++                writel(readl(h2x2_va_base) & ~BIT3, h2x2_va_base);
++                writel(readl(h2x2_va_base) | BIT2, h2x2_va_base);
++                //======= OTG2(PHY 1.1) Part======
++                /* Configure OTG2 in host mode */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, 0, BIT18);
++                /* Enable OTG2 VBUS input */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x84, BIT19, BIT19);
++                /* Turn on OTG2 clock */
++                ftpmu010_pcie_write_reg(usb_pmu_fd, 0x30, 0, BIT4);
++                /* force to full-speed */
++                mwOTG20_Control_ForceFullSpeed_Set(hcd->regs);
++                break;
++            default:
++                panic("Error OTG Base: 0x%x\n", (u32)hcd->rsrc_start);
++                break;
++        }
++    }
++#elif defined(CONFIG_PLATFORM_GM8287)
++    switch (hcd->rsrc_start) {
++        case USB_FOTG2XX_0_PA_BASE:
++            ftpmu010_write_reg(usb_pmu_fd, 0xC0, BIT4 | BIT5 | BIT19, BIT4 | BIT5 | BIT19);
++            ftpmu010_write_reg(usb_pmu_fd, 0xC0, 0, BIT0); /* OTG0 PHY clock */
++            ftpmu010_write_reg(usb_pmu_fd, 0xC0, BIT6, BIT6);
++            ftpmu010_write_reg(usb_pmu_fd, 0xC0, BIT3, BIT3);
++            ftpmu010_write_reg(usb_pmu_fd, 0xC0, 0, BIT2);
++            ftpmu010_write_reg(usb_pmu_fd, 0xC0, 0, BIT1); /* OTG0 hclk on */
++            break;
++        case USB_FOTG2XX_1_PA_BASE:
++            ftpmu010_write_reg(usb_pmu_fd, 0xC8, BIT4 | BIT5 | BIT19, BIT4 | BIT5 | BIT19);
++            ftpmu010_write_reg(usb_pmu_fd, 0xC8, 0, BIT0); /* OTG1 PHY clock */
++            ftpmu010_write_reg(usb_pmu_fd, 0xC8, BIT6, BIT6);
++            ftpmu010_write_reg(usb_pmu_fd, 0xC8, BIT3, BIT3);
++            ftpmu010_write_reg(usb_pmu_fd, 0xC8, 0, BIT2);
++            ftpmu010_write_reg(usb_pmu_fd, 0xC8, 0, BIT1); /* OTG1 hclk on */
++            break;
++        default:
++            panic("Error OTG Base: 0x%x\n", (u32)hcd->rsrc_start);
++            break;
++    }
++#elif defined(CONFIG_PLATFORM_GM8136)
++    switch (hcd->rsrc_start) {
++        case USB_FOTG2XX_0_PA_BASE:
++            {
++                /*
++                 * set the parameter of USB PHY, depends on package
++                 */
++                uint pkg_id, val;
++
++                pkg_id = (ftpmu010_read_reg(0x00) >> 2) & 0x1F;
++                switch (pkg_id) {
++                    case 0x04:
++                    case 0x10:
++                    case 0x14:
++                        val = BIT24 | BIT25; // LQFP
++                        break;
++                    default:
++                        val = BIT24 | BIT25 | BIT26 | BIT27; // BGA
++                        break;
++                }
++                ftpmu010_write_reg(usb_pmu_fd, 0xC0, val, BIT24 | BIT25 | BIT26 | BIT27);
++            }
++            break;
++    }
++#endif
++
++	mdelay(10); // waiting for PHY clock be stable, while clock source changed from externel to internel, at lease 5ms
++	mwOTG20Bit_Set(hcd->regs,0x40,BIT6); // put PHY into suspend mode
++	mdelay(10);
++	mwOTG20Bit_Clr(hcd->regs,0x40,BIT6);
++	mdelay(10);
++
++#ifdef CONFIG_OTG
++	//Host controller with OTG fucntion ==> Turn on Vbus
++	//Disable OTG interrupt
++    mdwFOTGPort(hcd->regs,0x08) &= 0xffffff00;
++
++	//Drive Vbus for FOTG100 (Default device A role)]
++	if ( mdwOTGC_Control_ID_Rd(hcd->regs) == OTG_ID_A_TYPE ) {
++		u32 temp;
++		udelay(1000);
++		printk("Enter Device A\n");
++		temp = mdwOTGC_INT_STS_Rd(hcd->regs);
++		mdwOTGC_INT_STS_Clr(hcd->regs,temp);
++		mdwOTGC_Control_A_BUS_DROP_Set(hcd->regs);
++		mdwOTGC_Control_A_BUS_REQ_Clr(hcd->regs);
++		udelay(1000);
++		printk("Drive Vbus because of ID pin shows Device A\n");
++		mdwOTGC_Control_A_BUS_DROP_Clr(hcd->regs);
++		mdwOTGC_Control_A_BUS_REQ_Set(hcd->regs);
++		udelay(1000);
++	}
++#endif
++
++#ifdef CONFIG_711MA_PHY
++	//Set cover bit to cover 711MA PHY full speed reset issue
++	mwOTG20_Control_COVER_FS_PHY_Reset_Set(hcd->regs);
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8126)
++	//Set OTG200 interrupt to high active, ex. A320
++	mwOTG20_Interrupt_OutPut_High_Set(hcd->regs);
++#endif
++
++	//Basic initialization for FPFA version IP
++	mwPeri20_Control_ChipEnable_Set(hcd->regs);
++
++	//Important: If AHB clock is >=15Mhz and <= 30MHz, please remark this line (Enable half speed)).
++	//IF > 30Hz, Disable half speed
++#ifdef EnableHalfSpeed
++	mwPeri20_Control_HALFSPEEDEnable_Set(hcd->regs);
++#else /* EnableHalfSpeed */
++	mwPeri20_Control_HALFSPEEDEnable_Clr(hcd->regs);
++#endif /* EnableHalfSpeed */
++
++#if 0
++	mwOTG20_Control_ForceHighSpeed_Clr(hcd->regs);
++	mwOTG20_Control_ForceFullSpeed_Clr(hcd->regs);
++#endif
++
++#if 0 // debug for force otg phy speed
++	mwOTG20_Control_ForceFullSpeed_Set(hcd->regs); // force to full-speed (do not ack to device's KJ pattern)
++	//mwOTG20_Control_ForceHighSpeed_Set(hcd->regs); // force to high-speed
++	if (mwOTG20Bit_Rd(hcd->regs,0x80,BIT12))
++		printk("!!!! Force Phy to Full-Speed !!!!\n");
++	else if (mwOTG20Bit_Rd(hcd->regs,0x80,BIT14))
++		printk("!!!! Force Phy to High-Speed !!!!\n");
++#endif
++}
++EXPORT_SYMBOL(init_FOTG2XX_Dev);
++
++void exit_FOTG2XX_Dev(struct usb_hcd *hcd)
++{
++#if defined(CONFIG_PLATFORM_GM8126)
++	ftpmu010_write_reg(usb_pmu_fd, 0x38, BIT16, BIT16);
++#elif defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id == FMEM_CPU_FA726 && pci_id == FMEM_PCI_HOST) {
++        ftpmu010_pcie_write_reg(usb_pmu_fd, 0x30, 1, BIT6); /* Turn off OTG0 clock */
++        ftpmu010_pcie_write_reg(usb_pmu_fd, 0x30, 1, BIT5); /* Turn off OTG1 clock */
++        ftpmu010_pcie_write_reg(usb_pmu_fd, 0x30, 1, BIT4); /* Turn off OTG2 clock */
++    }
++#elif defined(CONFIG_PLATFORM_GM8287)
++	ftpmu010_write_reg(usb_pmu_fd, 0xC0, BIT0, BIT0); /* OTG0 PHY clock */
++	ftpmu010_write_reg(usb_pmu_fd, 0xC0, BIT1, BIT1); /* OTG0 controller clock */
++	ftpmu010_write_reg(usb_pmu_fd, 0xC8, BIT0, BIT0); /* OTG1 PHY clock */
++	ftpmu010_write_reg(usb_pmu_fd, 0xC8, BIT1, BIT1); /* OTG1 controller clock */
++#elif defined(CONFIG_PLATFORM_GM8139)
++	ftpmu010_write_reg(usb_pmu_fd, 0xAC, BIT0, BIT0); /* OTG PHY clock */
++	ftpmu010_write_reg(usb_pmu_fd, 0xB4, BIT9, BIT9); /* OTG controller clock */
++#elif defined(CONFIG_PLATFORM_GM8136)
++    ftpmu010_write_reg(usb_pmu_fd, 0xAC, BIT0, BIT0); /* OTG PHY clock */
++    ftpmu010_write_reg(usb_pmu_fd, 0xB4, BIT9, BIT9); /* OTG controller clock */
++#endif
++}
++EXPORT_SYMBOL(exit_FOTG2XX_Dev);
++
++static int __init ftusb_init(void)
++{
++	int i, ret = 0;
++
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id == FMEM_CPU_FA726 && pci_id == FMEM_PCI_HOST) {
++        /* Map H2X */
++        h2x0_va_base = ioremap(H2X0_FOTG2XX_PA_BASE, H2X0_FOTG2XX_PA_SIZE);
++        h2x1_va_base = ioremap(H2X1_FOTG2XX_PA_BASE, H2X1_FOTG2XX_PA_SIZE);
++        h2x2_va_base = ioremap(H2X2_FOTG2XX_PA_BASE, H2X2_FOTG2XX_PA_SIZE);
++    }
++#endif
++
++	for (i = 0;i < FOTG_DEV_NR;i++) {
++		memset(&fotg2xx_data[i], 0, sizeof(fotg2xx_data[i]));
++		INIT_WORK(&fotg2xx_data[i].otg_work, OTG_handler);
++	}
++#if defined(CONFIG_PLATFORM_GM8126) || defined(CONFIG_PLATFORM_GM8287) || defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++	if ((usb_pmu_fd = ftpmu010_register_reg(&usb_clk_info)) < 0) {
++		ret = -1;
++		printk(KERN_ERR "%s: Register USB to PMU failed\n", __func__);
++	}
++#endif
++#if defined(CONFIG_PLATFORM_GM8210)
++    if (cpu_id == FMEM_CPU_FA726 && pci_id == FMEM_PCI_HOST) {
++        if ((usb_pmu_fd = ftpmu010_pcie_register_reg(&usb_clk_info)) < 0) {
++            ret = -1;
++            printk(KERN_ERR "%s: Register USB to PMU failed\n", __func__);
++        }
++    }
++#endif
++	return ret;
++}
++static void __exit ftusb_exit(void)
++{
++#if defined(CONFIG_PLATFORM_GM8126) || defined(CONFIG_PLATFORM_GM8287) || defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++	if (ftpmu010_deregister_reg(usb_pmu_fd) < 0)
++		printk(KERN_ERR "%s: Unregister USB from PMU Failed\n", __func__);
++#endif
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id == FMEM_CPU_FA726 && pci_id == FMEM_PCI_HOST) {
++        iounmap(h2x0_va_base);
++        iounmap(h2x1_va_base);
++        iounmap(h2x2_va_base);
++        if (ftpmu010_pcie_deregister_reg(usb_pmu_fd) < 0)
++            printk(KERN_ERR "%s: Unregister USB from PMU Failed\n", __func__);
++    }
++#endif
++}
++module_init(ftusb_init);
++module_exit(ftusb_exit);
++
++MODULE_AUTHOR("<GM-tech.com>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("OTG change mode driver");
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 6ca0c407..1239c6f0 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -99,7 +99,7 @@ config FB_BOOT_VESA_SUPPORT
+ 	  of VESA video modes set at an early boot stage via the vga= parameter.
+ 
+ config FB_CFB_FILLRECT
+-	tristate
++	tristate "FB_CFB_FILLRECT"
+ 	depends on FB
+ 	default n
+ 	---help---
+@@ -108,7 +108,7 @@ config FB_CFB_FILLRECT
+ 	  (accelerated) version.
+ 
+ config FB_CFB_COPYAREA
+-	tristate
++	tristate "FB_CFB_COPYAREA"
+ 	depends on FB
+ 	default n
+ 	---help---
+@@ -117,7 +117,7 @@ config FB_CFB_COPYAREA
+ 	  version.
+ 
+ config FB_CFB_IMAGEBLIT
+-	tristate
++	tristate "FB_CFB_IMAGEBLIT"
+ 	depends on FB
+ 	default n
+ 	---help---
+diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
+index df9e8f0e..b558cf17 100644
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -82,6 +82,13 @@ config WM8350_WATCHDOG
+ 
+ # ARM Architecture
+ 
++config FTWDT010_WATCHDOG
++	tristate "FTWDT010 watchdog"
++	depends on ARCH_GM || ARCH_GM_DUO || ARCH_GM_SMP
++	help
++	  Watchdog timer embedded into Grain Media chips. This will reboot your
++	  system when the timeout is reached.
++
+ config ARM_SP805_WATCHDOG
+ 	tristate "ARM SP805 Watchdog"
+ 	depends on ARM_AMBA
+diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
+index e8f479a1..624c1290 100644
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -29,6 +29,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
+ # ALPHA Architecture
+ 
+ # ARM Architecture
++obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o
+ obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
+ obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
+ obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
+diff --git a/drivers/watchdog/ftwdt010_wdt.c b/drivers/watchdog/ftwdt010_wdt.c
+new file mode 100644
+index 00000000..0f77e363
+--- /dev/null
++++ b/drivers/watchdog/ftwdt010_wdt.c
+@@ -0,0 +1,302 @@
++/*
++ *	Watchdog driver for the FTWDT010 Watch Dog Driver
++ *
++ *      (c) Copyright 2004 GM Technology Corp. (www.grain-media.com)
++ *	    Based on sa1100_wdt.c by Oleg Drokin <green@crimea.edu>
++ *          Based on SoftDog driver by Alan Cox <alan@redhat.com>
++ *
++ *	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.
++ *
++ *      27/11/2004 Initial release
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/device.h>
++#include <linux/synclink.h>
++#include <mach/ftpmu010.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#if defined(CONFIG_PLATFORM_GM8210)
++#include <mach/fmem.h>
++#endif
++
++#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136)
++#define SYSCLK  30000000
++#else
++#define SYSCLK  12000000
++#endif
++
++#define MAX_RESET_TIME (UINT_MAX / SYSCLK)
++#define DEFAULT_RESET_SECS	5
++
++#define WdCounter   0x0
++#define WdLoad		0x4
++#define WdRestart	0x8
++#define WdCR		0xC
++
++static int reset_secs = DEFAULT_RESET_SECS;
++static int nowayout = WATCHDOG_NOWAYOUT;
++static int watchdog_enable = 1;
++module_param(nowayout, int, 0);
++MODULE_PARM_DESC(nowayout,
++	"Watchdog cannot be stopped once started (default="
++		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
++
++static ssize_t ftwdt010dog_write(struct file *file, const char *data,
++				 size_t len, loff_t * ppos);
++static long ftwdt010dog_ioctl(struct file *file,
++			     unsigned int cmd, unsigned long arg);
++static int ftwdt010dog_open(struct inode *inode, struct file *file);
++static int ftwdt010dog_release(struct inode *inode, struct file *file);
++
++static struct file_operations ftwdt010dog_fops = {
++    owner:          THIS_MODULE,
++    write:          ftwdt010dog_write,
++    unlocked_ioctl: ftwdt010dog_ioctl,
++    open:           ftwdt010dog_open,
++    release:        ftwdt010dog_release,
++};
++
++static struct miscdevice ftwdt010dog_miscdev = {
++	WATCHDOG_MINOR,
++	"watchdog",
++	&ftwdt010dog_fops
++};
++
++static void reset_wdt(void __iomem * vbase, int alive_sec)
++{
++    u32 wdt_counter = 0;
++
++    if (!alive_sec || alive_sec > MAX_RESET_TIME) {
++        printk(KERN_WARNING "Warning! illegal watchdog reset time: %d!\n", alive_sec);
++        printk(KERN_WARNING "We force to set reset time to %d sec\n", DEFAULT_RESET_SECS);
++        alive_sec = DEFAULT_RESET_SECS; /* a buffer time for hw to count WDT timer */
++    }
++    wdt_counter = alive_sec * SYSCLK;
++
++    /*
++     * Watchdog program sequence (FTWDT010_DS_v1.5.pdf, by eason)
++     * 1. Disable the WatchDog timer
++     * 2. Set the WdLoad register
++     * 3. Write 0x5AB9 to the WdRestart register
++     * 4. Set the WdCR[Clock] bit (default: PCLK)
++     * 5. Enable the WatchDog timer
++     */
++	outb(inl(vbase + WdCR) & ~BIT0, vbase + WdCR);
++	outl(wdt_counter, vbase + WdLoad);
++	outl(0x5ab9, vbase + WdRestart);	/* Magic number */
++	outb(inl(vbase + WdCR) | BIT4, vbase + WdCR);
++	outb(inl(vbase + WdCR) | BIT0 | BIT1, vbase + WdCR);
++}
++
++/*
++ *	Allow only one person to hold it open
++ */
++
++static int ftwdt010dog_open(struct inode *inode, struct file *file)
++{
++	void __iomem *wdt_va_base = NULL;
++	int ret = 0;
++	/* Activate FTWDT010 Watchdog timer */
++	wdt_va_base = ioremap(WDT_FTWDT010_PA_BASE, WDT_FTWDT010_PA_SIZE);
++	printk(KERN_INFO "WDT base virtual address = %p\n", wdt_va_base);
++	if (!wdt_va_base) {
++		printk(KERN_INFO "Remap is failed\n");
++		return -EIO;
++	}
++	ret = dev_set_drvdata(ftwdt010dog_miscdev.this_device, (void *)wdt_va_base);
++	if (ret < 0)
++		printk(KERN_ERR"%s: Set wdt_va_base to drvdata error!\n", __func__);
++	reset_wdt(wdt_va_base, reset_secs);
++	return 0;
++}
++
++static int ftwdt010dog_release(struct inode *inode, struct file *file)
++{
++	void __iomem *wdt_va_base = dev_get_drvdata(ftwdt010dog_miscdev.this_device);
++	/*
++	 *      Shut off the timer.
++	 *      Lock it in if it's a module and we defined ...NOWAYOUT
++	 */
++	outl(0x5ab9, wdt_va_base + WdRestart);
++
++    if (nowayout != WATCHDOG_NOWAYOUT)
++        outb(0, wdt_va_base + WdCR);
++	return 0;
++}
++
++static ssize_t ftwdt010dog_write(struct file *file, const char *data,
++				 size_t len, loff_t * ppos)
++{
++	void __iomem *wdt_va_base = dev_get_drvdata(ftwdt010dog_miscdev.this_device);
++
++	if (len) {
++		outl(0x5ab9, wdt_va_base + WdRestart);
++		return 1;
++	}
++	return 0;
++}
++
++static long ftwdt010dog_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++{
++    void __user *argp = (void __user *)arg;
++    int __user *p = argp;
++	unsigned long count;
++    static struct watchdog_info ident = {
++identity:	"FTWDT010 Watchdog",
++    };
++	void __iomem *wdt_va_base = dev_get_drvdata(ftwdt010dog_miscdev.this_device);
++
++    switch (cmd) {
++        default:
++            return -ENOIOCTLCMD;
++
++        case WDIOC_GETSUPPORT:
++            return copy_to_user((struct watchdog_info *)arg, &ident,
++                    sizeof(ident));
++
++        case WDIOC_GETSTATUS:
++        case WDIOC_GETBOOTSTATUS:
++            return put_user(0, (int *)arg);
++
++        case WDIOC_SETOPTIONS:
++    	{
++    		int options;
++
++    		if (get_user(options, p))
++    			return -EFAULT;
++    		if (options & WDIOS_DISABLECARD) {
++    			outb(inl(wdt_va_base + WdCR) & ~BIT0, wdt_va_base + WdCR);
++                watchdog_enable = 0;
++                printk("%s, watchdog is disabled! \n", __func__);
++    			return 0;
++    		}
++    		if (options & WDIOS_ENABLECARD) {
++    			outb(inl(wdt_va_base + WdCR) | BIT0 | BIT1, wdt_va_base + WdCR);
++                watchdog_enable = 1;
++                reset_wdt(wdt_va_base + WdCounter, reset_secs);
++                printk("%s, watchdog is enabled! timeout: %ds\n", __func__, reset_secs);
++    			return 0;
++    		}
++    		printk("%s, invalid option value: 0x%x! \n", __func__, options);
++    		return -EINVAL;
++    	}
++
++        case WDIOC_SETTIMEOUT:
++            count =
++                copy_from_user(&reset_secs, (int *)arg, sizeof(int));
++            reset_wdt(wdt_va_base + WdCounter, reset_secs);
++            return 0;
++
++        case WDIOC_GETTIMEOUT:
++            return put_user(reset_secs, (int *)arg);
++
++        case WDIOC_KEEPALIVE:
++            if (watchdog_enable)
++                reset_wdt(wdt_va_base + WdCounter, reset_secs);
++            return 0;
++    }
++}
++
++/* PMU register data */
++static int wdt_fd = -1;
++static pmuReg_t regWDTArray[] = {
++/* reg_off  bit_masks  lock_bits     init_val    init_mask */
++#if defined(CONFIG_PLATFORM_GM8181)
++	{0x3C, BIT18, BIT18, 0, BIT18},
++#elif defined (CONFIG_PLATFORM_GM8126)
++	{0x3C, BIT15, BIT15, 0, BIT15},
++#elif defined (CONFIG_PLATFORM_GM8210) || defined (CONFIG_PLATFORM_GM8287)
++	{0xB8, BIT13, 0, 0, BIT13},
++#elif defined (CONFIG_PLATFORM_GM8139) || defined (CONFIG_PLATFORM_GM8136)
++	{0xB8, BIT10, 0, 0, BIT10},
++#endif
++};
++
++static pmuRegInfo_t wdt_clk_info = {
++	"wdt_clk",
++	ARRAY_SIZE(regWDTArray),
++	ATTR_TYPE_NONE,		/* no clock source */
++	regWDTArray
++};
++
++static int __init ftwdt010dog_init(void)
++{
++	int ret;
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id != FMEM_CPU_FA726 || pci_id != FMEM_PCI_HOST)
++        return 0;
++#endif
++
++	ret = misc_register(&ftwdt010dog_miscdev);
++
++	if (ret)
++		return ret;
++
++	wdt_fd = ftpmu010_register_reg(&wdt_clk_info);
++#if defined(CONFIG_PLATFORM_GM8181)
++	if (ftpmu010_del_lockbits(wdt_fd, 0x3C, BIT18) < 0) {
++		printk(KERN_ERR "%s: Unlock PMU offset 0x3C BIT18 failed\n",
++		       __func__);
++	}
++#elif defined (CONFIG_PLATFORM_GM8126)
++	if (ftpmu010_del_lockbits(wdt_fd, 0x3C, BIT15) < 0) {
++		printk(KERN_ERR "%s: Unlock PMU offset 0x3C BIT15 failed\n",
++		       __func__);
++	}
++#endif
++	if (unlikely(wdt_fd < 0)) {
++		printk(KERN_ERR "WDT registers to PMU fail! \n");
++		return wdt_fd;
++	}
++
++	return 0;
++}
++
++static void __exit ftwdt010dog_exit(void)
++{
++#if defined(CONFIG_PLATFORM_GM8210)
++    fmem_pci_id_t pci_id;
++    fmem_cpu_id_t cpu_id;
++    fmem_get_identifier(&pci_id, &cpu_id);
++    if (cpu_id != FMEM_CPU_FA726 || pci_id != FMEM_PCI_HOST)
++        return;
++#endif
++	/* disable WDT clk */
++#if defined(CONFIG_PLATFORM_GM8181)
++	if (ftpmu010_add_lockbits(wdt_fd, 0x3C, BIT18) < 0) {
++		printk(KERN_ERR
++		       "Add PMU register 0x3C lock_bit BIT18 Failed\n");
++	}
++	if (ftpmu010_write_reg(wdt_fd, 0x3C, BIT18, BIT18) < 0) {
++		printk(KERN_ERR "Write PMU register 0x3C Failed\n");
++	}
++#elif defined (CONFIG_PLATFORM_GM8126)
++	if (ftpmu010_add_lockbits(wdt_fd, 0x3C, BIT15) < 0) {
++		printk(KERN_ERR
++		       "Add PMU register 0x3C lock_bit BIT15 Failed\n");
++	}
++	if (ftpmu010_write_reg(wdt_fd, 0x3C, BIT15, BIT15) < 0) {
++		printk(KERN_ERR "Write PMU register 0x3C Failed\n");
++	}
++#endif
++	if (ftpmu010_deregister_reg(wdt_fd) < 0)
++		printk(KERN_ERR "Unregister WDT from PMU Failed\n");
++
++	misc_deregister(&ftwdt010dog_miscdev);
++}
++
++module_init(ftwdt010dog_init);
++module_exit(ftwdt010dog_exit);
++
++MODULE_AUTHOR("GM Corp.");
++MODULE_LICENSE("GPL");
+diff --git a/fs/Kconfig b/fs/Kconfig
+index d621f02a..847f2c15 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -7,7 +7,7 @@ menu "File systems"
+ if BLOCK
+ 
+ source "fs/ext2/Kconfig"
+-source "fs/ext3/Kconfig"
++#source "fs/ext3/Kconfig"
+ source "fs/ext4/Kconfig"
+ 
+ config FS_XIP
+diff --git a/fs/proc/array.c b/fs/proc/array.c
+index c602b8d2..aad5e78e 100644
+--- a/fs/proc/array.c
++++ b/fs/proc/array.c
+@@ -337,6 +337,42 @@ static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
+ 	seq_putc(m, '\n');
+ }
+ 
++#if defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP)
++#include <linux/kallsyms.h>
++void dump_regs(struct task_struct *task)
++{
++    char tcomm[20];
++    int cnt = 0;   //stack postion
++    unsigned int addr;
++    struct pt_regs *regs = task_pt_regs(task);
++    struct thread_info *thread = task_thread_info(task);
++
++    get_task_comm(tcomm, task);
++    
++    printk("\ntask [%s]\n", tcomm);
++    print_symbol("Kernel Mode PC is at (%s)\n", thread->cpu_context.pc);
++    printk("Kernel Mode Stack is 0x%x\n", (int)thread->cpu_context.sp);
++    
++    addr = thread->cpu_context.sp + 0xc0; //0xc8,0xd4,0xe0
++    for (cnt = 0; cnt < 8; cnt++) {
++        printk("  %08x: %08x %08x %08x %08x\n",  addr + (cnt * 4),
++            *(unsigned int *)(addr + (cnt * 4)), *(unsigned int *)(addr + (cnt * 4) + 4),
++            *(unsigned int *)(addr + (cnt * 4) + 8), *(unsigned int*)(addr + (cnt * 4) + 0xc));
++    }
++
++    printk("\nUser Mode PC is 0x%x\n", (int)instruction_pointer(regs));
++    printk("User Mode LR is 0x%x\n", (int)regs->ARM_lr);
++    printk("  pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\n"
++           "  sp : %08lx  ip : %08lx  fp : %08lx\n",
++            regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
++    printk("  r10: %08lx  r9 : %08lx  r8 : %08lx\n", regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
++    printk("  r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n", regs->ARM_r7, regs->ARM_r6,
++            regs->ARM_r5, regs->ARM_r4);
++    printk("  r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n", regs->ARM_r3, regs->ARM_r2,
++            regs->ARM_r1, regs->ARM_r0);
++}
++#endif
++
+ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
+ 			struct pid *pid, struct task_struct *task)
+ {
+@@ -354,6 +390,10 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
+ 	task_cpus_allowed(m, task);
+ 	cpuset_task_status_allowed(m, task);
+ 	task_context_switch_counts(m, task);
++
++#if defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP)
++    dump_regs(task);
++#endif
+ 	return 0;
+ }
+ 
+diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
+index 1ff4e221..097a2c64 100644
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -1,9 +1,10 @@
+-#ifndef _ASM_GENERIC_GPIO_H
+-#define _ASM_GENERIC_GPIO_H
++#ifndef _ASM_ARM_GPIO_H
++#define _ASM_ARM_GPIO_H
+ 
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/errno.h>
++#include <mach/platform/gpio.h>
+ #include <linux/of.h>
+ 
+ #ifdef CONFIG_GPIOLIB
+@@ -47,6 +48,20 @@ struct seq_file;
+ struct module;
+ struct device_node;
+ 
++struct gpio_interrupt_mode {
++	u8 trigger_method;
++#define GPIO_INT_TRIGGER_EDGE   0x01
++#define GPIO_INT_TRIGGER_LEVEL  0x02
++
++	u8 trigger_edge_nr;
++#define GPIO_INT_SINGLE_EDGE    0x01
++#define GPIO_INT_BOTH_EDGE      0x02
++
++	u8 trigger_rise_neg;
++#define GPIO_INT_RISE           0x01
++#define GPIO_INT_FALLING        0x02
++};
++
+ /**
+  * struct gpio_chip - abstract a GPIO controller
+  * @label: for diagnostics
+@@ -90,37 +105,30 @@ struct device_node;
+  * is calculated by subtracting @base from the gpio number.
+  */
+ struct gpio_chip {
+-	const char		*label;
+-	struct device		*dev;
+-	struct module		*owner;
+-
+-	int			(*request)(struct gpio_chip *chip,
+-						unsigned offset);
+-	void			(*free)(struct gpio_chip *chip,
+-						unsigned offset);
+-
+-	int			(*direction_input)(struct gpio_chip *chip,
+-						unsigned offset);
+-	int			(*get)(struct gpio_chip *chip,
+-						unsigned offset);
+-	int			(*direction_output)(struct gpio_chip *chip,
+-						unsigned offset, int value);
+-	int			(*set_debounce)(struct gpio_chip *chip,
+-						unsigned offset, unsigned debounce);
+-
+-	void			(*set)(struct gpio_chip *chip,
+-						unsigned offset, int value);
+-
+-	int			(*to_irq)(struct gpio_chip *chip,
+-						unsigned offset);
+-
+-	void			(*dbg_show)(struct seq_file *s,
+-						struct gpio_chip *chip);
+-	int			base;
+-	u16			ngpio;
+-	const char		*const *names;
+-	unsigned		can_sleep:1;
+-	unsigned		exported:1;
++	const char *label;
++	struct device *dev;
++	struct module *owner;
++
++	int (*request) (struct gpio_chip * chip, unsigned offset);
++	void (*free) (struct gpio_chip * chip, unsigned offset);
++
++	int (*direction_input) (struct gpio_chip * chip, unsigned offset);
++	int (*get) (struct gpio_chip * chip, unsigned offset);
++	int (*direction_output) (struct gpio_chip * chip,
++				 unsigned offset, int value);
++	int (*set_debounce) (struct gpio_chip * chip,
++			     unsigned offset, unsigned debounce);
++
++	void (*set) (struct gpio_chip * chip, unsigned offset, int value);
++
++	int (*to_irq) (struct gpio_chip * chip, unsigned offset);
++
++	void (*dbg_show) (struct seq_file * s, struct gpio_chip * chip);
++	int base;
++	u16 ngpio;
++	const char *const *names;
++	unsigned can_sleep:1;
++	unsigned exported:1;
+ 
+ #if defined(CONFIG_OF_GPIO)
+ 	/*
+@@ -129,13 +137,22 @@ struct gpio_chip {
+ 	 */
+ 	struct device_node *of_node;
+ 	int of_gpio_n_cells;
+-	int (*of_xlate)(struct gpio_chip *gc,
+-		        const struct of_phandle_args *gpiospec, u32 *flags);
++	int (*of_xlate) (struct gpio_chip * gc,
++			 const struct of_phandle_args * gpiospec, u32 * flags);
+ #endif
++
++	int (*int_clr) (struct gpio_chip * chip, unsigned offset);
++	int (*int_setup) (struct gpio_chip * chip, unsigned offset,
++			  const struct gpio_interrupt_mode * mode);
++	int (*int_enable) (struct gpio_chip * chip, unsigned offset);
++	int (*int_disable) (struct gpio_chip * chip, unsigned offset);
++	int (*int_check) (struct gpio_chip * chip, unsigned offset);
++	int (*int_mask) (struct gpio_chip * chip, unsigned offset);
++	int (*int_unmask) (struct gpio_chip * chip, unsigned offset);
+ };
+ 
+ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
+-			unsigned offset);
++					 unsigned offset);
+ extern struct gpio_chip *gpio_to_chip(unsigned gpio);
+ extern int __must_check gpiochip_reserve(int start, int ngpio);
+ 
+@@ -143,10 +160,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio);
+ extern int gpiochip_add(struct gpio_chip *chip);
+ extern int __must_check gpiochip_remove(struct gpio_chip *chip);
+ extern struct gpio_chip *gpiochip_find(void *data,
+-					int (*match)(struct gpio_chip *chip,
++				       int (*match) (struct gpio_chip * chip,
+ 						     void *data));
+ 
+-
+ /* Always use the library code for GPIO management calls,
+  * or when sleeping may be involved.
+  */
+@@ -161,7 +177,6 @@ extern int gpio_set_debounce(unsigned gpio, unsigned debounce);
+ extern int gpio_get_value_cansleep(unsigned gpio);
+ extern void gpio_set_value_cansleep(unsigned gpio, int value);
+ 
+-
+ /* A platform's <asm/gpio.h> code may want to inline the I/O calls when
+  * the GPIO is constant and refers to some always-present controller,
+  * giving direct access to chip registers and tight bitbanging loops.
+@@ -173,7 +188,8 @@ extern int __gpio_cansleep(unsigned gpio);
+ 
+ extern int __gpio_to_irq(unsigned gpio);
+ 
+-extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
++extern int gpio_request_one(unsigned gpio, unsigned long flags,
++			    const char *label);
+ extern int gpio_request_array(const struct gpio *array, size_t num);
+ extern void gpio_free_array(const struct gpio *array, size_t num);
+ 
+@@ -181,6 +197,15 @@ extern void gpio_free_array(const struct gpio *array, size_t num);
+ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
+ void devm_gpio_free(struct device *dev, unsigned int gpio);
+ 
++extern int gpio_interrupt_clear(unsigned gpio);
++extern int gpio_interrupt_setup(unsigned gpio,
++				struct gpio_interrupt_mode *mode);
++extern int gpio_interrupt_enable(unsigned gpio);
++extern int gpio_interrupt_disable(unsigned gpio);
++extern int gpio_interrupt_check(unsigned gpio);
++extern int gpio_interrupt_mask(unsigned gpio);
++extern int gpio_interrupt_unmask(unsigned gpio);
++
+ #ifdef CONFIG_GPIO_SYSFS
+ 
+ /*
+@@ -189,13 +214,13 @@ void devm_gpio_free(struct device *dev, unsigned int gpio);
+  */
+ extern int gpio_export(unsigned gpio, bool direction_may_change);
+ extern int gpio_export_link(struct device *dev, const char *name,
+-			unsigned gpio);
++			    unsigned gpio);
+ extern int gpio_sysfs_set_active_low(unsigned gpio, int value);
+ extern void gpio_unexport(unsigned gpio);
+ 
+-#endif	/* CONFIG_GPIO_SYSFS */
++#endif /* CONFIG_GPIO_SYSFS */
+ 
+-#else	/* !CONFIG_GPIOLIB */
++#else /* !CONFIG_GPIOLIB */
+ 
+ static inline bool gpio_is_valid(int number)
+ {
+@@ -238,7 +263,7 @@ static inline int gpio_export(unsigned gpio, bool direction_may_change)
+ }
+ 
+ static inline int gpio_export_link(struct device *dev, const char *name,
+-				unsigned gpio)
++				   unsigned gpio)
+ {
+ 	return -ENOSYS;
+ }
+@@ -251,6 +276,6 @@ static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
+ static inline void gpio_unexport(unsigned gpio)
+ {
+ }
+-#endif	/* CONFIG_GPIO_SYSFS */
++#endif /* CONFIG_GPIO_SYSFS */
+ 
+-#endif /* _ASM_GENERIC_GPIO_H */
++#endif /* _ASM_ARM_GPIO_H */
+diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
+index 679b349d..2b624103 100644
+--- a/include/linux/dmaengine.h
++++ b/include/linux/dmaengine.h
+@@ -615,6 +615,51 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single(
+ 	return chan->device->device_prep_slave_sg(chan, &sg, 1, dir, flags);
+ }
+ 
++/**
++ * dmaengine_prep_dma_cyclic - prepare the cyclic DMA transfer
++ * @chan: the DMA channel to prepare
++ * @buf_addr: physical DMA address where the buffer starts
++ * @buf_len: total number of bytes for the entire buffer
++ * @period_len: number of bytes for each period
++ * @direction: transfer direction, to or from device
++ */
++static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
++            struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, 
++            size_t period_len, enum dma_transfer_direction direction) 
++{
++    return chan->device->device_prep_dma_cyclic(chan, buf_addr, buf_len, period_len, direction);
++}		
++
++/**
++ * dmaengine_prep_dma_memcpy - prepare a memcpy operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
++            struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
++		    size_t len, unsigned long flags)
++{
++    return chan->device->device_prep_dma_memcpy(chan, dest, src, len, flags);
++}
++
++/**
++ * dmaengine_prep_dma_memset - prepare a memset operation
++ * @chan: the channel to prepare operation on
++ * @dest: operation virtual destination address
++ * @src: operation virtual source address
++ * @len: operation length
++ * @flags: tx descriptor status flags
++ */
++static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memset(
++            struct dma_chan *chan, dma_addr_t dest, int value,
++		    size_t len, unsigned long flags)
++{
++    return chan->device->device_prep_dma_memset(chan, dest, value, len, flags);
++}
++		    
+ static inline int dmaengine_terminate_all(struct dma_chan *chan)
+ {
+ 	return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
+diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h
+index dd8da342..8a05926d 100644
+--- a/include/linux/micrel_phy.h
++++ b/include/linux/micrel_phy.h
+@@ -1,16 +1,37 @@
++/*
++ * include/linux/micrel_phy.h
++ *
++ * Micrel PHY IDs
++ *
++ * 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.
++ *
++ */
++
+ #ifndef _MICREL_PHY_H
+ #define _MICREL_PHY_H
+ 
+-#define MICREL_PHY_ID_MASK	0x00fffff0
++#define MICREL_PHY_ID_MASK      0x00fffff0
++
++#define PHY_ID_KSZ8873MLL       0x000e7237
++#define PHY_ID_KSZ9021          0x00221610
++#define PHY_ID_KS8737           0x00221720
++#define PHY_ID_KSZ8021          0x00221555
++#define PHY_ID_KSZ8041          0x00221510
++#define PHY_ID_KSZ8051          0x00221550
++/* same id: ks8001 Rev. A/B, and ks8721 Rev 3. */
++#define PHY_ID_KSZ8001          0x0022161A
++/* same id: KS8081, KS8091 */
++#define PHY_ID_KSZ8081          0x00221560
++#define PHY_ID_KSZ8061          0x00221570
++#define PHY_ID_KSZ9031          0x00221620
+ 
+-#define PHY_ID_KSZ9021		0x00221611
+-#define PHY_ID_KS8737		0x00221720
+-#define PHY_ID_KS8041		0x00221510
+-#define PHY_ID_KS8051		0x00221550
+-/* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */
+-#define PHY_ID_KS8001		0x0022161A
++#define PHY_ID_KSZ886X          0x00221430
++#define PHY_ID_KSZ8863          0x00221435
+ 
+ /* struct phy_device dev_flags definitions */
+-#define MICREL_PHY_50MHZ_CLK	0x00000001
++#define MICREL_PHY_50MHZ_CLK    0x00000001
+ 
+ #endif /* _MICREL_PHY_H */
+diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
+index c750f851..ab2b79c6 100644
+--- a/include/linux/mmc/sdhci.h
++++ b/include/linux/mmc/sdhci.h
+@@ -136,6 +136,7 @@ struct sdhci_host {
+ 	struct mmc_command *cmd;	/* Current command */
+ 	struct mmc_data *data;	/* Current data request */
+ 	unsigned int data_early:1;	/* Data finished before cmd */
++	unsigned int busy_handle:1;	/* Handling the order of Busy-end */
+ 
+ 	struct sg_mapping_iter sg_miter;	/* SG state for PIO */
+ 	unsigned int blocks;	/* remaining PIO blocks */
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 63b5a8b6..ab5c629e 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -556,6 +556,7 @@ struct nand_chip {
+ #define NAND_MFR_MICRON		0x2c
+ #define NAND_MFR_AMD		0x01
+ #define NAND_MFR_MACRONIX	0xc2
++#define NAND_MFR_SPINAND	0xc8
+ 
+ /**
+  * struct nand_flash_dev - NAND Flash Device ID Structure
+diff --git a/include/linux/netfilter/xt_CONNMARK.h b/include/linux/netfilter/xt_CONNMARK.h
+index 2f2e48ec..efc17a83 100644
+--- a/include/linux/netfilter/xt_CONNMARK.h
++++ b/include/linux/netfilter/xt_CONNMARK.h
+@@ -1,6 +1,31 @@
+-#ifndef _XT_CONNMARK_H_target
+-#define _XT_CONNMARK_H_target
++#ifndef _XT_CONNMARK_H
++#define _XT_CONNMARK_H
+ 
+-#include <linux/netfilter/xt_connmark.h>
++#include <linux/types.h>
+ 
+-#endif /*_XT_CONNMARK_H_target*/
++/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * 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.
++ */
++
++enum {
++	XT_CONNMARK_SET = 0,
++	XT_CONNMARK_SAVE,
++	XT_CONNMARK_RESTORE
++};
++
++struct xt_connmark_tginfo1 {
++	__u32 ctmark, ctmask, nfmask;
++	__u8 mode;
++};
++
++struct xt_connmark_mtinfo1 {
++	__u32 mark, mask;
++	__u8 invert;
++};
++
++#endif /*_XT_CONNMARK_H*/
+diff --git a/include/linux/netfilter/xt_DSCP.h b/include/linux/netfilter/xt_DSCP.h
+index 648e0b3b..15f8932a 100644
+--- a/include/linux/netfilter/xt_DSCP.h
++++ b/include/linux/netfilter/xt_DSCP.h
+@@ -1,26 +1,31 @@
+-/* x_tables module for setting the IPv4/IPv6 DSCP field
++/* x_tables module for matching the IPv4/IPv6 DSCP field
+  *
+  * (C) 2002 Harald Welte <laforge@gnumonks.org>
+- * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+  * This software is distributed under GNU GPL v2, 1991
+  *
+  * See RFC2474 for a description of the DSCP field within the IP Header.
+  *
+- * xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
++ * xt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
+ */
+-#ifndef _XT_DSCP_TARGET_H
+-#define _XT_DSCP_TARGET_H
+-#include <linux/netfilter/xt_dscp.h>
++#ifndef _XT_DSCP_H
++#define _XT_DSCP_H
++
+ #include <linux/types.h>
+ 
+-/* target info */
+-struct xt_DSCP_info {
++#define XT_DSCP_MASK	0xfc	/* 11111100 */
++#define XT_DSCP_SHIFT	2
++#define XT_DSCP_MAX	0x3f	/* 00111111 */
++
++/* match info */
++struct xt_dscp_info {
+ 	__u8 dscp;
++	__u8 invert;
+ };
+ 
+-struct xt_tos_target_info {
+-	__u8 tos_value;
++struct xt_tos_match_info {
+ 	__u8 tos_mask;
++	__u8 tos_value;
++	__u8 invert;
+ };
+ 
+-#endif /* _XT_DSCP_TARGET_H */
++#endif /* _XT_DSCP_H */
+diff --git a/include/linux/netfilter/xt_TCPMSS.h b/include/linux/netfilter/xt_TCPMSS.h
+index 9a6960af..fbac56b9 100644
+--- a/include/linux/netfilter/xt_TCPMSS.h
++++ b/include/linux/netfilter/xt_TCPMSS.h
+@@ -1,12 +1,11 @@
+-#ifndef _XT_TCPMSS_H
+-#define _XT_TCPMSS_H
++#ifndef _XT_TCPMSS_MATCH_H
++#define _XT_TCPMSS_MATCH_H
+ 
+ #include <linux/types.h>
+ 
+-struct xt_tcpmss_info {
+-	__u16 mss;
++struct xt_tcpmss_match_info {
++    __u16 mss_min, mss_max;
++    __u8 invert;
+ };
+ 
+-#define XT_TCPMSS_CLAMP_PMTU 0xffff
+-
+-#endif /* _XT_TCPMSS_H */
++#endif /*_XT_TCPMSS_MATCH_H*/
+diff --git a/include/linux/spi/ftspi020.h b/include/linux/spi/ftspi020.h
+new file mode 100644
+index 00000000..129320eb
+--- /dev/null
++++ b/include/linux/spi/ftspi020.h
+@@ -0,0 +1,125 @@
++/**
++ * Command arguments definition for FTSPI020.
++ *
++ * Author: BingJiun Luo <bjluo@faraday-tech.com> 
++ *
++ * Copyright (c) 2011, Faraday Technology Corp.
++ *
++ */
++
++typedef struct sys_header {	
++    char signature[8];          /* Signature is "GM8xxx" */
++    unsigned int bootm_addr;    /* Image offset to load by spiboot */
++    unsigned int bootm_size;
++    unsigned int bootm_reserved;
++    
++    struct {
++        unsigned int addr;          /* image address */
++        unsigned int size;          /* image size */
++        unsigned char name[8];      /* image name */
++        unsigned int reserved[1];
++    } image[10];
++    
++    struct 
++    {
++        unsigned int pagesz_log2;   // page size with bytes in log2
++        unsigned int secsz_log2;    // sector size with bytes in log2
++        unsigned int chipsz_log2;   // chip size with bytes in log2
++        unsigned int clk_div;       // 2/4/6/8
++    } norfixup;	
++
++#ifdef CONFIG_PLATFORM_GM8210
++    unsigned int addr;          /* image address */
++    unsigned int size;          /* image size */
++    unsigned char name[8];      /* image name */
++#else        
++    unsigned int reserved[4];   // unused
++#endif
++    
++    unsigned char   last_256[4];    // byte254:0x55, byte255:0xAA
++} sys_header_t;
++
++/*
++ * Settings value required to send command.
++ */
++struct ftspi020_cmd {
++	char flags;
++	/* offset 0x00: CMD Queue first word */
++	u32 spi_addr;	
++	/* offset 0x04: CMD Queue second word */
++	u32 addr_len;
++	u32 dum_2nd_cyc;
++	u32 ins_len;
++	u32 conti_read_mode_en;
++	/* offset 0x08: CMD queue third word */
++	u32 data_cnt;
++	/* offset 0x0C: CMD queue fourth word */
++	u32 write_en;
++	u32 read_status_en;
++	u32 read_status;
++	u32 dtr_mode;
++	u32 spi_mode;
++	u32 conti_read_mode_code;
++	u32 ins_code;
++
++	/* User data buffer pointer */
++	const void *tx_buf;
++	void *rx_buf;
++};
++
++/*
++ * In what state this command belong ?
++ */
++#define FTSPI020_XFER_BEGIN			0x01
++#define FTSPI020_XFER_END			0x02
++#define FTSPI020_XFER_CMD_STATE			0x04
++#define FTSPI020_XFER_DATA_STATE		0x08
++#define FTSPI020_XFER_CHECK_CMD_COMPLETE	0x10
++
++/*
++ * CMD1 Register offset 4: Command Queue Second Word
++ */
++#define FTSPI020_CMD1_CONT_READ_MODE_EN		(1 << 28)
++#define FTSPI020_CMD1_CONT_READ_MODE_DIS	(0 << 28)
++
++#define FTSPI020_CMD1_OP_CODE_0_BYTE		(0 << 24)
++#define FTSPI020_CMD1_OP_CODE_1_BYTE		(1 << 24)
++#define FTSPI020_CMD1_OP_CODE_2_BYTE		(2 << 24)
++
++#define FTSPI020_CMD1_DUMMY_CYCLE(x)	(((x) & 0xff) << 16)
++
++#define FTSPI020_CMD1_NO_ADDR		(0 << 0)
++#define FTSPI020_CMD1_ADDR_1BYTE	(1 << 0)
++#define FTSPI020_CMD1_ADDR_2BYTE	(2 << 0)
++#define FTSPI020_CMD1_ADDR_3BYTE	(3 << 0)
++#define FTSPI020_CMD1_ADDR_4BYTE	(4 << 0)
++
++
++/*
++ * CMD3 Register offset 0xc: Command Queue Fourth Word
++ */
++#define FTSPI020_CMD3_INSTR_CODE(x)	(((x) & 0xff) << 24)
++#define FTSPI020_CMD3_CONT_READ_CODE(x)	(((x) & 0xff) << 16)
++
++#define FTSPI020_CMD3_CE(x)		(((x) & 0x3) << 8)
++
++#define FTSPI020_CMD3_SERIAL_MODE	(0 << 5)
++#define FTSPI020_CMD3_DUAL_MODE		(1 << 5)
++#define FTSPI020_CMD3_QUAD_MODE		(2 << 5)
++#define FTSPI020_CMD3_DUAL_IO_MODE	(3 << 5)
++#define FTSPI020_CMD3_QUAD_IO_MODE	(4 << 5)
++
++#define FTSPI020_CMD3_DTR_MODE_EN	(1 << 4)
++#define FTSPI020_CMD3_DTR_MODE_DIS	(0 << 4)
++
++#define FTSPI020_CMD3_STS_SW_READ	(1 << 3)
++#define FTSPI020_CMD3_STS_HW_READ	(0 << 3)
++
++#define FTSPI020_CMD3_RD_STS_EN		(1 << 2)
++#define FTSPI020_CMD3_RD_STS_DIS	(0 << 2)
++
++#define	FTSPI020_CMD3_WRITE		(1 << 1)	
++#define	FTSPI020_CMD3_READ		(0 << 1)	
++
++#define FTSPI020_CMD3_CMD_COMPL_INTR	(1 << 0)
++
+diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
+index 7cc95ee3..ee0829df 100644
+--- a/include/linux/usb/ehci_def.h
++++ b/include/linux/usb/ehci_def.h
+@@ -111,7 +111,11 @@ struct ehci_regs {
+ 	/* ASYNCLISTADDR: offset 0x18 */
+ 	u32		async_next;	/* address of next async queue head */
+ 
++#if !defined(CONFIG_ARCH_GM) && !defined(CONFIG_ARCH_GM_DUO)&& !defined(CONFIG_ARCH_GM_SMP)
+ 	u32		reserved[9];
++#else
++        //missed on Faraday's controller
++#endif
+ 
+ 	/* CONFIGFLAG: offset 0x40 */
+ 	u32		configured_flag;
+@@ -163,6 +167,32 @@ struct ehci_regs {
+ #define USBMODE_CM_HC	(3<<0)		/* host controller mode */
+ #define USBMODE_CM_IDLE	(0<<0)		/* idle state */
+ 
++// OTG210 related register
++#define OTG210_MISC                  0x30     /* Miscellaneous register */
++#define OTG210_MISC_EOF2_Time        (3<<4)   /* EOF2_Timing points */
++#define OTG210_MISC_EOF1_Time        (3<<2)   /* EOF1_Timing points */
++#define OTG210_MISC_ASYN_SCH_SLPT    (3<<0)   /* Asyn Schedule sleep timer */
++
++#define OTG210_OTG_STATUS            0x70     /* OTG Control Status register */
++#define OTG210_OTG_STATUS_SPD_TYPE   (3<<22)  /* Host Speed Type */
++#define OTG210_OTG_STATUS_CROLE      (1<<20)  /* Current Role, 0:Host, 1:Device */
++
++#define OTG210_OTG_MASK_INTR         0xB4     /* OTG Control Mask HC/OTG/DEV interrupt register */
++#define OTG210_OTG_MASK_INTR_HC     (1<<2)    /* Mask Host interrupt */
++
++// USBH200 related register
++#define USBH200_TIMER                0x24     /* EOF time & Async sleep Timer register */
++#define USBH200_TIMER_EOF2_Time      (3<<4)   /* EOF2_Timing points */
++#define USBH200_TIMER_EOF1_Time      (3<<2)   /* EOF1_Timing points */
++#define USBH200_TIMER_ASYN_SCH_SLPT  (3<<0)   /* Asyn Schedule sleep timer */
++
++#define USBH200_BUS_STATUS          0x30     /* Host Control Bus Control/Status register */
++#define USBH200_BUS_STATUS_SPD_TYPE (3<<9)   /* Host Speed Type */
++
++#define USBH200_BUS_MONITOR          0x34     /* Host Control Bus Monitor Status register */
++#define USBH200_BUS_MONITOR_OVC      (1<<1)   /* Over Current Detection */
++#define USBH200_BUS_MONITOR_VBUS_ERR (1<<0)   /* VBUS Error */
++
+ /* Moorestown has some non-standard registers, partially due to the fact that
+  * its EHCI controller has both TT and LPM support. HOSTPCx are extensions to
+  * PORTSCx
+diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
+index da653b5c..971ad75a 100644
+--- a/include/linux/usb/gadget.h
++++ b/include/linux/usb/gadget.h
+@@ -562,6 +562,10 @@ static inline int gadget_is_dualspeed(struct usb_gadget *g)
+ 	/* runtime test would check "g->max_speed" ... that might be
+ 	 * useful to work around hardware bugs, but is mostly pointless
+ 	 */
++#if defined(CONFIG_PLATFORM_GM8136)
++    if (CONFIG_GM_OTG_CHOOSE == 1)
++        return 0;
++#endif
+ 	return 1;
+ #else
+ 	return 0;
+diff --git a/init/do_mounts.c b/init/do_mounts.c
+index 2974c8b3..2b905be2 100644
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -27,6 +27,7 @@ int __initdata rd_doload;	/* 1 = load RAM disk, 0 = don't load */
+ 
+ int root_mountflags = MS_RDONLY | MS_SILENT;
+ static char * __initdata root_device_name;
++int root_mtd_num = 0xFFFF;
+ static char __initdata saved_root_name[64];
+ static int root_wait;
+ 
+@@ -282,6 +283,7 @@ static char * __initdata root_fs_names;
+ static int __init fs_names_setup(char *str)
+ {
+ 	root_fs_names = str;
++	//printk("stype str=%s\n",*str);
+ 	return 1;
+ }
+ 
+@@ -353,6 +355,10 @@ void __init mount_block_root(char *name, int flags)
+ #endif
+ 
+ 	get_fs_names(fs_names);
++	// squash
++	if (strncmp(fs_names, "squashfs", 8) != 0)
++	    root_mtd_num = 0xFFFF;
++
+ retry:
+ 	for (p = fs_names; *p; p += strlen(p)+1) {
+ 		int err = do_mount_root(name, p, flags, root_mount_data);
+@@ -498,6 +504,23 @@ void __init mount_root(void)
+ #endif
+ }
+ 
++static s32 atoi(char *psz_buf)
++{
++        char *pch = psz_buf;
++        s32 base = 0;
++
++        while (isspace(*pch))
++                pch++;
++
++        if (*pch == '-' || *pch == '+') {
++                base = 10;
++                pch++;
++        } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
++                base = 16;
++        }
++
++        return simple_strtoul(pch, NULL, base);
++}
+ /*
+  * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
+  */
+@@ -532,6 +555,13 @@ void __init prepare_namespace(void)
+ 		ROOT_DEV = name_to_dev_t(root_device_name);
+ 		if (strncmp(root_device_name, "/dev/", 5) == 0)
+ 			root_device_name += 5;
++			
++		// squash
++		if (strncmp(root_device_name, "mtdblock", 8) == 0) {
++		    static char *root_mtd;
++		    root_mtd = root_device_name + 8;
++		    root_mtd_num = atoi(root_mtd);
++	    }
+ 	}
+ 
+ 	if (initrd_load())
+diff --git a/init/main.c b/init/main.c
+index ff49a6da..b85b5912 100644
+--- a/init/main.c
++++ b/init/main.c
+@@ -121,6 +121,7 @@ extern void softirq_init(void);
+ 
+ /* Untouched command line saved by arch-specific code. */
+ char __initdata boot_command_line[COMMAND_LINE_SIZE];
++EXPORT_SYMBOL(boot_command_line);
+ /* Untouched saved command line (eg. for /proc) */
+ char *saved_command_line;
+ /* Command line for parameter parsing */
+@@ -632,7 +633,7 @@ asmlinkage void __init start_kernel(void)
+ 	sfi_init_late();
+ 
+ 	ftrace_init();
+-
++    
+ 	/* Do the rest non-__init'ed, we're now alive */
+ 	rest_init();
+ }
+diff --git a/kernel/kexec.c b/kernel/kexec.c
+index 7b088678..cb5d13c8 100644
+--- a/kernel/kexec.c
++++ b/kernel/kexec.c
+@@ -1462,7 +1462,9 @@ static int __init crash_save_vmcoreinfo_init(void)
+ 
+ 	VMCOREINFO_SYMBOL(init_uts_ns);
+ 	VMCOREINFO_SYMBOL(node_online_map);
++#ifdef CONFIG_MMU
+ 	VMCOREINFO_SYMBOL(swapper_pg_dir);
++#endif
+ 	VMCOREINFO_SYMBOL(_stext);
+ 	VMCOREINFO_SYMBOL(vmlist);
+ 
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index b342f578..423f40f3 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -1932,6 +1932,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
+ 	local_irq_enable();
+ #endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
+ 	finish_lock_switch(rq, prev);
++	finish_arch_post_lock_switch();
+ 
+ 	fire_sched_in_preempt_notifiers(current);
+ 	if (mm)
+diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
+index 98c0c262..d72483d0 100644
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -692,6 +692,9 @@ static inline int task_running(struct rq *rq, struct task_struct *p)
+ #ifndef finish_arch_switch
+ # define finish_arch_switch(prev)	do { } while (0)
+ #endif
++#ifndef finish_arch_post_lock_switch
++# define finish_arch_post_lock_switch()	do { } while (0)
++#endif
+ 
+ #ifndef __ARCH_WANT_UNLOCKED_CTXSW
+ static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next)
+diff --git a/mkimage b/mkimage
+new file mode 100644
+index 00000000..e1cca9e3
+Binary files /dev/null and b/mkimage differ
+diff --git a/mm/page-writeback.c b/mm/page-writeback.c
+index 363ba708..2ee236f8 100644
+--- a/mm/page-writeback.c
++++ b/mm/page-writeback.c
+@@ -65,7 +65,11 @@ static long ratelimit_pages = 32;
+ /*
+  * Start background writeback (via writeback threads) at this percentage
+  */
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++int dirty_background_ratio = 1;
++#else
+ int dirty_background_ratio = 10;
++#endif
+ 
+ /*
+  * dirty_background_bytes starts at 0 (disabled) so that it is a function of
+@@ -82,7 +86,11 @@ int vm_highmem_is_dirtyable;
+ /*
+  * The generator of dirty data starts writeback at this percentage
+  */
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++int vm_dirty_ratio = 2;
++#else
+ int vm_dirty_ratio = 20;
++#endif
+ 
+ /*
+  * vm_dirty_bytes starts at 0 (disabled) so that it is a function of
+@@ -93,12 +101,20 @@ unsigned long vm_dirty_bytes;
+ /*
+  * The interval between `kupdate'-style writebacks
+  */
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++unsigned int dirty_writeback_interval = 1 * 100; /* centiseconds */
++#else
+ unsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */
++#endif
+ 
+ /*
+  * The longest time for which data is allowed to remain dirty
+  */
++#ifdef CONFIG_SATA_AHCI_PLATFORM
++unsigned int dirty_expire_interval = 10 * 100; /* centiseconds */
++#else
+ unsigned int dirty_expire_interval = 30 * 100; /* centiseconds */
++#endif
+ 
+ /*
+  * Flag that makes the machine dump writes/reads and block dirtyings.
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index a13ded19..11ae920b 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -3381,7 +3381,7 @@ void __ref build_all_zonelists(void *data)
+ 	else
+ 		page_group_by_mobility_disabled = 0;
+ 
+-	printk("Built %i zonelists in %s order, mobility grouping %s.  "
++	printk(KERN_INFO "Built %i zonelists in %s order, mobility grouping %s.  "
+ 		"Total pages: %ld\n",
+ 			nr_online_nodes,
+ 			zonelist_order_name[current_zonelist_order],
+diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
+index 63e49890..ce231dc0 100644
+--- a/net/ipv4/arp.c
++++ b/net/ipv4/arp.c
+@@ -599,7 +599,12 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+ 
+ 	skb_reserve(skb, hlen);
+ 	skb_reset_network_header(skb);
++#if 0 // Original code
+ 	arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev));
++#else // Modify: add extra 18 bytes data buffer for ARP padding space
++    #define SIZE_OF_ARP_PADDING   18
++    arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev)+SIZE_OF_ARP_PADDING);
++#endif
+ 	skb->dev = dev;
+ 	skb->protocol = htons(ETH_P_ARP);
+ 	if (src_hw == NULL)
+@@ -673,7 +678,10 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+ 		memset(arp_ptr, 0, dev->addr_len);
+ 	arp_ptr += dev->addr_len;
+ 	memcpy(arp_ptr, &dest_ip, 4);
+-
++#if 1 // Modify: Clear the ARP padding to be zero forcefully.
++	arp_ptr += 4;
++	memset(arp_ptr, 0x00, SIZE_OF_ARP_PADDING);
++#endif
+ 	return skb;
+ 
+ out:
+diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c
+deleted file mode 100644
+index ae827165..00000000
+--- a/net/netfilter/xt_DSCP.c
++++ /dev/null
+@@ -1,164 +0,0 @@
+-/* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8
+- *
+- * (C) 2002 by Harald Welte <laforge@netfilter.org>
+- * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
+- *
+- * 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.
+- *
+- * See RFC2474 for a description of the DSCP field within the IP Header.
+-*/
+-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+-#include <linux/module.h>
+-#include <linux/skbuff.h>
+-#include <linux/ip.h>
+-#include <linux/ipv6.h>
+-#include <net/dsfield.h>
+-
+-#include <linux/netfilter/x_tables.h>
+-#include <linux/netfilter/xt_DSCP.h>
+-
+-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+-MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("ipt_DSCP");
+-MODULE_ALIAS("ip6t_DSCP");
+-MODULE_ALIAS("ipt_TOS");
+-MODULE_ALIAS("ip6t_TOS");
+-
+-static unsigned int
+-dscp_tg(struct sk_buff *skb, const struct xt_action_param *par)
+-{
+-	const struct xt_DSCP_info *dinfo = par->targinfo;
+-	u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
+-
+-	if (dscp != dinfo->dscp) {
+-		if (!skb_make_writable(skb, sizeof(struct iphdr)))
+-			return NF_DROP;
+-
+-		ipv4_change_dsfield(ip_hdr(skb), (__u8)(~XT_DSCP_MASK),
+-				    dinfo->dscp << XT_DSCP_SHIFT);
+-
+-	}
+-	return XT_CONTINUE;
+-}
+-
+-static unsigned int
+-dscp_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+-{
+-	const struct xt_DSCP_info *dinfo = par->targinfo;
+-	u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
+-
+-	if (dscp != dinfo->dscp) {
+-		if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
+-			return NF_DROP;
+-
+-		ipv6_change_dsfield(ipv6_hdr(skb), (__u8)(~XT_DSCP_MASK),
+-				    dinfo->dscp << XT_DSCP_SHIFT);
+-	}
+-	return XT_CONTINUE;
+-}
+-
+-static int dscp_tg_check(const struct xt_tgchk_param *par)
+-{
+-	const struct xt_DSCP_info *info = par->targinfo;
+-
+-	if (info->dscp > XT_DSCP_MAX) {
+-		pr_info("dscp %x out of range\n", info->dscp);
+-		return -EDOM;
+-	}
+-	return 0;
+-}
+-
+-static unsigned int
+-tos_tg(struct sk_buff *skb, const struct xt_action_param *par)
+-{
+-	const struct xt_tos_target_info *info = par->targinfo;
+-	struct iphdr *iph = ip_hdr(skb);
+-	u_int8_t orig, nv;
+-
+-	orig = ipv4_get_dsfield(iph);
+-	nv   = (orig & ~info->tos_mask) ^ info->tos_value;
+-
+-	if (orig != nv) {
+-		if (!skb_make_writable(skb, sizeof(struct iphdr)))
+-			return NF_DROP;
+-		iph = ip_hdr(skb);
+-		ipv4_change_dsfield(iph, 0, nv);
+-	}
+-
+-	return XT_CONTINUE;
+-}
+-
+-static unsigned int
+-tos_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+-{
+-	const struct xt_tos_target_info *info = par->targinfo;
+-	struct ipv6hdr *iph = ipv6_hdr(skb);
+-	u_int8_t orig, nv;
+-
+-	orig = ipv6_get_dsfield(iph);
+-	nv   = (orig & ~info->tos_mask) ^ info->tos_value;
+-
+-	if (orig != nv) {
+-		if (!skb_make_writable(skb, sizeof(struct iphdr)))
+-			return NF_DROP;
+-		iph = ipv6_hdr(skb);
+-		ipv6_change_dsfield(iph, 0, nv);
+-	}
+-
+-	return XT_CONTINUE;
+-}
+-
+-static struct xt_target dscp_tg_reg[] __read_mostly = {
+-	{
+-		.name		= "DSCP",
+-		.family		= NFPROTO_IPV4,
+-		.checkentry	= dscp_tg_check,
+-		.target		= dscp_tg,
+-		.targetsize	= sizeof(struct xt_DSCP_info),
+-		.table		= "mangle",
+-		.me		= THIS_MODULE,
+-	},
+-	{
+-		.name		= "DSCP",
+-		.family		= NFPROTO_IPV6,
+-		.checkentry	= dscp_tg_check,
+-		.target		= dscp_tg6,
+-		.targetsize	= sizeof(struct xt_DSCP_info),
+-		.table		= "mangle",
+-		.me		= THIS_MODULE,
+-	},
+-	{
+-		.name		= "TOS",
+-		.revision	= 1,
+-		.family		= NFPROTO_IPV4,
+-		.table		= "mangle",
+-		.target		= tos_tg,
+-		.targetsize	= sizeof(struct xt_tos_target_info),
+-		.me		= THIS_MODULE,
+-	},
+-	{
+-		.name		= "TOS",
+-		.revision	= 1,
+-		.family		= NFPROTO_IPV6,
+-		.table		= "mangle",
+-		.target		= tos_tg6,
+-		.targetsize	= sizeof(struct xt_tos_target_info),
+-		.me		= THIS_MODULE,
+-	},
+-};
+-
+-static int __init dscp_tg_init(void)
+-{
+-	return xt_register_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg));
+-}
+-
+-static void __exit dscp_tg_exit(void)
+-{
+-	xt_unregister_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg));
+-}
+-
+-module_init(dscp_tg_init);
+-module_exit(dscp_tg_exit);
+diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
+index 190ad37c..c53d4d18 100644
+--- a/net/netfilter/xt_TCPMSS.c
++++ b/net/netfilter/xt_TCPMSS.c
+@@ -1,320 +1,110 @@
+-/*
+- * This is a module which is used for setting the MSS option in TCP packets.
+- *
+- * Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
++/* Kernel module to match TCP MSS values. */
++
++/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
++ * Portions (C) 2005 by Harald Welte <laforge@netfilter.org>
+  *
+  * 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.
+  */
+-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
+ #include <linux/module.h>
+ #include <linux/skbuff.h>
+-#include <linux/ip.h>
+-#include <linux/gfp.h>
+-#include <linux/ipv6.h>
+-#include <linux/tcp.h>
+-#include <net/dst.h>
+-#include <net/flow.h>
+-#include <net/ipv6.h>
+-#include <net/route.h>
+ #include <net/tcp.h>
+ 
++#include <linux/netfilter/xt_tcpmss.h>
++#include <linux/netfilter/x_tables.h>
++
+ #include <linux/netfilter_ipv4/ip_tables.h>
+ #include <linux/netfilter_ipv6/ip6_tables.h>
+-#include <linux/netfilter/x_tables.h>
+-#include <linux/netfilter/xt_tcpudp.h>
+-#include <linux/netfilter/xt_TCPMSS.h>
+ 
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+-MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment");
+-MODULE_ALIAS("ipt_TCPMSS");
+-MODULE_ALIAS("ip6t_TCPMSS");
++MODULE_DESCRIPTION("Xtables: TCP MSS match");
++MODULE_ALIAS("ipt_tcpmss");
++MODULE_ALIAS("ip6t_tcpmss");
+ 
+-static inline unsigned int
+-optlen(const u_int8_t *opt, unsigned int offset)
++static bool
++tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par)
+ {
+-	/* Beware zero-length options: make finite progress */
+-	if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
+-		return 1;
+-	else
+-		return opt[offset+1];
+-}
+-
+-static int
+-tcpmss_mangle_packet(struct sk_buff *skb,
+-		     const struct xt_tcpmss_info *info,
+-		     unsigned int in_mtu,
+-		     unsigned int tcphoff,
+-		     unsigned int minlen)
+-{
+-	struct tcphdr *tcph;
+-	unsigned int tcplen, i;
+-	__be16 oldval;
+-	u16 newmss;
+-	u8 *opt;
+-
+-	if (!skb_make_writable(skb, skb->len))
+-		return -1;
+-
+-	tcplen = skb->len - tcphoff;
+-	tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+-
+-	/* Header cannot be larger than the packet */
+-	if (tcplen < tcph->doff*4)
+-		return -1;
+-
+-	if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
+-		if (dst_mtu(skb_dst(skb)) <= minlen) {
+-			if (net_ratelimit())
+-				pr_err("unknown or invalid path-MTU (%u)\n",
+-				       dst_mtu(skb_dst(skb)));
+-			return -1;
+-		}
+-		if (in_mtu <= minlen) {
+-			if (net_ratelimit())
+-				pr_err("unknown or invalid path-MTU (%u)\n",
+-				       in_mtu);
+-			return -1;
+-		}
+-		newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen;
+-	} else
+-		newmss = info->mss;
+-
+-	opt = (u_int8_t *)tcph;
+-	for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
+-		if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
+-		    opt[i+1] == TCPOLEN_MSS) {
+-			u_int16_t oldmss;
+-
+-			oldmss = (opt[i+2] << 8) | opt[i+3];
+-
+-			/* Never increase MSS, even when setting it, as
+-			 * doing so results in problems for hosts that rely
+-			 * on MSS being set correctly.
+-			 */
+-			if (oldmss <= newmss)
+-				return 0;
+-
+-			opt[i+2] = (newmss & 0xff00) >> 8;
+-			opt[i+3] = newmss & 0x00ff;
+-
+-			inet_proto_csum_replace2(&tcph->check, skb,
+-						 htons(oldmss), htons(newmss),
+-						 0);
+-			return 0;
++	const struct xt_tcpmss_match_info *info = par->matchinfo;
++	const struct tcphdr *th;
++	struct tcphdr _tcph;
++	/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
++	const u_int8_t *op;
++	u8 _opt[15 * 4 - sizeof(_tcph)];
++	unsigned int i, optlen;
++
++	/* If we don't have the whole header, drop packet. */
++	th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
++	if (th == NULL)
++		goto dropit;
++
++	/* Malformed. */
++	if (th->doff*4 < sizeof(*th))
++		goto dropit;
++
++	optlen = th->doff*4 - sizeof(*th);
++	if (!optlen)
++		goto out;
++
++	/* Truncated options. */
++	op = skb_header_pointer(skb, par->thoff + sizeof(*th), optlen, _opt);
++	if (op == NULL)
++		goto dropit;
++
++	for (i = 0; i < optlen; ) {
++		if (op[i] == TCPOPT_MSS
++		    && (optlen - i) >= TCPOLEN_MSS
++		    && op[i+1] == TCPOLEN_MSS) {
++			u_int16_t mssval;
++
++			mssval = (op[i+2] << 8) | op[i+3];
++
++			return (mssval >= info->mss_min &&
++				mssval <= info->mss_max) ^ info->invert;
+ 		}
++		if (op[i] < 2)
++			i++;
++		else
++			i += op[i+1] ? : 1;
+ 	}
++out:
++	return info->invert;
+ 
+-	/* There is data after the header so the option can't be added
+-	   without moving it, and doing so may make the SYN packet
+-	   itself too large. Accept the packet unmodified instead. */
+-	if (tcplen > tcph->doff*4)
+-		return 0;
+-
+-	/*
+-	 * MSS Option not found ?! add it..
+-	 */
+-	if (skb_tailroom(skb) < TCPOLEN_MSS) {
+-		if (pskb_expand_head(skb, 0,
+-				     TCPOLEN_MSS - skb_tailroom(skb),
+-				     GFP_ATOMIC))
+-			return -1;
+-		tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+-	}
+-
+-	skb_put(skb, TCPOLEN_MSS);
+-
+-	opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
+-	memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
+-
+-	inet_proto_csum_replace2(&tcph->check, skb,
+-				 htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
+-	opt[0] = TCPOPT_MSS;
+-	opt[1] = TCPOLEN_MSS;
+-	opt[2] = (newmss & 0xff00) >> 8;
+-	opt[3] = newmss & 0x00ff;
+-
+-	inet_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), 0);
+-
+-	oldval = ((__be16 *)tcph)[6];
+-	tcph->doff += TCPOLEN_MSS/4;
+-	inet_proto_csum_replace2(&tcph->check, skb,
+-				 oldval, ((__be16 *)tcph)[6], 0);
+-	return TCPOLEN_MSS;
+-}
+-
+-static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
+-				    unsigned int family)
+-{
+-	struct flowi fl;
+-	const struct nf_afinfo *ai;
+-	struct rtable *rt = NULL;
+-	u_int32_t mtu     = ~0U;
+-
+-	if (family == PF_INET) {
+-		struct flowi4 *fl4 = &fl.u.ip4;
+-		memset(fl4, 0, sizeof(*fl4));
+-		fl4->daddr = ip_hdr(skb)->saddr;
+-	} else {
+-		struct flowi6 *fl6 = &fl.u.ip6;
+-
+-		memset(fl6, 0, sizeof(*fl6));
+-		fl6->daddr = ipv6_hdr(skb)->saddr;
+-	}
+-	rcu_read_lock();
+-	ai = nf_get_afinfo(family);
+-	if (ai != NULL)
+-		ai->route(&init_net, (struct dst_entry **)&rt, &fl, false);
+-	rcu_read_unlock();
+-
+-	if (rt != NULL) {
+-		mtu = dst_mtu(&rt->dst);
+-		dst_release(&rt->dst);
+-	}
+-	return mtu;
+-}
+-
+-static unsigned int
+-tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
+-{
+-	struct iphdr *iph = ip_hdr(skb);
+-	__be16 newlen;
+-	int ret;
+-
+-	ret = tcpmss_mangle_packet(skb, par->targinfo,
+-				   tcpmss_reverse_mtu(skb, PF_INET),
+-				   iph->ihl * 4,
+-				   sizeof(*iph) + sizeof(struct tcphdr));
+-	if (ret < 0)
+-		return NF_DROP;
+-	if (ret > 0) {
+-		iph = ip_hdr(skb);
+-		newlen = htons(ntohs(iph->tot_len) + ret);
+-		csum_replace2(&iph->check, iph->tot_len, newlen);
+-		iph->tot_len = newlen;
+-	}
+-	return XT_CONTINUE;
+-}
+-
+-#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+-static unsigned int
+-tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+-{
+-	struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+-	u8 nexthdr;
+-	__be16 frag_off;
+-	int tcphoff;
+-	int ret;
+-
+-	nexthdr = ipv6h->nexthdr;
+-	tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr, &frag_off);
+-	if (tcphoff < 0)
+-		return NF_DROP;
+-	ret = tcpmss_mangle_packet(skb, par->targinfo,
+-				   tcpmss_reverse_mtu(skb, PF_INET6),
+-				   tcphoff,
+-				   sizeof(*ipv6h) + sizeof(struct tcphdr));
+-	if (ret < 0)
+-		return NF_DROP;
+-	if (ret > 0) {
+-		ipv6h = ipv6_hdr(skb);
+-		ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret);
+-	}
+-	return XT_CONTINUE;
+-}
+-#endif
+-
+-/* Must specify -p tcp --syn */
+-static inline bool find_syn_match(const struct xt_entry_match *m)
+-{
+-	const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
+-
+-	if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
+-	    tcpinfo->flg_cmp & TCPHDR_SYN &&
+-	    !(tcpinfo->invflags & XT_TCP_INV_FLAGS))
+-		return true;
+-
++dropit:
++	par->hotdrop = true;
+ 	return false;
+ }
+ 
+-static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
+-{
+-	const struct xt_tcpmss_info *info = par->targinfo;
+-	const struct ipt_entry *e = par->entryinfo;
+-	const struct xt_entry_match *ematch;
+-
+-	if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+-	    (par->hook_mask & ~((1 << NF_INET_FORWARD) |
+-			   (1 << NF_INET_LOCAL_OUT) |
+-			   (1 << NF_INET_POST_ROUTING))) != 0) {
+-		pr_info("path-MTU clamping only supported in "
+-			"FORWARD, OUTPUT and POSTROUTING hooks\n");
+-		return -EINVAL;
+-	}
+-	xt_ematch_foreach(ematch, e)
+-		if (find_syn_match(ematch))
+-			return 0;
+-	pr_info("Only works on TCP SYN packets\n");
+-	return -EINVAL;
+-}
+-
+-#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+-static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
+-{
+-	const struct xt_tcpmss_info *info = par->targinfo;
+-	const struct ip6t_entry *e = par->entryinfo;
+-	const struct xt_entry_match *ematch;
+-
+-	if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
+-	    (par->hook_mask & ~((1 << NF_INET_FORWARD) |
+-			   (1 << NF_INET_LOCAL_OUT) |
+-			   (1 << NF_INET_POST_ROUTING))) != 0) {
+-		pr_info("path-MTU clamping only supported in "
+-			"FORWARD, OUTPUT and POSTROUTING hooks\n");
+-		return -EINVAL;
+-	}
+-	xt_ematch_foreach(ematch, e)
+-		if (find_syn_match(ematch))
+-			return 0;
+-	pr_info("Only works on TCP SYN packets\n");
+-	return -EINVAL;
+-}
+-#endif
+-
+-static struct xt_target tcpmss_tg_reg[] __read_mostly = {
++static struct xt_match tcpmss_mt_reg[] __read_mostly = {
+ 	{
++		.name		= "tcpmss",
+ 		.family		= NFPROTO_IPV4,
+-		.name		= "TCPMSS",
+-		.checkentry	= tcpmss_tg4_check,
+-		.target		= tcpmss_tg4,
+-		.targetsize	= sizeof(struct xt_tcpmss_info),
++		.match		= tcpmss_mt,
++		.matchsize	= sizeof(struct xt_tcpmss_match_info),
+ 		.proto		= IPPROTO_TCP,
+ 		.me		= THIS_MODULE,
+ 	},
+-#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+ 	{
++		.name		= "tcpmss",
+ 		.family		= NFPROTO_IPV6,
+-		.name		= "TCPMSS",
+-		.checkentry	= tcpmss_tg6_check,
+-		.target		= tcpmss_tg6,
+-		.targetsize	= sizeof(struct xt_tcpmss_info),
++		.match		= tcpmss_mt,
++		.matchsize	= sizeof(struct xt_tcpmss_match_info),
+ 		.proto		= IPPROTO_TCP,
+ 		.me		= THIS_MODULE,
+ 	},
+-#endif
+ };
+ 
+-static int __init tcpmss_tg_init(void)
++static int __init tcpmss_mt_init(void)
+ {
+-	return xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
++	return xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
+ }
+ 
+-static void __exit tcpmss_tg_exit(void)
++static void __exit tcpmss_mt_exit(void)
+ {
+-	xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
++	xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
+ }
+ 
+-module_init(tcpmss_tg_init);
+-module_exit(tcpmss_tg_exit);
++module_init(tcpmss_mt_init);
++module_exit(tcpmss_mt_exit);
+diff --git a/scripts/depmod.sh b/scripts/depmod.sh
+index 2ae48170..2ee3a1ee 100755
+--- a/scripts/depmod.sh
++++ b/scripts/depmod.sh
+@@ -2,12 +2,13 @@
+ #
+ # A depmod wrapper used by the toplevel Makefile
+ 
+-if test $# -ne 2; then
++if test $# -ne 3; then
+ 	echo "Usage: $0 /sbin/depmod <kernelrelease>" >&2
+ 	exit 1
+ fi
+ DEPMOD=$1
+ KERNELRELEASE=$2
++INSTALL_MOD_PATH=$3
+ 
+ if ! test -r System.map -a -x "$DEPMOD"; then
+ 	exit 0
+diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
+index 3420bd3d..c09c4458 100644
+--- a/sound/core/pcm_lib.c
++++ b/sound/core/pcm_lib.c
+@@ -170,6 +170,9 @@ static void xrun(struct snd_pcm_substream *substream)
+ 	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+ 		snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
+ 	snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
++
++    printk("Kernel: XRUN %d happens! User application doesn't process data in time! \n", substream->stream);
++
+ 	if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
+ 		char name[16];
+ 		snd_pcm_debug_name(substream, name, sizeof(name));
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index 7c205e77..ee0abf49 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -320,7 +320,7 @@ config SND_SOC_WM8728
+ 	tristate
+ 
+ config SND_SOC_WM8731
+-	tristate
++	tristate "Wolfson WM8731 Codec support"
+ 
+ config SND_SOC_WM8737
+ 	tristate
+diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
+index 8821af70..385b42b7 100644
+--- a/sound/soc/codecs/wm8731.c
++++ b/sound/soc/codecs/wm8731.c
+@@ -446,7 +446,21 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
+ 
+ 		/* Clear PWROFF, gate CLKOUT, everything else as-is */
+ 		reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f;
++#ifdef CONFIG_ARCH_FARADAY
++		/*
++		 * Make sure that CLKOUT of wm8731 will not be powered down.
++		 *
++		 * We choose external clock source (X_SSP_CLK) as SSP0 clock
++		 * input by setting bit 4 of SCLK_CFG1 register of SCU010.
++		 * The external clock source (X_SSP_CLK) comes from CLKOUT of
++		 * wm8731 on A369 evb. The wm8731 codec driver in Linux gates
++		 * CLKOUT by default. We need to apply this patch or there will
++		 * be no external clock.
++		 */
++		snd_soc_write(codec, WM8731_PWR, reg);
++#else
+ 		snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
++#endif
+ 		break;
+ 	case SND_SOC_BIAS_OFF:
+ 		snd_soc_write(codec, WM8731_PWR, 0xffff);
diff --git a/br-ext-chip-grainmedia/board/gm8136/kernel/patches/10_overlayfs.v13.patch b/br-ext-chip-grainmedia/board/gm8136/kernel/patches/10_overlayfs.v13.patch
new file mode 100644
index 00000000..e6179e47
--- /dev/null
+++ b/br-ext-chip-grainmedia/board/gm8136/kernel/patches/10_overlayfs.v13.patch
@@ -0,0 +1,3363 @@
+diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
+index 4fca82e..42b0539 100644
+--- a/Documentation/filesystems/Locking
++++ b/Documentation/filesystems/Locking
+@@ -62,6 +62,7 @@ ata *);
+ 	int (*removexattr) (struct dentry *, const char *);
+ 	void (*truncate_range)(struct inode *, loff_t, loff_t);
+ 	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
++	struct file *(*open)(struct dentry *,struct file *,const struct cred *);
+ 
+ locking rules:
+ 	all may block
+@@ -89,6 +90,7 @@ listxattr:	no
+ removexattr:	yes
+ truncate_range:	yes
+ fiemap:		no
++open:		no
+ 	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
+ victim.
+ 	cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
+diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt
+new file mode 100644
+index 0000000..7161dc3
+--- /dev/null
++++ b/Documentation/filesystems/overlayfs.txt
+@@ -0,0 +1,199 @@
++Written by: Neil Brown <neilb@suse.de>
++
++Overlay Filesystem
++==================
++
++This document describes a prototype for a new approach to providing
++overlay-filesystem functionality in Linux (sometimes referred to as
++union-filesystems).  An overlay-filesystem tries to present a
++filesystem which is the result over overlaying one filesystem on top
++of the other.
++
++The result will inevitably fail to look exactly like a normal
++filesystem for various technical reasons.  The expectation is that
++many use cases will be able to ignore these differences.
++
++This approach is 'hybrid' because the objects that appear in the
++filesystem do not all appear to belong to that filesystem.  In many
++cases an object accessed in the union will be indistinguishable
++from accessing the corresponding object from the original filesystem.
++This is most obvious from the 'st_dev' field returned by stat(2).
++
++While directories will report an st_dev from the overlay-filesystem,
++all non-directory objects will report an st_dev from the lower or
++upper filesystem that is providing the object.  Similarly st_ino will
++only be unique when combined with st_dev, and both of these can change
++over the lifetime of a non-directory object.  Many applications and
++tools ignore these values and will not be affected.
++
++Upper and Lower
++---------------
++
++An overlay filesystem combines two filesystems - an 'upper' filesystem
++and a 'lower' filesystem.  When a name exists in both filesystems, the
++object in the 'upper' filesystem is visible while the object in the
++'lower' filesystem is either hidden or, in the case of directories,
++merged with the 'upper' object.
++
++It would be more correct to refer to an upper and lower 'directory
++tree' rather than 'filesystem' as it is quite possible for both
++directory trees to be in the same filesystem and there is no
++requirement that the root of a filesystem be given for either upper or
++lower.
++
++The lower filesystem can be any filesystem supported by Linux and does
++not need to be writable.  The lower filesystem can even be another
++overlayfs.  The upper filesystem will normally be writable and if it
++is it must support the creation of trusted.* extended attributes, and
++must provide valid d_type in readdir responses, at least for symbolic
++links - so NFS is not suitable.
++
++A read-only overlay of two read-only filesystems may use any
++filesystem type.
++
++Directories
++-----------
++
++Overlaying mainly involved directories.  If a given name appears in both
++upper and lower filesystems and refers to a non-directory in either,
++then the lower object is hidden - the name refers only to the upper
++object.
++
++Where both upper and lower objects are directories, a merged directory
++is formed.
++
++At mount time, the two directories given as mount options are combined
++into a merged directory:
++
++  mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper /overlay
++
++Then whenever a lookup is requested in such a merged directory, the
++lookup is performed in each actual directory and the combined result
++is cached in the dentry belonging to the overlay filesystem.  If both
++actual lookups find directories, both are stored and a merged
++directory is created, otherwise only one is stored: the upper if it
++exists, else the lower.
++
++Only the lists of names from directories are merged.  Other content
++such as metadata and extended attributes are reported for the upper
++directory only.  These attributes of the lower directory are hidden.
++
++whiteouts and opaque directories
++--------------------------------
++
++In order to support rm and rmdir without changing the lower
++filesystem, an overlay filesystem needs to record in the upper filesystem
++that files have been removed.  This is done using whiteouts and opaque
++directories (non-directories are always opaque).
++
++The overlay filesystem uses extended attributes with a
++"trusted.overlay."  prefix to record these details.
++
++A whiteout is created as a symbolic link with target
++"(overlay-whiteout)" and with xattr "trusted.overlay.whiteout" set to "y".
++When a whiteout is found in the upper level of a merged directory, any
++matching name in the lower level is ignored, and the whiteout itself
++is also hidden.
++
++A directory is made opaque by setting the xattr "trusted.overlay.opaque"
++to "y".  Where the upper filesystem contains an opaque directory, any
++directory in the lower filesystem with the same name is ignored.
++
++readdir
++-------
++
++When a 'readdir' request is made on a merged directory, the upper and
++lower directories are each read and the name lists merged in the
++obvious way (upper is read first, then lower - entries that already
++exist are not re-added).  This merged name list is cached in the
++'struct file' and so remains as long as the file is kept open.  If the
++directory is opened and read by two processes at the same time, they
++will each have separate caches.  A seekdir to the start of the
++directory (offset 0) followed by a readdir will cause the cache to be
++discarded and rebuilt.
++
++This means that changes to the merged directory do not appear while a
++directory is being read.  This is unlikely to be noticed by many
++programs.
++
++seek offsets are assigned sequentially when the directories are read.
++Thus if
++  - read part of a directory
++  - remember an offset, and close the directory
++  - re-open the directory some time later
++  - seek to the remembered offset
++
++there may be little correlation between the old and new locations in
++the list of filenames, particularly if anything has changed in the
++directory.
++
++Readdir on directories that are not merged is simply handled by the
++underlying directory (upper or lower).
++
++
++Non-directories
++---------------
++
++Objects that are not directories (files, symlinks, device-special
++files etc.) are presented either from the upper or lower filesystem as
++appropriate.  When a file in the lower filesystem is accessed in a way
++the requires write-access, such as opening for write access, changing
++some metadata etc., the file is first copied from the lower filesystem
++to the upper filesystem (copy_up).  Note that creating a hard-link
++also requires copy_up, though of course creation of a symlink does
++not.
++
++The copy_up may turn out to be unnecessary, for example if the file is
++opened for read-write but the data is not modified.
++
++The copy_up process first makes sure that the containing directory
++exists in the upper filesystem - creating it and any parents as
++necessary.  It then creates the object with the same metadata (owner,
++mode, mtime, symlink-target etc.) and then if the object is a file, the
++data is copied from the lower to the upper filesystem.  Finally any
++extended attributes are copied up.
++
++Once the copy_up is complete, the overlay filesystem simply
++provides direct access to the newly created file in the upper
++filesystem - future operations on the file are barely noticed by the
++overlay filesystem (though an operation on the name of the file such as
++rename or unlink will of course be noticed and handled).
++
++
++Non-standard behavior
++---------------------
++
++The copy_up operation essentially creates a new, identical file and
++moves it over to the old name.  The new file may be on a different
++filesystem, so both st_dev and st_ino of the file may change.
++
++Any open files referring to this inode will access the old data and
++metadata.  Similarly any file locks obtained before copy_up will not
++apply to the copied up file.
++
++On a file is opened with O_RDONLY fchmod(2), fchown(2), futimesat(2)
++and fsetxattr(2) will fail with EROFS.
++
++If a file with multiple hard links is copied up, then this will
++"break" the link.  Changes will not be propagated to other names
++referring to the same inode.
++
++Symlinks in /proc/PID/ and /proc/PID/fd which point to a non-directory
++object in overlayfs will not contain vaid absolute paths, only
++relative paths leading up to the filesystem's root.  This will be
++fixed in the future.
++
++Some operations are not atomic, for example a crash during copy_up or
++rename will leave the filesystem in an inconsitent state.  This will
++be addressed in the future.
++
++Changes to underlying filesystems
++---------------------------------
++
++Offline changes, when the overlay is not mounted, are allowed to either
++the upper or the lower trees.
++
++Changes to the underlying filesystems while part of a mounted overlay
++filesystem are not allowed.  If the underlying filesystem is changed,
++the behavior of the overlay is undefined, though it will not result in
++a crash or deadlock.
+diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
+index 0d04920..f06c91f 100644
+--- a/Documentation/filesystems/vfs.txt
++++ b/Documentation/filesystems/vfs.txt
+@@ -364,6 +364,8 @@ struct inode_operations {
+ 	ssize_t (*listxattr) (struct dentry *, char *, size_t);
+ 	int (*removexattr) (struct dentry *, const char *);
+ 	void (*truncate_range)(struct inode *, loff_t, loff_t);
++	struct file *(*open) (struct dentry *, struct file *,
++			      const struct cred *);
+ };
+ 
+ Again, all methods are called without any locks being held, unless
+@@ -475,6 +477,12 @@ otherwise noted.
+   truncate_range: a method provided by the underlying filesystem to truncate a
+   	range of blocks , i.e. punch a hole somewhere in a file.
+ 
++  open: this is an alternative to f_op->open(), the difference is that this
++	method may return any open file, not necessarily originating from the
++	same filesystem as the one i_op->open() was called on.  It may be useful
++	for stacking filesystems which want to allow native I/O directly on
++	underlying files.
++
+ 
+ The Address Space Object
+ ========================
+diff --git a/MAINTAINERS b/MAINTAINERS
+index b362709..7ba226c 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4998,6 +4998,13 @@ F:	drivers/scsi/osd/
+ F:	include/scsi/osd_*
+ F:	fs/exofs/
+ 
++OVERLAYFS FILESYSTEM
++M:	Miklos Szeredi <miklos@szeredi.hu>
++L:	linux-fsdevel@vger.kernel.org
++S:	Supported
++F:	fs/overlayfs/*
++F:	Documentation/filesystems/overlayfs.txt
++
+ P54 WIRELESS DRIVER
+ M:	Christian Lamparter <chunkeey@googlemail.com>
+ L:	linux-wireless@vger.kernel.org
+diff --git a/fs/Kconfig b/fs/Kconfig
+index f95ae3a..e0c5d43 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -67,6 +67,7 @@ source "fs/quota/Kconfig"
+ 
+ source "fs/autofs4/Kconfig"
+ source "fs/fuse/Kconfig"
++source "fs/overlayfs/Kconfig"
+ 
+ config CUSE
+ 	tristate "Character device in Userspace support"
+diff --git a/fs/Makefile b/fs/Makefile
+index 2fb9779..fcd9788 100644
+--- a/fs/Makefile
++++ b/fs/Makefile
+@@ -106,6 +106,7 @@ obj-$(CONFIG_QNX6FS_FS)		+= qnx6/
+ obj-$(CONFIG_AUTOFS4_FS)	+= autofs4/
+ obj-$(CONFIG_ADFS_FS)		+= adfs/
+ obj-$(CONFIG_FUSE_FS)		+= fuse/
++obj-$(CONFIG_OVERLAYFS_FS)	+= overlayfs/
+ obj-$(CONFIG_UDF_FS)		+= udf/
+ obj-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs/
+ obj-$(CONFIG_OMFS_FS)		+= omfs/
+diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
+index 6895493..c54ea90 100644
+--- a/fs/ecryptfs/main.c
++++ b/fs/ecryptfs/main.c
+@@ -544,6 +544,13 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
+ 	s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
+ 	s->s_blocksize = path.dentry->d_sb->s_blocksize;
+ 	s->s_magic = ECRYPTFS_SUPER_MAGIC;
++	s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1;
++
++	rc = -EINVAL;
++	if (s->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) {
++		printk(KERN_ERR "eCryptfs: maximum fs stacking depth exceeded\n");
++		goto out_free;
++	}
+ 
+ 	inode = ecryptfs_get_inode(path.dentry->d_inode, s);
+ 	rc = PTR_ERR(inode);
+diff --git a/fs/namei.c b/fs/namei.c
+index c427919..e172a5b 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -328,6 +328,36 @@ static inline int do_inode_permission(struct inode *inode, int mask)
+ }
+ 
+ /**
++ * inode_only_permission  -  check access rights to a given inode only
++ * @inode:	inode to check permissions on
++ * @mask:	right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...)
++ *
++ * Uses to check read/write/execute permissions on an inode directly, we do
++ * not check filesystem permissions.
++ */
++int inode_only_permission(struct inode *inode, int mask)
++{
++	int retval;
++
++	/*
++	 * Nobody gets write access to an immutable file.
++	 */
++	if (unlikely(mask & MAY_WRITE) && IS_IMMUTABLE(inode))
++		return -EACCES;
++
++	retval = do_inode_permission(inode, mask);
++	if (retval)
++		return retval;
++
++	retval = devcgroup_inode_permission(inode, mask);
++	if (retval)
++		return retval;
++
++	return security_inode_permission(inode, mask);
++}
++EXPORT_SYMBOL(inode_only_permission);
++
++/**
+  * inode_permission  -  check for access rights to a given inode
+  * @inode:	inode to check permission on
+  * @mask:	right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...)
+@@ -341,8 +371,6 @@ static inline int do_inode_permission(struct inode *inode, int mask)
+  */
+ int inode_permission(struct inode *inode, int mask)
+ {
+-	int retval;
+-
+ 	if (unlikely(mask & MAY_WRITE)) {
+ 		umode_t mode = inode->i_mode;
+ 
+@@ -352,23 +380,9 @@ int inode_permission(struct inode *inode, int mask)
+ 		if (IS_RDONLY(inode) &&
+ 		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
+ 			return -EROFS;
+-
+-		/*
+-		 * Nobody gets write access to an immutable file.
+-		 */
+-		if (IS_IMMUTABLE(inode))
+-			return -EACCES;
+ 	}
+ 
+-	retval = do_inode_permission(inode, mask);
+-	if (retval)
+-		return retval;
+-
+-	retval = devcgroup_inode_permission(inode, mask);
+-	if (retval)
+-		return retval;
+-
+-	return security_inode_permission(inode, mask);
++	return inode_only_permission(inode, mask);
+ }
+ 
+ /**
+diff --git a/fs/namespace.c b/fs/namespace.c
+index e608199..2551ec0 100644
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1325,6 +1325,24 @@ void drop_collected_mounts(struct vfsmount *mnt)
+ 	release_mounts(&umount_list);
+ }
+ 
++struct vfsmount *clone_private_mount(struct path *path)
++{
++	struct mount *old_mnt = real_mount(path->mnt);
++	struct mount *new_mnt;
++
++	if (IS_MNT_UNBINDABLE(old_mnt))
++		return ERR_PTR(-EINVAL);
++
++	down_read(&namespace_sem);
++	new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
++	up_read(&namespace_sem);
++	if (!new_mnt)
++		return ERR_PTR(-ENOMEM);
++
++	return &new_mnt->mnt;
++}
++EXPORT_SYMBOL_GPL(clone_private_mount);
++
+ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
+ 		   struct vfsmount *root)
+ {
+diff --git a/fs/open.c b/fs/open.c
+index 5720854..3e132ba 100644
+--- a/fs/open.c
++++ b/fs/open.c
+@@ -644,24 +644,24 @@ static inline int __get_file_write_access(struct inode *inode,
+ 	return error;
+ }
+ 
+-static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
+-					struct file *f,
+-					int (*open)(struct inode *, struct file *),
+-					const struct cred *cred)
++static struct file *__dentry_open(struct path *path, struct file *f,
++				  int (*open)(struct inode *, struct file *),
++				  const struct cred *cred)
+ {
+ 	static const struct file_operations empty_fops = {};
+ 	struct inode *inode;
+ 	int error;
+ 
++	path_get(path);
+ 	f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
+ 				FMODE_PREAD | FMODE_PWRITE;
+ 
+ 	if (unlikely(f->f_flags & O_PATH))
+ 		f->f_mode = FMODE_PATH;
+ 
+-	inode = dentry->d_inode;
++	inode = path->dentry->d_inode;
+ 	if (f->f_mode & FMODE_WRITE) {
+-		error = __get_file_write_access(inode, mnt);
++		error = __get_file_write_access(inode, path->mnt);
+ 		if (error)
+ 			goto cleanup_file;
+ 		if (!special_file(inode->i_mode))
+@@ -669,8 +669,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
+ 	}
+ 
+ 	f->f_mapping = inode->i_mapping;
+-	f->f_path.dentry = dentry;
+-	f->f_path.mnt = mnt;
++	f->f_path = *path;
+ 	f->f_pos = 0;
+ 	file_sb_list_add(f, inode->i_sb);
+ 
+@@ -727,7 +726,7 @@ cleanup_all:
+ 			 * here, so just reset the state.
+ 			 */
+ 			file_reset_write(f);
+-			mnt_drop_write(mnt);
++			mnt_drop_write(path->mnt);
+ 		}
+ 	}
+ 	file_sb_list_del(f);
+@@ -735,8 +734,7 @@ cleanup_all:
+ 	f->f_path.mnt = NULL;
+ cleanup_file:
+ 	put_filp(f);
+-	dput(dentry);
+-	mntput(mnt);
++	path_put(path);
+ 	return ERR_PTR(error);
+ }
+ 
+@@ -762,14 +760,14 @@ cleanup_file:
+ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
+ 		int (*open)(struct inode *, struct file *))
+ {
++	struct path path = { .dentry = dentry, .mnt = nd->path.mnt };
+ 	const struct cred *cred = current_cred();
+ 
+ 	if (IS_ERR(nd->intent.open.file))
+ 		goto out;
+ 	if (IS_ERR(dentry))
+ 		goto out_err;
+-	nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
+-					     nd->intent.open.file,
++	nd->intent.open.file = __dentry_open(&path, nd->intent.open.file,
+ 					     open, cred);
+ out:
+ 	return nd->intent.open.file;
+@@ -797,11 +795,9 @@ struct file *nameidata_to_filp(struct nameidata *nd)
+ 	nd->intent.open.file = NULL;
+ 
+ 	/* Has the filesystem initialised the file for us? */
+-	if (filp->f_path.dentry == NULL) {
+-		path_get(&nd->path);
+-		filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp,
+-				     NULL, cred);
+-	}
++	if (filp->f_path.dentry == NULL)
++		filp = vfs_open(&nd->path, filp, cred);
++
+ 	return filp;
+ }
+ 
+@@ -812,27 +808,48 @@ struct file *nameidata_to_filp(struct nameidata *nd)
+ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
+ 			 const struct cred *cred)
+ {
+-	int error;
+ 	struct file *f;
++	struct file *ret;
++	struct path path = { .dentry = dentry, .mnt = mnt };
+ 
+ 	validate_creds(cred);
+ 
+ 	/* We must always pass in a valid mount pointer. */
+ 	BUG_ON(!mnt);
+ 
+-	error = -ENFILE;
++	ret = ERR_PTR(-ENFILE);
+ 	f = get_empty_filp();
+-	if (f == NULL) {
+-		dput(dentry);
+-		mntput(mnt);
+-		return ERR_PTR(error);
++	if (f != NULL) {
++		f->f_flags = flags;
++		ret = vfs_open(&path, f, cred);
+ 	}
++	path_put(&path);
+ 
+-	f->f_flags = flags;
+-	return __dentry_open(dentry, mnt, f, NULL, cred);
++	return ret;
+ }
+ EXPORT_SYMBOL(dentry_open);
+ 
++/**
++ * vfs_open - open the file at the given path
++ * @path: path to open
++ * @filp: newly allocated file with f_flag initialized
++ * @cred: credentials to use
++ *
++ * Open the file.  If successful, the returned file will have acquired
++ * an additional reference for path.
++ */
++struct file *vfs_open(struct path *path, struct file *filp,
++		      const struct cred *cred)
++{
++	struct inode *inode = path->dentry->d_inode;
++
++	if (inode->i_op->open)
++		return inode->i_op->open(path->dentry, filp, cred);
++	else
++		return __dentry_open(path, filp, NULL, cred);
++}
++EXPORT_SYMBOL(vfs_open);
++
+ static void __put_unused_fd(struct files_struct *files, unsigned int fd)
+ {
+ 	struct fdtable *fdt = files_fdtable(files);
+diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig
+new file mode 100644
+index 0000000..c4517da
+--- /dev/null
++++ b/fs/overlayfs/Kconfig
+@@ -0,0 +1,4 @@
++config OVERLAYFS_FS
++	tristate "Overlay filesystem support"
++	help
++	  Add support for overlay filesystem.
+diff --git a/fs/overlayfs/Makefile b/fs/overlayfs/Makefile
+new file mode 100644
+index 0000000..8f91889
+--- /dev/null
++++ b/fs/overlayfs/Makefile
+@@ -0,0 +1,7 @@
++#
++# Makefile for the overlay filesystem.
++#
++
++obj-$(CONFIG_OVERLAYFS_FS) += overlayfs.o
++
++overlayfs-objs := super.o inode.o dir.o readdir.o copy_up.o
+diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
+new file mode 100644
+index 0000000..87dbeee
+--- /dev/null
++++ b/fs/overlayfs/copy_up.c
+@@ -0,0 +1,385 @@
++/*
++ *
++ * Copyright (C) 2011 Novell Inc.
++ *
++ * 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 <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/file.h>
++#include <linux/splice.h>
++#include <linux/xattr.h>
++#include <linux/security.h>
++#include <linux/uaccess.h>
++#include <linux/sched.h>
++#include "overlayfs.h"
++
++#define OVL_COPY_UP_CHUNK_SIZE (1 << 20)
++
++static int ovl_copy_up_xattr(struct dentry *old, struct dentry *new)
++{
++	ssize_t list_size, size;
++	char *buf, *name, *value;
++	int error;
++
++	if (!old->d_inode->i_op->getxattr ||
++	    !new->d_inode->i_op->getxattr)
++		return 0;
++
++	list_size = vfs_listxattr(old, NULL, 0);
++	if (list_size <= 0) {
++		if (list_size == -EOPNOTSUPP)
++			return 0;
++		return list_size;
++	}
++
++	buf = kzalloc(list_size, GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++
++	error = -ENOMEM;
++	value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL);
++	if (!value)
++		goto out;
++
++	list_size = vfs_listxattr(old, buf, list_size);
++	if (list_size <= 0) {
++		error = list_size;
++		goto out_free_value;
++	}
++
++	for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
++		size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX);
++		if (size <= 0) {
++			error = size;
++			goto out_free_value;
++		}
++		error = vfs_setxattr(new, name, value, size, 0);
++		if (error)
++			goto out_free_value;
++	}
++
++out_free_value:
++	kfree(value);
++out:
++	kfree(buf);
++	return error;
++}
++
++static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
++{
++	struct file *old_file;
++	struct file *new_file;
++	int error = 0;
++
++	if (len == 0)
++		return 0;
++
++	old_file = ovl_path_open(old, O_RDONLY);
++	if (IS_ERR(old_file))
++		return PTR_ERR(old_file);
++
++	new_file = ovl_path_open(new, O_WRONLY);
++	if (IS_ERR(new_file)) {
++		error = PTR_ERR(new_file);
++		goto out_fput;
++	}
++
++	/* FIXME: copy up sparse files efficiently */
++	while (len) {
++		loff_t offset = new_file->f_pos;
++		size_t this_len = OVL_COPY_UP_CHUNK_SIZE;
++		long bytes;
++
++		if (len < this_len)
++			this_len = len;
++
++		if (signal_pending_state(TASK_KILLABLE, current)) {
++			error = -EINTR;
++			break;
++		}
++
++		bytes = do_splice_direct(old_file, &offset, new_file, this_len,
++				 SPLICE_F_MOVE);
++		if (bytes <= 0) {
++			error = bytes;
++			break;
++		}
++
++		len -= bytes;
++	}
++
++	fput(new_file);
++out_fput:
++	fput(old_file);
++	return error;
++}
++
++static char *ovl_read_symlink(struct dentry *realdentry)
++{
++	int res;
++	char *buf;
++	struct inode *inode = realdentry->d_inode;
++	mm_segment_t old_fs;
++
++	res = -EINVAL;
++	if (!inode->i_op->readlink)
++		goto err;
++
++	res = -ENOMEM;
++	buf = (char *) __get_free_page(GFP_KERNEL);
++	if (!buf)
++		goto err;
++
++	old_fs = get_fs();
++	set_fs(get_ds());
++	/* The cast to a user pointer is valid due to the set_fs() */
++	res = inode->i_op->readlink(realdentry,
++				    (char __user *)buf, PAGE_SIZE - 1);
++	set_fs(old_fs);
++	if (res < 0) {
++		free_page((unsigned long) buf);
++		goto err;
++	}
++	buf[res] = '\0';
++
++	return buf;
++
++err:
++	return ERR_PTR(res);
++}
++
++static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat)
++{
++	struct iattr attr = {
++		.ia_valid =
++		     ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SET | ATTR_MTIME_SET,
++		.ia_atime = stat->atime,
++		.ia_mtime = stat->mtime,
++	};
++
++	return notify_change(upperdentry, &attr);
++}
++
++static int ovl_set_mode(struct dentry *upperdentry, umode_t mode)
++{
++	struct iattr attr = {
++		.ia_valid = ATTR_MODE,
++		.ia_mode = mode,
++	};
++
++	return notify_change(upperdentry, &attr);
++}
++
++static int ovl_copy_up_locked(struct dentry *upperdir, struct dentry *dentry,
++			      struct path *lowerpath, struct kstat *stat,
++			      const char *link)
++{
++	int err;
++	struct path newpath;
++	umode_t mode = stat->mode;
++
++	/* Can't properly set mode on creation because of the umask */
++	stat->mode &= S_IFMT;
++
++	ovl_path_upper(dentry, &newpath);
++	WARN_ON(newpath.dentry);
++	newpath.dentry = ovl_upper_create(upperdir, dentry, stat, link);
++	if (IS_ERR(newpath.dentry))
++		return PTR_ERR(newpath.dentry);
++
++	if (S_ISREG(stat->mode)) {
++		err = ovl_copy_up_data(lowerpath, &newpath, stat->size);
++		if (err)
++			goto err_remove;
++	}
++
++	err = ovl_copy_up_xattr(lowerpath->dentry, newpath.dentry);
++	if (err)
++		goto err_remove;
++
++	mutex_lock(&newpath.dentry->d_inode->i_mutex);
++	if (!S_ISLNK(stat->mode))
++		err = ovl_set_mode(newpath.dentry, mode);
++	if (!err)
++		err = ovl_set_timestamps(newpath.dentry, stat);
++	mutex_unlock(&newpath.dentry->d_inode->i_mutex);
++	if (err)
++		goto err_remove;
++
++	ovl_dentry_update(dentry, newpath.dentry);
++
++	/*
++	 * Easiest way to get rid of the lower dentry reference is to
++	 * drop this dentry.  This is neither needed nor possible for
++	 * directories.
++	 */
++	if (!S_ISDIR(stat->mode))
++		d_drop(dentry);
++
++	return 0;
++
++err_remove:
++	if (S_ISDIR(stat->mode))
++		vfs_rmdir(upperdir->d_inode, newpath.dentry);
++	else
++		vfs_unlink(upperdir->d_inode, newpath.dentry);
++
++	dput(newpath.dentry);
++
++	return err;
++}
++
++/*
++ * Copy up a single dentry
++ *
++ * Directory renames only allowed on "pure upper" (already created on
++ * upper filesystem, never copied up).  Directories which are on lower or
++ * are merged may not be renamed.  For these -EXDEV is returned and
++ * userspace has to deal with it.  This means, when copying up a
++ * directory we can rely on it and ancestors being stable.
++ *
++ * Non-directory renames start with copy up of source if necessary.  The
++ * actual rename will only proceed once the copy up was successful.  Copy
++ * up uses upper parent i_mutex for exclusion.  Since rename can change
++ * d_parent it is possible that the copy up will lock the old parent.  At
++ * that point the file will have already been copied up anyway.
++ */
++static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
++			   struct path *lowerpath, struct kstat *stat)
++{
++	int err;
++	struct kstat pstat;
++	struct path parentpath;
++	struct dentry *upperdir;
++	const struct cred *old_cred;
++	struct cred *override_cred;
++	char *link = NULL;
++
++	ovl_path_upper(parent, &parentpath);
++	upperdir = parentpath.dentry;
++
++	err = vfs_getattr(parentpath.mnt, parentpath.dentry, &pstat);
++	if (err)
++		return err;
++
++	if (S_ISLNK(stat->mode)) {
++		link = ovl_read_symlink(lowerpath->dentry);
++		if (IS_ERR(link))
++			return PTR_ERR(link);
++	}
++
++	err = -ENOMEM;
++	override_cred = prepare_creds();
++	if (!override_cred)
++		goto out_free_link;
++
++	override_cred->fsuid = stat->uid;
++	override_cred->fsgid = stat->gid;
++	/*
++	 * CAP_SYS_ADMIN for copying up extended attributes
++	 * CAP_DAC_OVERRIDE for create
++	 * CAP_FOWNER for chmod, timestamp update
++	 * CAP_FSETID for chmod
++	 * CAP_MKNOD for mknod
++	 */
++	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
++	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
++	cap_raise(override_cred->cap_effective, CAP_FOWNER);
++	cap_raise(override_cred->cap_effective, CAP_FSETID);
++	cap_raise(override_cred->cap_effective, CAP_MKNOD);
++	old_cred = override_creds(override_cred);
++
++	mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT);
++	if (ovl_path_type(dentry) != OVL_PATH_LOWER) {
++		err = 0;
++	} else {
++		err = ovl_copy_up_locked(upperdir, dentry, lowerpath,
++					 stat, link);
++		if (!err) {
++			/* Restore timestamps on parent (best effort) */
++			ovl_set_timestamps(upperdir, &pstat);
++		}
++	}
++
++	mutex_unlock(&upperdir->d_inode->i_mutex);
++
++	revert_creds(old_cred);
++	put_cred(override_cred);
++
++out_free_link:
++	if (link)
++		free_page((unsigned long) link);
++
++	return err;
++}
++
++int ovl_copy_up(struct dentry *dentry)
++{
++	int err;
++
++	err = 0;
++	while (!err) {
++		struct dentry *next;
++		struct dentry *parent;
++		struct path lowerpath;
++		struct kstat stat;
++		enum ovl_path_type type = ovl_path_type(dentry);
++
++		if (type != OVL_PATH_LOWER)
++			break;
++
++		next = dget(dentry);
++		/* find the topmost dentry not yet copied up */
++		for (;;) {
++			parent = dget_parent(next);
++
++			type = ovl_path_type(parent);
++			if (type != OVL_PATH_LOWER)
++				break;
++
++			dput(next);
++			next = parent;
++		}
++
++		ovl_path_lower(next, &lowerpath);
++		err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat);
++		if (!err)
++			err = ovl_copy_up_one(parent, next, &lowerpath, &stat);
++
++		dput(parent);
++		dput(next);
++	}
++
++	return err;
++}
++
++/* Optimize by not copying up the file first and truncating later */
++int ovl_copy_up_truncate(struct dentry *dentry, loff_t size)
++{
++	int err;
++	struct kstat stat;
++	struct path lowerpath;
++	struct dentry *parent = dget_parent(dentry);
++
++	err = ovl_copy_up(parent);
++	if (err)
++		goto out_dput_parent;
++
++	ovl_path_lower(dentry, &lowerpath);
++	err = vfs_getattr(lowerpath.mnt, lowerpath.dentry, &stat);
++	if (err)
++		goto out_dput_parent;
++
++	if (size < stat.size)
++		stat.size = size;
++
++	err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
++
++out_dput_parent:
++	dput(parent);
++	return err;
++}
+diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
+new file mode 100644
+index 0000000..c914c97
+--- /dev/null
++++ b/fs/overlayfs/dir.c
+@@ -0,0 +1,602 @@
++/*
++ *
++ * Copyright (C) 2011 Novell Inc.
++ *
++ * 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 <linux/fs.h>
++#include <linux/namei.h>
++#include <linux/xattr.h>
++#include <linux/security.h>
++#include <linux/cred.h>
++#include "overlayfs.h"
++
++static const char *ovl_whiteout_symlink = "(overlay-whiteout)";
++
++static int ovl_whiteout(struct dentry *upperdir, struct dentry *dentry)
++{
++	int err;
++	struct dentry *newdentry;
++	const struct cred *old_cred;
++	struct cred *override_cred;
++
++	/* FIXME: recheck lower dentry to see if whiteout is really needed */
++
++	err = -ENOMEM;
++	override_cred = prepare_creds();
++	if (!override_cred)
++		goto out;
++
++	/*
++	 * CAP_SYS_ADMIN for setxattr
++	 * CAP_DAC_OVERRIDE for symlink creation
++	 * CAP_FOWNER for unlink in sticky directory
++	 */
++	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
++	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
++	cap_raise(override_cred->cap_effective, CAP_FOWNER);
++	override_cred->fsuid = 0;
++	override_cred->fsgid = 0;
++	old_cred = override_creds(override_cred);
++
++	newdentry = lookup_one_len(dentry->d_name.name, upperdir,
++				   dentry->d_name.len);
++	err = PTR_ERR(newdentry);
++	if (IS_ERR(newdentry))
++		goto out_put_cred;
++
++	/* Just been removed within the same locked region */
++	WARN_ON(newdentry->d_inode);
++
++	err = vfs_symlink(upperdir->d_inode, newdentry, ovl_whiteout_symlink);
++	if (err)
++		goto out_dput;
++
++	ovl_dentry_version_inc(dentry->d_parent);
++
++	err = vfs_setxattr(newdentry, ovl_whiteout_xattr, "y", 1, 0);
++	if (err)
++		vfs_unlink(upperdir->d_inode, newdentry);
++
++out_dput:
++	dput(newdentry);
++out_put_cred:
++	revert_creds(old_cred);
++	put_cred(override_cred);
++out:
++	if (err) {
++		/*
++		 * There's no way to recover from failure to whiteout.
++		 * What should we do?  Log a big fat error and... ?
++		 */
++		printk(KERN_ERR "overlayfs: ERROR - failed to whiteout '%s'\n",
++		       dentry->d_name.name);
++	}
++
++	return err;
++}
++
++static struct dentry *ovl_lookup_create(struct dentry *upperdir,
++					struct dentry *template)
++{
++	int err;
++	struct dentry *newdentry;
++	struct qstr *name = &template->d_name;
++
++	newdentry = lookup_one_len(name->name, upperdir, name->len);
++	if (IS_ERR(newdentry))
++		return newdentry;
++
++	if (newdentry->d_inode) {
++		const struct cred *old_cred;
++		struct cred *override_cred;
++
++		/* No need to check whiteout if lower parent is non-existent */
++		err = -EEXIST;
++		if (!ovl_dentry_lower(template->d_parent))
++			goto out_dput;
++
++		if (!S_ISLNK(newdentry->d_inode->i_mode))
++			goto out_dput;
++
++		err = -ENOMEM;
++		override_cred = prepare_creds();
++		if (!override_cred)
++			goto out_dput;
++
++		/*
++		 * CAP_SYS_ADMIN for getxattr
++		 * CAP_FOWNER for unlink in sticky directory
++		 */
++		cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
++		cap_raise(override_cred->cap_effective, CAP_FOWNER);
++		old_cred = override_creds(override_cred);
++
++		err = -EEXIST;
++		if (ovl_is_whiteout(newdentry))
++			err = vfs_unlink(upperdir->d_inode, newdentry);
++
++		revert_creds(old_cred);
++		put_cred(override_cred);
++		if (err)
++			goto out_dput;
++
++		dput(newdentry);
++		newdentry = lookup_one_len(name->name, upperdir, name->len);
++		if (IS_ERR(newdentry)) {
++			ovl_whiteout(upperdir, template);
++			return newdentry;
++		}
++
++		/*
++		 * Whiteout just been successfully removed, parent
++		 * i_mutex is still held, there's no way the lookup
++		 * could return positive.
++		 */
++		WARN_ON(newdentry->d_inode);
++	}
++
++	return newdentry;
++
++out_dput:
++	dput(newdentry);
++	return ERR_PTR(err);
++}
++
++struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry,
++				struct kstat *stat, const char *link)
++{
++	int err;
++	struct dentry *newdentry;
++	struct inode *dir = upperdir->d_inode;
++
++	newdentry = ovl_lookup_create(upperdir, dentry);
++	if (IS_ERR(newdentry))
++		goto out;
++
++	switch (stat->mode & S_IFMT) {
++	case S_IFREG:
++		err = vfs_create(dir, newdentry, stat->mode, NULL);
++		break;
++
++	case S_IFDIR:
++		err = vfs_mkdir(dir, newdentry, stat->mode);
++		break;
++
++	case S_IFCHR:
++	case S_IFBLK:
++	case S_IFIFO:
++	case S_IFSOCK:
++		err = vfs_mknod(dir, newdentry, stat->mode, stat->rdev);
++		break;
++
++	case S_IFLNK:
++		err = vfs_symlink(dir, newdentry, link);
++		break;
++
++	default:
++		err = -EPERM;
++	}
++	if (err) {
++		if (ovl_dentry_is_opaque(dentry))
++			ovl_whiteout(upperdir, dentry);
++		dput(newdentry);
++		newdentry = ERR_PTR(err);
++	} else if (WARN_ON(!newdentry->d_inode)) {
++		/*
++		 * Not quite sure if non-instantiated dentry is legal or not.
++		 * VFS doesn't seem to care so check and warn here.
++		 */
++		dput(newdentry);
++		newdentry = ERR_PTR(-ENOENT);
++	}
++
++out:
++	return newdentry;
++
++}
++
++static int ovl_set_opaque(struct dentry *upperdentry)
++{
++	int err;
++	const struct cred *old_cred;
++	struct cred *override_cred;
++
++	override_cred = prepare_creds();
++	if (!override_cred)
++		return -ENOMEM;
++
++	/* CAP_SYS_ADMIN for setxattr of "trusted" namespace */
++	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
++	old_cred = override_creds(override_cred);
++	err = vfs_setxattr(upperdentry, ovl_opaque_xattr, "y", 1, 0);
++	revert_creds(old_cred);
++	put_cred(override_cred);
++
++	return err;
++}
++
++static int ovl_remove_opaque(struct dentry *upperdentry)
++{
++	int err;
++	const struct cred *old_cred;
++	struct cred *override_cred;
++
++	override_cred = prepare_creds();
++	if (!override_cred)
++		return -ENOMEM;
++
++	/* CAP_SYS_ADMIN for removexattr of "trusted" namespace */
++	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
++	old_cred = override_creds(override_cred);
++	err = vfs_removexattr(upperdentry, ovl_opaque_xattr);
++	revert_creds(old_cred);
++	put_cred(override_cred);
++
++	return err;
++}
++
++static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
++			 struct kstat *stat)
++{
++	int err;
++	enum ovl_path_type type;
++	struct path realpath;
++
++	type = ovl_path_real(dentry, &realpath);
++	err = vfs_getattr(realpath.mnt, realpath.dentry, stat);
++	if (err)
++		return err;
++
++	stat->dev = dentry->d_sb->s_dev;
++	stat->ino = dentry->d_inode->i_ino;
++
++	/*
++	 * It's probably not worth it to count subdirs to get the
++	 * correct link count.  nlink=1 seems to pacify 'find' and
++	 * other utilities.
++	 */
++	if (type == OVL_PATH_MERGE)
++		stat->nlink = 1;
++
++	return 0;
++}
++
++static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
++			     const char *link)
++{
++	int err;
++	struct dentry *newdentry;
++	struct dentry *upperdir;
++	struct inode *inode;
++	struct kstat stat = {
++		.mode = mode,
++		.rdev = rdev,
++	};
++
++	err = -ENOMEM;
++	inode = ovl_new_inode(dentry->d_sb, mode, dentry->d_fsdata);
++	if (!inode)
++		goto out;
++
++	err = ovl_copy_up(dentry->d_parent);
++	if (err)
++		goto out_iput;
++
++	upperdir = ovl_dentry_upper(dentry->d_parent);
++	mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT);
++
++	newdentry = ovl_upper_create(upperdir, dentry, &stat, link);
++	err = PTR_ERR(newdentry);
++	if (IS_ERR(newdentry))
++		goto out_unlock;
++
++	ovl_dentry_version_inc(dentry->d_parent);
++	if (ovl_dentry_is_opaque(dentry) && S_ISDIR(mode)) {
++		err = ovl_set_opaque(newdentry);
++		if (err) {
++			vfs_rmdir(upperdir->d_inode, newdentry);
++			ovl_whiteout(upperdir, dentry);
++			goto out_dput;
++		}
++	}
++	ovl_dentry_update(dentry, newdentry);
++	d_instantiate(dentry, inode);
++	inode = NULL;
++	newdentry = NULL;
++	err = 0;
++
++out_dput:
++	dput(newdentry);
++out_unlock:
++	mutex_unlock(&upperdir->d_inode->i_mutex);
++out_iput:
++	iput(inode);
++out:
++	return err;
++}
++
++static int ovl_create(struct inode *dir, struct dentry *dentry, umode_t mode,
++			struct nameidata *nd)
++{
++	return ovl_create_object(dentry, (mode & 07777) | S_IFREG, 0, NULL);
++}
++
++static int ovl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
++{
++	return ovl_create_object(dentry, (mode & 07777) | S_IFDIR, 0, NULL);
++}
++
++static int ovl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
++		     dev_t rdev)
++{
++	return ovl_create_object(dentry, mode, rdev, NULL);
++}
++
++static int ovl_symlink(struct inode *dir, struct dentry *dentry,
++			 const char *link)
++{
++	return ovl_create_object(dentry, S_IFLNK, 0, link);
++}
++
++static int ovl_do_remove(struct dentry *dentry, bool is_dir)
++{
++	int err;
++	enum ovl_path_type type;
++	struct path realpath;
++	struct dentry *upperdir;
++
++	err = ovl_copy_up(dentry->d_parent);
++	if (err)
++		return err;
++
++	upperdir = ovl_dentry_upper(dentry->d_parent);
++	mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT);
++	type = ovl_path_real(dentry, &realpath);
++	if (type != OVL_PATH_LOWER) {
++		err = -ESTALE;
++		if (realpath.dentry->d_parent != upperdir)
++			goto out_d_drop;
++
++		/* FIXME: create whiteout up front and rename to target */
++
++		if (is_dir)
++			err = vfs_rmdir(upperdir->d_inode, realpath.dentry);
++		else
++			err = vfs_unlink(upperdir->d_inode, realpath.dentry);
++		if (err)
++			goto out_d_drop;
++
++		ovl_dentry_version_inc(dentry->d_parent);
++	}
++
++	if (type != OVL_PATH_UPPER || ovl_dentry_is_opaque(dentry))
++		err = ovl_whiteout(upperdir, dentry);
++
++	/*
++	 * Keeping this dentry hashed would mean having to release
++	 * upperpath/lowerpath, which could only be done if we are the
++	 * sole user of this dentry.  Too tricky...  Just unhash for
++	 * now.
++	 */
++out_d_drop:
++	d_drop(dentry);
++	mutex_unlock(&upperdir->d_inode->i_mutex);
++
++	return err;
++}
++
++static int ovl_unlink(struct inode *dir, struct dentry *dentry)
++{
++	return ovl_do_remove(dentry, false);
++}
++
++
++static int ovl_rmdir(struct inode *dir, struct dentry *dentry)
++{
++	int err;
++	enum ovl_path_type type;
++
++	type = ovl_path_type(dentry);
++	if (type != OVL_PATH_UPPER) {
++		err = ovl_check_empty_and_clear(dentry, type);
++		if (err)
++			return err;
++	}
++
++	return ovl_do_remove(dentry, true);
++}
++
++static int ovl_link(struct dentry *old, struct inode *newdir,
++		    struct dentry *new)
++{
++	int err;
++	struct dentry *olddentry;
++	struct dentry *newdentry;
++	struct dentry *upperdir;
++	struct inode *newinode;
++
++	err = ovl_copy_up(old);
++	if (err)
++		goto out;
++
++	err = ovl_copy_up(new->d_parent);
++	if (err)
++		goto out;
++
++	upperdir = ovl_dentry_upper(new->d_parent);
++	mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT);
++	newdentry = ovl_lookup_create(upperdir, new);
++	err = PTR_ERR(newdentry);
++	if (IS_ERR(newdentry))
++		goto out_unlock;
++
++	olddentry = ovl_dentry_upper(old);
++	err = vfs_link(olddentry, upperdir->d_inode, newdentry);
++	if (!err) {
++		if (WARN_ON(!newdentry->d_inode)) {
++			dput(newdentry);
++			err = -ENOENT;
++			goto out_unlock;
++		}
++		newinode = ovl_new_inode(old->d_sb, newdentry->d_inode->i_mode,
++				new->d_fsdata);
++		if (!newinode)
++			goto link_fail;
++
++		ovl_dentry_version_inc(new->d_parent);
++		ovl_dentry_update(new, newdentry);
++
++		d_instantiate(new, newinode);
++	} else {
++link_fail:
++		if (ovl_dentry_is_opaque(new))
++			ovl_whiteout(upperdir, new);
++		dput(newdentry);
++	}
++out_unlock:
++	mutex_unlock(&upperdir->d_inode->i_mutex);
++out:
++	return err;
++
++}
++
++static int ovl_rename(struct inode *olddir, struct dentry *old,
++			struct inode *newdir, struct dentry *new)
++{
++	int err;
++	enum ovl_path_type old_type;
++	enum ovl_path_type new_type;
++	struct dentry *old_upperdir;
++	struct dentry *new_upperdir;
++	struct dentry *olddentry;
++	struct dentry *newdentry;
++	struct dentry *trap;
++	bool old_opaque;
++	bool new_opaque;
++	bool new_create = false;
++	bool is_dir = S_ISDIR(old->d_inode->i_mode);
++
++	/* Don't copy up directory trees */
++	old_type = ovl_path_type(old);
++	if (old_type != OVL_PATH_UPPER && is_dir)
++		return -EXDEV;
++
++	if (new->d_inode) {
++		new_type = ovl_path_type(new);
++
++		if (new_type == OVL_PATH_LOWER && old_type == OVL_PATH_LOWER) {
++			if (ovl_dentry_lower(old)->d_inode ==
++			    ovl_dentry_lower(new)->d_inode)
++				return 0;
++		}
++		if (new_type != OVL_PATH_LOWER && old_type != OVL_PATH_LOWER) {
++			if (ovl_dentry_upper(old)->d_inode ==
++			    ovl_dentry_upper(new)->d_inode)
++				return 0;
++		}
++
++		if (new_type != OVL_PATH_UPPER &&
++		    S_ISDIR(new->d_inode->i_mode)) {
++			err = ovl_check_empty_and_clear(new, new_type);
++			if (err)
++				return err;
++		}
++	} else {
++		new_type = OVL_PATH_UPPER;
++	}
++
++	err = ovl_copy_up(old);
++	if (err)
++		return err;
++
++	err = ovl_copy_up(new->d_parent);
++	if (err)
++		return err;
++
++	old_upperdir = ovl_dentry_upper(old->d_parent);
++	new_upperdir = ovl_dentry_upper(new->d_parent);
++
++	trap = lock_rename(new_upperdir, old_upperdir);
++
++	olddentry = ovl_dentry_upper(old);
++	newdentry = ovl_dentry_upper(new);
++	if (newdentry) {
++		dget(newdentry);
++	} else {
++		new_create = true;
++		newdentry = ovl_lookup_create(new_upperdir, new);
++		err = PTR_ERR(newdentry);
++		if (IS_ERR(newdentry))
++			goto out_unlock;
++	}
++
++	err = -ESTALE;
++	if (olddentry->d_parent != old_upperdir)
++		goto out_dput;
++	if (newdentry->d_parent != new_upperdir)
++		goto out_dput;
++	if (olddentry == trap)
++		goto out_dput;
++	if (newdentry == trap)
++		goto out_dput;
++
++	old_opaque = ovl_dentry_is_opaque(old);
++	new_opaque = ovl_dentry_is_opaque(new) || new_type != OVL_PATH_UPPER;
++
++	if (is_dir && !old_opaque && new_opaque) {
++		err = ovl_set_opaque(olddentry);
++		if (err)
++			goto out_dput;
++	}
++
++	err = vfs_rename(old_upperdir->d_inode, olddentry,
++			 new_upperdir->d_inode, newdentry);
++
++	if (err) {
++		if (new_create && ovl_dentry_is_opaque(new))
++			ovl_whiteout(new_upperdir, new);
++		if (is_dir && !old_opaque && new_opaque)
++			ovl_remove_opaque(olddentry);
++		goto out_dput;
++	}
++
++	if (old_type != OVL_PATH_UPPER || old_opaque)
++		err = ovl_whiteout(old_upperdir, old);
++	if (is_dir && old_opaque && !new_opaque)
++		ovl_remove_opaque(olddentry);
++
++	if (old_opaque != new_opaque)
++		ovl_dentry_set_opaque(old, new_opaque);
++
++	ovl_dentry_version_inc(old->d_parent);
++	ovl_dentry_version_inc(new->d_parent);
++
++out_dput:
++	dput(newdentry);
++out_unlock:
++	unlock_rename(new_upperdir, old_upperdir);
++	return err;
++}
++
++const struct inode_operations ovl_dir_inode_operations = {
++	.lookup		= ovl_lookup,
++	.mkdir		= ovl_mkdir,
++	.symlink	= ovl_symlink,
++	.unlink		= ovl_unlink,
++	.rmdir		= ovl_rmdir,
++	.rename		= ovl_rename,
++	.link		= ovl_link,
++	.setattr	= ovl_setattr,
++	.create		= ovl_create,
++	.mknod		= ovl_mknod,
++	.permission	= ovl_permission,
++	.getattr	= ovl_dir_getattr,
++	.setxattr	= ovl_setxattr,
++	.getxattr	= ovl_getxattr,
++	.listxattr	= ovl_listxattr,
++	.removexattr	= ovl_removexattr,
++};
+diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
+new file mode 100644
+index 0000000..1a8e232
+--- /dev/null
++++ b/fs/overlayfs/inode.c
+@@ -0,0 +1,375 @@
++/*
++ *
++ * Copyright (C) 2011 Novell Inc.
++ *
++ * 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 <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/xattr.h>
++#include "overlayfs.h"
++
++int ovl_setattr(struct dentry *dentry, struct iattr *attr)
++{
++	struct dentry *upperdentry;
++	int err;
++
++	if ((attr->ia_valid & ATTR_SIZE) && !ovl_dentry_upper(dentry))
++		err = ovl_copy_up_truncate(dentry, attr->ia_size);
++	else
++		err = ovl_copy_up(dentry);
++	if (err)
++		return err;
++
++	upperdentry = ovl_dentry_upper(dentry);
++
++	if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
++		attr->ia_valid &= ~ATTR_MODE;
++
++	mutex_lock(&upperdentry->d_inode->i_mutex);
++	err = notify_change(upperdentry, attr);
++	mutex_unlock(&upperdentry->d_inode->i_mutex);
++
++	return err;
++}
++
++static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
++			 struct kstat *stat)
++{
++	struct path realpath;
++
++	ovl_path_real(dentry, &realpath);
++	return vfs_getattr(realpath.mnt, realpath.dentry, stat);
++}
++
++int ovl_permission(struct inode *inode, int mask)
++{
++	struct ovl_entry *oe;
++	struct dentry *alias = NULL;
++	struct inode *realinode;
++	struct dentry *realdentry;
++	bool is_upper;
++	int err;
++
++	if (S_ISDIR(inode->i_mode)) {
++		oe = inode->i_private;
++	} else if (mask & MAY_NOT_BLOCK) {
++		return -ECHILD;
++	} else {
++		/*
++		 * For non-directories find an alias and get the info
++		 * from there.
++		 */
++		spin_lock(&inode->i_lock);
++		if (WARN_ON(list_empty(&inode->i_dentry))) {
++			spin_unlock(&inode->i_lock);
++			return -ENOENT;
++		}
++		alias = list_entry(inode->i_dentry.next,
++				   struct dentry, d_alias);
++		dget(alias);
++		spin_unlock(&inode->i_lock);
++		oe = alias->d_fsdata;
++	}
++
++	realdentry = ovl_entry_real(oe, &is_upper);
++
++	/* Careful in RCU walk mode */
++	realinode = ACCESS_ONCE(realdentry->d_inode);
++	if (!realinode) {
++		WARN_ON(!(mask & MAY_NOT_BLOCK));
++		err = -ENOENT;
++		goto out_dput;
++	}
++
++	if (mask & MAY_WRITE) {
++		umode_t mode = realinode->i_mode;
++
++		/*
++		 * Writes will always be redirected to upper layer, so
++		 * ignore lower layer being read-only.
++		 *
++		 * If the overlay itself is read-only then proceed
++		 * with the permission check, don't return EROFS.
++		 * This will only happen if this is the lower layer of
++		 * another overlayfs.
++		 *
++		 * If upper fs becomes read-only after the overlay was
++		 * constructed return EROFS to prevent modification of
++		 * upper layer.
++		 */
++		err = -EROFS;
++		if (is_upper && !IS_RDONLY(inode) && IS_RDONLY(realinode) &&
++		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
++			goto out_dput;
++	}
++
++	err = inode_only_permission(realinode, mask);
++out_dput:
++	dput(alias);
++	return err;
++}
++
++
++struct ovl_link_data {
++	struct dentry *realdentry;
++	void *cookie;
++};
++
++static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++	void *ret;
++	struct dentry *realdentry;
++	struct inode *realinode;
++
++	realdentry = ovl_dentry_real(dentry);
++	realinode = realdentry->d_inode;
++
++	if (WARN_ON(!realinode->i_op->follow_link))
++		return ERR_PTR(-EPERM);
++
++	ret = realinode->i_op->follow_link(realdentry, nd);
++	if (IS_ERR(ret))
++		return ret;
++
++	if (realinode->i_op->put_link) {
++		struct ovl_link_data *data;
++
++		data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL);
++		if (!data) {
++			realinode->i_op->put_link(realdentry, nd, ret);
++			return ERR_PTR(-ENOMEM);
++		}
++		data->realdentry = realdentry;
++		data->cookie = ret;
++
++		return data;
++	} else {
++		return NULL;
++	}
++}
++
++static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
++{
++	struct inode *realinode;
++	struct ovl_link_data *data = c;
++
++	if (!data)
++		return;
++
++	realinode = data->realdentry->d_inode;
++	realinode->i_op->put_link(data->realdentry, nd, data->cookie);
++	kfree(data);
++}
++
++static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
++{
++	struct path realpath;
++	struct inode *realinode;
++
++	ovl_path_real(dentry, &realpath);
++	realinode = realpath.dentry->d_inode;
++
++	if (!realinode->i_op->readlink)
++		return -EINVAL;
++
++	//touch_atime(&realpath);
++
++	return realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
++}
++
++
++static bool ovl_is_private_xattr(const char *name)
++{
++	return strncmp(name, "trusted.overlay.", 14) == 0;
++}
++
++int ovl_setxattr(struct dentry *dentry, const char *name,
++		 const void *value, size_t size, int flags)
++{
++	int err;
++	struct dentry *upperdentry;
++
++	if (ovl_is_private_xattr(name))
++		return -EPERM;
++
++	err = ovl_copy_up(dentry);
++	if (err)
++		return err;
++
++	upperdentry = ovl_dentry_upper(dentry);
++	return  vfs_setxattr(upperdentry, name, value, size, flags);
++}
++
++ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
++		     void *value, size_t size)
++{
++	if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
++	    ovl_is_private_xattr(name))
++		return -ENODATA;
++
++	return vfs_getxattr(ovl_dentry_real(dentry), name, value, size);
++}
++
++ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
++{
++	ssize_t res;
++	int off;
++
++	res = vfs_listxattr(ovl_dentry_real(dentry), list, size);
++	if (res <= 0 || size == 0)
++		return res;
++
++	if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE)
++		return res;
++
++	/* filter out private xattrs */
++	for (off = 0; off < res;) {
++		char *s = list + off;
++		size_t slen = strlen(s) + 1;
++
++		BUG_ON(off + slen > res);
++
++		if (ovl_is_private_xattr(s)) {
++			res -= slen;
++			memmove(s, s + slen, res - off);
++		} else {
++			off += slen;
++		}
++	}
++
++	return res;
++}
++
++int ovl_removexattr(struct dentry *dentry, const char *name)
++{
++	int err;
++	struct path realpath;
++	enum ovl_path_type type;
++
++	if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
++	    ovl_is_private_xattr(name))
++		return -ENODATA;
++
++	type = ovl_path_real(dentry, &realpath);
++	if (type == OVL_PATH_LOWER) {
++		err = vfs_getxattr(realpath.dentry, name, NULL, 0);
++		if (err < 0)
++			return err;
++
++		err = ovl_copy_up(dentry);
++		if (err)
++			return err;
++
++		ovl_path_upper(dentry, &realpath);
++	}
++
++	return vfs_removexattr(realpath.dentry, name);
++}
++
++static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type,
++				  struct dentry *realdentry)
++{
++	if (type != OVL_PATH_LOWER)
++		return false;
++
++	if (special_file(realdentry->d_inode->i_mode))
++		return false;
++
++	if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC))
++		return false;
++
++	return true;
++}
++
++static struct file *ovl_open(struct dentry *dentry, struct file *file,
++			     const struct cred *cred)
++{
++	int err;
++	struct path realpath;
++	enum ovl_path_type type;
++
++	type = ovl_path_real(dentry, &realpath);
++	if (ovl_open_need_copy_up(file->f_flags, type, realpath.dentry)) {
++		if (file->f_flags & O_TRUNC)
++			err = ovl_copy_up_truncate(dentry, 0);
++		else
++			err = ovl_copy_up(dentry);
++		if (err)
++			return ERR_PTR(err);
++
++		ovl_path_upper(dentry, &realpath);
++	}
++
++	return vfs_open(&realpath, file, cred);
++}
++
++static const struct inode_operations ovl_file_inode_operations = {
++	.setattr	= ovl_setattr,
++	.permission	= ovl_permission,
++	.getattr	= ovl_getattr,
++	.setxattr	= ovl_setxattr,
++	.getxattr	= ovl_getxattr,
++	.listxattr	= ovl_listxattr,
++	.removexattr	= ovl_removexattr,
++	.open		= ovl_open,
++};
++
++static const struct inode_operations ovl_symlink_inode_operations = {
++	.setattr	= ovl_setattr,
++	.follow_link	= ovl_follow_link,
++	.put_link	= ovl_put_link,
++	.readlink	= ovl_readlink,
++	.getattr	= ovl_getattr,
++	.setxattr	= ovl_setxattr,
++	.getxattr	= ovl_getxattr,
++	.listxattr	= ovl_listxattr,
++	.removexattr	= ovl_removexattr,
++};
++
++struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
++			    struct ovl_entry *oe)
++{
++	struct inode *inode;
++
++	inode = new_inode(sb);
++	if (!inode)
++		return NULL;
++
++	mode &= S_IFMT;
++
++	inode->i_ino = get_next_ino();
++	inode->i_mode = mode;
++	inode->i_flags |= S_NOATIME | S_NOCMTIME;
++
++	switch (mode) {
++	case S_IFDIR:
++		inode->i_private = oe;
++		inode->i_op = &ovl_dir_inode_operations;
++		inode->i_fop = &ovl_dir_operations;
++		break;
++
++	case S_IFLNK:
++		inode->i_op = &ovl_symlink_inode_operations;
++		break;
++
++	case S_IFREG:
++	case S_IFSOCK:
++	case S_IFBLK:
++	case S_IFCHR:
++	case S_IFIFO:
++		inode->i_op = &ovl_file_inode_operations;
++		break;
++
++	default:
++		WARN(1, "illegal file type: %i\n", mode);
++		iput(inode);
++		inode = NULL;
++	}
++
++	return inode;
++
++}
+diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
+new file mode 100644
+index 0000000..1dd05f7
+--- /dev/null
++++ b/fs/overlayfs/overlayfs.h
+@@ -0,0 +1,64 @@
++/*
++ *
++ * Copyright (C) 2011 Novell Inc.
++ *
++ * 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.
++ */
++
++struct ovl_entry;
++
++enum ovl_path_type {
++	OVL_PATH_UPPER,
++	OVL_PATH_MERGE,
++	OVL_PATH_LOWER,
++};
++
++extern const char *ovl_opaque_xattr;
++extern const char *ovl_whiteout_xattr;
++extern const struct dentry_operations ovl_dentry_operations;
++
++enum ovl_path_type ovl_path_type(struct dentry *dentry);
++u64 ovl_dentry_version_get(struct dentry *dentry);
++void ovl_dentry_version_inc(struct dentry *dentry);
++void ovl_path_upper(struct dentry *dentry, struct path *path);
++void ovl_path_lower(struct dentry *dentry, struct path *path);
++enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
++struct dentry *ovl_dentry_upper(struct dentry *dentry);
++struct dentry *ovl_dentry_lower(struct dentry *dentry);
++struct dentry *ovl_dentry_real(struct dentry *dentry);
++struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper);
++bool ovl_dentry_is_opaque(struct dentry *dentry);
++void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
++bool ovl_is_whiteout(struct dentry *dentry);
++void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
++struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
++			  struct nameidata *nd);
++struct file *ovl_path_open(struct path *path, int flags);
++
++struct dentry *ovl_upper_create(struct dentry *upperdir, struct dentry *dentry,
++				struct kstat *stat, const char *link);
++
++/* readdir.c */
++extern const struct file_operations ovl_dir_operations;
++int ovl_check_empty_and_clear(struct dentry *dentry, enum ovl_path_type type);
++
++/* inode.c */
++int ovl_setattr(struct dentry *dentry, struct iattr *attr);
++int ovl_permission(struct inode *inode, int mask);
++int ovl_setxattr(struct dentry *dentry, const char *name,
++		 const void *value, size_t size, int flags);
++ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
++		     void *value, size_t size);
++ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
++int ovl_removexattr(struct dentry *dentry, const char *name);
++
++struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
++			    struct ovl_entry *oe);
++/* dir.c */
++extern const struct inode_operations ovl_dir_inode_operations;
++
++/* copy_up.c */
++int ovl_copy_up(struct dentry *dentry);
++int ovl_copy_up_truncate(struct dentry *dentry, loff_t size);
+diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
+new file mode 100644
+index 0000000..0797efb
+--- /dev/null
++++ b/fs/overlayfs/readdir.c
+@@ -0,0 +1,566 @@
++/*
++ *
++ * Copyright (C) 2011 Novell Inc.
++ *
++ * 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 <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/namei.h>
++#include <linux/file.h>
++#include <linux/xattr.h>
++#include <linux/rbtree.h>
++#include <linux/security.h>
++#include <linux/cred.h>
++#include "overlayfs.h"
++
++struct ovl_cache_entry {
++	const char *name;
++	unsigned int len;
++	unsigned int type;
++	u64 ino;
++	bool is_whiteout;
++	struct list_head l_node;
++	struct rb_node node;
++};
++
++struct ovl_readdir_data {
++	struct rb_root *root;
++	struct list_head *list;
++	struct list_head *middle;
++	struct dentry *dir;
++	int count;
++	int err;
++};
++
++struct ovl_dir_file {
++	bool is_real;
++	bool is_cached;
++	struct list_head cursor;
++	u64 cache_version;
++	struct list_head cache;
++	struct file *realfile;
++};
++
++static struct ovl_cache_entry *ovl_cache_entry_from_node(struct rb_node *n)
++{
++	return container_of(n, struct ovl_cache_entry, node);
++}
++
++static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root,
++						    const char *name, int len)
++{
++	struct rb_node *node = root->rb_node;
++	int cmp;
++
++	while (node) {
++		struct ovl_cache_entry *p = ovl_cache_entry_from_node(node);
++
++		cmp = strncmp(name, p->name, len);
++		if (cmp > 0)
++			node = p->node.rb_right;
++		else if (cmp < 0 || len < p->len)
++			node = p->node.rb_left;
++		else
++			return p;
++	}
++
++	return NULL;
++}
++
++static struct ovl_cache_entry *ovl_cache_entry_new(const char *name, int len,
++						   u64 ino, unsigned int d_type)
++{
++	struct ovl_cache_entry *p;
++
++	p = kmalloc(sizeof(*p) + len + 1, GFP_KERNEL);
++	if (p) {
++		char *name_copy = (char *) (p + 1);
++		memcpy(name_copy, name, len);
++		name_copy[len] = '\0';
++		p->name = name_copy;
++		p->len = len;
++		p->type = d_type;
++		p->ino = ino;
++		p->is_whiteout = false;
++	}
++
++	return p;
++}
++
++static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
++				  const char *name, int len, u64 ino,
++				  unsigned int d_type)
++{
++	struct rb_node **newp = &rdd->root->rb_node;
++	struct rb_node *parent = NULL;
++	struct ovl_cache_entry *p;
++
++	while (*newp) {
++		int cmp;
++		struct ovl_cache_entry *tmp;
++
++		parent = *newp;
++		tmp = ovl_cache_entry_from_node(*newp);
++		cmp = strncmp(name, tmp->name, len);
++		if (cmp > 0)
++			newp = &tmp->node.rb_right;
++		else if (cmp < 0 || len < tmp->len)
++			newp = &tmp->node.rb_left;
++		else
++			return 0;
++	}
++
++	p = ovl_cache_entry_new(name, len, ino, d_type);
++	if (p == NULL)
++		return -ENOMEM;
++
++	list_add_tail(&p->l_node, rdd->list);
++	rb_link_node(&p->node, parent, newp);
++	rb_insert_color(&p->node, rdd->root);
++
++	return 0;
++}
++
++static int ovl_fill_lower(void *buf, const char *name, int namelen,
++			    loff_t offset, u64 ino, unsigned int d_type)
++{
++	struct ovl_readdir_data *rdd = buf;
++	struct ovl_cache_entry *p;
++
++	rdd->count++;
++	p = ovl_cache_entry_find(rdd->root, name, namelen);
++	if (p) {
++		list_move_tail(&p->l_node, rdd->middle);
++	} else {
++		p = ovl_cache_entry_new(name, namelen, ino, d_type);
++		if (p == NULL)
++			rdd->err = -ENOMEM;
++		else
++			list_add_tail(&p->l_node, rdd->middle);
++	}
++
++	return rdd->err;
++}
++
++static void ovl_cache_free(struct list_head *list)
++{
++	struct ovl_cache_entry *p;
++	struct ovl_cache_entry *n;
++
++	list_for_each_entry_safe(p, n, list, l_node)
++		kfree(p);
++
++	INIT_LIST_HEAD(list);
++}
++
++static int ovl_fill_upper(void *buf, const char *name, int namelen,
++			  loff_t offset, u64 ino, unsigned int d_type)
++{
++	struct ovl_readdir_data *rdd = buf;
++
++	rdd->count++;
++	return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
++}
++
++static inline int ovl_dir_read(struct path *realpath,
++			       struct ovl_readdir_data *rdd, filldir_t filler)
++{
++	struct file *realfile;
++	int err;
++
++	realfile = ovl_path_open(realpath, O_RDONLY | O_DIRECTORY);
++	if (IS_ERR(realfile))
++		return PTR_ERR(realfile);
++
++	do {
++		rdd->count = 0;
++		rdd->err = 0;
++		err = vfs_readdir(realfile, filler, rdd);
++		if (err >= 0)
++			err = rdd->err;
++	} while (!err && rdd->count);
++	fput(realfile);
++
++	return 0;
++}
++
++static void ovl_dir_reset(struct file *file)
++{
++	struct ovl_dir_file *od = file->private_data;
++	enum ovl_path_type type = ovl_path_type(file->f_path.dentry);
++
++	if (ovl_dentry_version_get(file->f_path.dentry) != od->cache_version) {
++		list_del_init(&od->cursor);
++		ovl_cache_free(&od->cache);
++		od->is_cached = false;
++	}
++	WARN_ON(!od->is_real && type != OVL_PATH_MERGE);
++	if (od->is_real && type == OVL_PATH_MERGE) {
++		fput(od->realfile);
++		od->realfile = NULL;
++		od->is_real = false;
++	}
++}
++
++static int ovl_dir_mark_whiteouts(struct ovl_readdir_data *rdd)
++{
++	struct ovl_cache_entry *p;
++	struct dentry *dentry;
++	const struct cred *old_cred;
++	struct cred *override_cred;
++
++	override_cred = prepare_creds();
++	if (!override_cred) {
++		ovl_cache_free(rdd->list);
++		return -ENOMEM;
++	}
++
++	/*
++	 * CAP_SYS_ADMIN for getxattr
++	 * CAP_DAC_OVERRIDE for lookup
++	 */
++	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
++	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
++	old_cred = override_creds(override_cred);
++
++	mutex_lock(&rdd->dir->d_inode->i_mutex);
++	list_for_each_entry(p, rdd->list, l_node) {
++		if (p->type != DT_LNK)
++			continue;
++
++		dentry = lookup_one_len(p->name, rdd->dir, p->len);
++		if (IS_ERR(dentry))
++			continue;
++
++		p->is_whiteout = ovl_is_whiteout(dentry);
++		dput(dentry);
++	}
++	mutex_unlock(&rdd->dir->d_inode->i_mutex);
++
++	revert_creds(old_cred);
++	put_cred(override_cred);
++
++	return 0;
++}
++
++static inline int ovl_dir_read_merged(struct path *upperpath,
++				      struct path *lowerpath,
++				      struct ovl_readdir_data *rdd)
++{
++	int err;
++	struct rb_root root = RB_ROOT;
++	struct list_head middle;
++
++	rdd->root = &root;
++	if (upperpath->dentry) {
++		rdd->dir = upperpath->dentry;
++		err = ovl_dir_read(upperpath, rdd, ovl_fill_upper);
++		if (err)
++			goto out;
++
++		err = ovl_dir_mark_whiteouts(rdd);
++		if (err)
++			goto out;
++	}
++	/*
++	 * Insert lowerpath entries before upperpath ones, this allows
++	 * offsets to be reasonably constant
++	 */
++	list_add(&middle, rdd->list);
++	rdd->middle = &middle;
++	err = ovl_dir_read(lowerpath, rdd, ovl_fill_lower);
++	list_del(&middle);
++out:
++	rdd->root = NULL;
++
++	return err;
++}
++
++static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos)
++{
++	struct list_head *l;
++	loff_t off;
++
++	l = od->cache.next;
++	for (off = 0; off < pos; off++) {
++		if (l == &od->cache)
++			break;
++		l = l->next;
++	}
++	list_move_tail(&od->cursor, l);
++}
++
++static int ovl_readdir(struct file *file, void *buf, filldir_t filler)
++{
++	struct ovl_dir_file *od = file->private_data;
++	int res;
++
++	if (!file->f_pos)
++		ovl_dir_reset(file);
++
++	if (od->is_real) {
++		res = vfs_readdir(od->realfile, filler, buf);
++		file->f_pos = od->realfile->f_pos;
++
++		return res;
++	}
++
++	if (!od->is_cached) {
++		struct path lowerpath;
++		struct path upperpath;
++		struct ovl_readdir_data rdd = { .list = &od->cache };
++
++		ovl_path_lower(file->f_path.dentry, &lowerpath);
++		ovl_path_upper(file->f_path.dentry, &upperpath);
++
++		res = ovl_dir_read_merged(&upperpath, &lowerpath, &rdd);
++		if (res) {
++			ovl_cache_free(rdd.list);
++			return res;
++		}
++
++		od->cache_version = ovl_dentry_version_get(file->f_path.dentry);
++		od->is_cached = true;
++
++		ovl_seek_cursor(od, file->f_pos);
++	}
++
++	while (od->cursor.next != &od->cache) {
++		int over;
++		loff_t off;
++		struct ovl_cache_entry *p;
++
++		p = list_entry(od->cursor.next, struct ovl_cache_entry, l_node);
++		off = file->f_pos;
++		if (!p->is_whiteout) {
++			over = filler(buf, p->name, p->len, off, p->ino,
++				      p->type);
++			if (over)
++				break;
++		}
++		file->f_pos++;
++		list_move(&od->cursor, &p->l_node);
++	}
++
++	return 0;
++}
++
++static loff_t ovl_dir_llseek(struct file *file, loff_t offset, int origin)
++{
++	loff_t res;
++	struct ovl_dir_file *od = file->private_data;
++
++	mutex_lock(&file->f_dentry->d_inode->i_mutex);
++	if (!file->f_pos)
++		ovl_dir_reset(file);
++
++	if (od->is_real) {
++		res = vfs_llseek(od->realfile, offset, origin);
++		file->f_pos = od->realfile->f_pos;
++	} else {
++		res = -EINVAL;
++
++		switch (origin) {
++		case SEEK_CUR:
++			offset += file->f_pos;
++			break;
++		case SEEK_SET:
++			break;
++		default:
++			goto out_unlock;
++		}
++		if (offset < 0)
++			goto out_unlock;
++
++		if (offset != file->f_pos) {
++			file->f_pos = offset;
++			if (od->is_cached)
++				ovl_seek_cursor(od, offset);
++		}
++		res = offset;
++	}
++out_unlock:
++	mutex_unlock(&file->f_dentry->d_inode->i_mutex);
++
++	return res;
++}
++
++static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
++			 int datasync)
++{
++	struct ovl_dir_file *od = file->private_data;
++
++	/* May need to reopen directory if it got copied up */
++	if (!od->realfile) {
++		struct path upperpath;
++
++		ovl_path_upper(file->f_path.dentry, &upperpath);
++		od->realfile = ovl_path_open(&upperpath, O_RDONLY);
++		if (IS_ERR(od->realfile))
++			return PTR_ERR(od->realfile);
++	}
++
++	return vfs_fsync_range(od->realfile, start, end, datasync);
++}
++
++static int ovl_dir_release(struct inode *inode, struct file *file)
++{
++	struct ovl_dir_file *od = file->private_data;
++
++	list_del(&od->cursor);
++	ovl_cache_free(&od->cache);
++	if (od->realfile)
++		fput(od->realfile);
++	kfree(od);
++
++	return 0;
++}
++
++static int ovl_dir_open(struct inode *inode, struct file *file)
++{
++	struct path realpath;
++	struct file *realfile;
++	struct ovl_dir_file *od;
++	enum ovl_path_type type;
++
++	od = kzalloc(sizeof(struct ovl_dir_file), GFP_KERNEL);
++	if (!od)
++		return -ENOMEM;
++
++	type = ovl_path_real(file->f_path.dentry, &realpath);
++	realfile = ovl_path_open(&realpath, file->f_flags);
++	if (IS_ERR(realfile)) {
++		kfree(od);
++		return PTR_ERR(realfile);
++	}
++	INIT_LIST_HEAD(&od->cache);
++	INIT_LIST_HEAD(&od->cursor);
++	od->is_cached = false;
++	od->realfile = realfile;
++	od->is_real = (type != OVL_PATH_MERGE);
++	file->private_data = od;
++
++	return 0;
++}
++
++const struct file_operations ovl_dir_operations = {
++	.read		= generic_read_dir,
++	.open		= ovl_dir_open,
++	.readdir	= ovl_readdir,
++	.llseek		= ovl_dir_llseek,
++	.fsync		= ovl_dir_fsync,
++	.release	= ovl_dir_release,
++};
++
++static int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
++{
++	int err;
++	struct path lowerpath;
++	struct path upperpath;
++	struct ovl_cache_entry *p;
++	struct ovl_readdir_data rdd = { .list = list };
++
++	ovl_path_upper(dentry, &upperpath);
++	ovl_path_lower(dentry, &lowerpath);
++
++	err = ovl_dir_read_merged(&upperpath, &lowerpath, &rdd);
++	if (err)
++		return err;
++
++	err = 0;
++
++	list_for_each_entry(p, list, l_node) {
++		if (p->is_whiteout)
++			continue;
++
++		if (p->name[0] == '.') {
++			if (p->len == 1)
++				continue;
++			if (p->len == 2 && p->name[1] == '.')
++				continue;
++		}
++		err = -ENOTEMPTY;
++		break;
++	}
++
++	return err;
++}
++
++static int ovl_remove_whiteouts(struct dentry *dir, struct list_head *list)
++{
++	struct path upperpath;
++	struct dentry *upperdir;
++	struct ovl_cache_entry *p;
++	const struct cred *old_cred;
++	struct cred *override_cred;
++	int err;
++
++	ovl_path_upper(dir, &upperpath);
++	upperdir = upperpath.dentry;
++
++	override_cred = prepare_creds();
++	if (!override_cred)
++		return -ENOMEM;
++
++	/*
++	 * CAP_DAC_OVERRIDE for lookup and unlink
++	 * CAP_SYS_ADMIN for setxattr of "trusted" namespace
++	 * CAP_FOWNER for unlink in sticky directory
++	 */
++	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
++	cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
++	cap_raise(override_cred->cap_effective, CAP_FOWNER);
++	old_cred = override_creds(override_cred);
++
++	err = vfs_setxattr(upperdir, ovl_opaque_xattr, "y", 1, 0);
++	if (err)
++		goto out_revert_creds;
++
++	mutex_lock_nested(&upperdir->d_inode->i_mutex, I_MUTEX_PARENT);
++	list_for_each_entry(p, list, l_node) {
++		struct dentry *dentry;
++		int ret;
++
++		if (!p->is_whiteout)
++			continue;
++
++		dentry = lookup_one_len(p->name, upperdir, p->len);
++		if (IS_ERR(dentry)) {
++			printk(KERN_WARNING
++			    "overlayfs: failed to lookup whiteout %.*s: %li\n",
++			    p->len, p->name, PTR_ERR(dentry));
++			continue;
++		}
++		ret = vfs_unlink(upperdir->d_inode, dentry);
++		dput(dentry);
++		if (ret)
++			printk(KERN_WARNING
++			    "overlayfs: failed to unlink whiteout %.*s: %i\n",
++			    p->len, p->name, ret);
++	}
++	mutex_unlock(&upperdir->d_inode->i_mutex);
++
++out_revert_creds:
++	revert_creds(old_cred);
++	put_cred(override_cred);
++
++	return err;
++}
++
++int ovl_check_empty_and_clear(struct dentry *dentry, enum ovl_path_type type)
++{
++	int err;
++	LIST_HEAD(list);
++
++	err = ovl_check_empty_dir(dentry, &list);
++	if (!err && type == OVL_PATH_MERGE)
++		err = ovl_remove_whiteouts(dentry, &list);
++
++	ovl_cache_free(&list);
++
++	return err;
++}
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+new file mode 100644
+index 0000000..1d2d1e2
+--- /dev/null
++++ b/fs/overlayfs/super.c
+@@ -0,0 +1,664 @@
++/*
++ *
++ * Copyright (C) 2011 Novell Inc.
++ *
++ * 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 <linux/fs.h>
++#include <linux/namei.h>
++#include <linux/xattr.h>
++#include <linux/security.h>
++#include <linux/mount.h>
++#include <linux/slab.h>
++#include <linux/parser.h>
++#include <linux/module.h>
++#include <linux/cred.h>
++#include <linux/sched.h>
++#include <linux/seq_file.h>
++#include "overlayfs.h"
++
++MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
++MODULE_DESCRIPTION("Overlay filesystem");
++MODULE_LICENSE("GPL");
++
++struct ovl_config {
++	char *lowerdir;
++	char *upperdir;
++};
++
++/* private information held for overlayfs's superblock */
++struct ovl_fs {
++	struct vfsmount *upper_mnt;
++	struct vfsmount *lower_mnt;
++	/* pathnames of lower and upper dirs, for show_options */
++	struct ovl_config config;
++};
++
++/* private information held for every overlayfs dentry */
++struct ovl_entry {
++	/*
++	 * Keep "double reference" on upper dentries, so that
++	 * d_delete() doesn't think it's OK to reset d_inode to NULL.
++	 */
++	struct dentry *__upperdentry;
++	struct dentry *lowerdentry;
++	union {
++		struct {
++			u64 version;
++			bool opaque;
++		};
++		struct rcu_head rcu;
++	};
++};
++
++const char *ovl_whiteout_xattr = "trusted.overlay.whiteout";
++const char *ovl_opaque_xattr = "trusted.overlay.opaque";
++
++
++enum ovl_path_type ovl_path_type(struct dentry *dentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	if (oe->__upperdentry) {
++		if (oe->lowerdentry && S_ISDIR(dentry->d_inode->i_mode))
++			return OVL_PATH_MERGE;
++		else
++			return OVL_PATH_UPPER;
++	} else {
++		return OVL_PATH_LOWER;
++	}
++}
++
++static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe)
++{
++	struct dentry *upperdentry = ACCESS_ONCE(oe->__upperdentry);
++	smp_read_barrier_depends();
++	return upperdentry;
++}
++
++void ovl_path_upper(struct dentry *dentry, struct path *path)
++{
++	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	path->mnt = ofs->upper_mnt;
++	path->dentry = ovl_upperdentry_dereference(oe);
++}
++
++void ovl_path_lower(struct dentry *dentry, struct path *path)
++{
++	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	path->mnt = ofs->lower_mnt;
++	path->dentry = oe->lowerdentry;
++}
++
++enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
++{
++
++	enum ovl_path_type type = ovl_path_type(dentry);
++
++	if (type == OVL_PATH_LOWER)
++		ovl_path_lower(dentry, path);
++	else
++		ovl_path_upper(dentry, path);
++
++	return type;
++}
++
++struct dentry *ovl_dentry_upper(struct dentry *dentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	return ovl_upperdentry_dereference(oe);
++}
++
++struct dentry *ovl_dentry_lower(struct dentry *dentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	return oe->lowerdentry;
++}
++
++struct dentry *ovl_dentry_real(struct dentry *dentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++	struct dentry *realdentry;
++
++	realdentry = ovl_upperdentry_dereference(oe);
++	if (!realdentry)
++		realdentry = oe->lowerdentry;
++
++	return realdentry;
++}
++
++struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper)
++{
++	struct dentry *realdentry;
++
++	realdentry = ovl_upperdentry_dereference(oe);
++	if (realdentry) {
++		*is_upper = true;
++	} else {
++		realdentry = oe->lowerdentry;
++		*is_upper = false;
++	}
++	return realdentry;
++}
++
++bool ovl_dentry_is_opaque(struct dentry *dentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++	return oe->opaque;
++}
++
++void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++	oe->opaque = opaque;
++}
++
++void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	WARN_ON(!mutex_is_locked(&upperdentry->d_parent->d_inode->i_mutex));
++	WARN_ON(oe->__upperdentry);
++	BUG_ON(!upperdentry->d_inode);
++	smp_wmb();
++	oe->__upperdentry = dget(upperdentry);
++}
++
++void ovl_dentry_version_inc(struct dentry *dentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	WARN_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));
++	oe->version++;
++}
++
++u64 ovl_dentry_version_get(struct dentry *dentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	WARN_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));
++	return oe->version;
++}
++
++bool ovl_is_whiteout(struct dentry *dentry)
++{
++	int res;
++	char val;
++
++	if (!dentry)
++		return false;
++	if (!dentry->d_inode)
++		return false;
++	if (!S_ISLNK(dentry->d_inode->i_mode))
++		return false;
++
++	res = vfs_getxattr(dentry, ovl_whiteout_xattr, &val, 1);
++	if (res == 1 && val == 'y')
++		return true;
++
++	return false;
++}
++
++static bool ovl_is_opaquedir(struct dentry *dentry)
++{
++	int res;
++	char val;
++
++	if (!S_ISDIR(dentry->d_inode->i_mode))
++		return false;
++
++	res = vfs_getxattr(dentry, ovl_opaque_xattr, &val, 1);
++	if (res == 1 && val == 'y')
++		return true;
++
++	return false;
++}
++
++static void ovl_entry_free(struct rcu_head *head)
++{
++	struct ovl_entry *oe = container_of(head, struct ovl_entry, rcu);
++	kfree(oe);
++}
++
++static void ovl_dentry_release(struct dentry *dentry)
++{
++	struct ovl_entry *oe = dentry->d_fsdata;
++
++	if (oe) {
++		dput(oe->__upperdentry);
++		dput(oe->__upperdentry);
++		dput(oe->lowerdentry);
++		call_rcu(&oe->rcu, ovl_entry_free);
++	}
++}
++
++const struct dentry_operations ovl_dentry_operations = {
++	.d_release = ovl_dentry_release,
++};
++
++static struct ovl_entry *ovl_alloc_entry(void)
++{
++	return kzalloc(sizeof(struct ovl_entry), GFP_KERNEL);
++}
++
++static inline struct dentry *ovl_lookup_real(struct dentry *dir,
++					     struct qstr *name)
++{
++	struct dentry *dentry;
++
++	mutex_lock(&dir->d_inode->i_mutex);
++	dentry = lookup_one_len(name->name, dir, name->len);
++	mutex_unlock(&dir->d_inode->i_mutex);
++
++	if (IS_ERR(dentry)) {
++		if (PTR_ERR(dentry) == -ENOENT)
++			dentry = NULL;
++	} else if (!dentry->d_inode) {
++		dput(dentry);
++		dentry = NULL;
++	}
++	return dentry;
++}
++
++static int ovl_do_lookup(struct dentry *dentry)
++{
++	struct ovl_entry *oe;
++	struct dentry *upperdir;
++	struct dentry *lowerdir;
++	struct dentry *upperdentry = NULL;
++	struct dentry *lowerdentry = NULL;
++	struct inode *inode = NULL;
++	int err;
++
++	err = -ENOMEM;
++	oe = ovl_alloc_entry();
++	if (!oe)
++		goto out;
++
++	upperdir = ovl_dentry_upper(dentry->d_parent);
++	lowerdir = ovl_dentry_lower(dentry->d_parent);
++
++	if (upperdir) {
++		upperdentry = ovl_lookup_real(upperdir, &dentry->d_name);
++		err = PTR_ERR(upperdentry);
++		if (IS_ERR(upperdentry))
++			goto out_put_dir;
++
++		if (lowerdir && upperdentry &&
++		    (S_ISLNK(upperdentry->d_inode->i_mode) ||
++		     S_ISDIR(upperdentry->d_inode->i_mode))) {
++			const struct cred *old_cred;
++			struct cred *override_cred;
++
++			err = -ENOMEM;
++			override_cred = prepare_creds();
++			if (!override_cred)
++				goto out_dput_upper;
++
++			/* CAP_SYS_ADMIN needed for getxattr */
++			cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
++			old_cred = override_creds(override_cred);
++
++			if (ovl_is_opaquedir(upperdentry)) {
++				oe->opaque = true;
++			} else if (ovl_is_whiteout(upperdentry)) {
++				dput(upperdentry);
++				upperdentry = NULL;
++				oe->opaque = true;
++			}
++			revert_creds(old_cred);
++			put_cred(override_cred);
++		}
++	}
++	if (lowerdir && !oe->opaque) {
++		lowerdentry = ovl_lookup_real(lowerdir, &dentry->d_name);
++		err = PTR_ERR(lowerdentry);
++		if (IS_ERR(lowerdentry))
++			goto out_dput_upper;
++	}
++
++	if (lowerdentry && upperdentry &&
++	    (!S_ISDIR(upperdentry->d_inode->i_mode) ||
++	     !S_ISDIR(lowerdentry->d_inode->i_mode))) {
++		dput(lowerdentry);
++		lowerdentry = NULL;
++		oe->opaque = true;
++	}
++
++	if (lowerdentry || upperdentry) {
++		struct dentry *realdentry;
++
++		realdentry = upperdentry ? upperdentry : lowerdentry;
++		err = -ENOMEM;
++		inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode,
++				      oe);
++		if (!inode)
++			goto out_dput;
++	}
++
++	if (upperdentry)
++		oe->__upperdentry = dget(upperdentry);
++
++	if (lowerdentry)
++		oe->lowerdentry = lowerdentry;
++
++	dentry->d_fsdata = oe;
++	dentry->d_op = &ovl_dentry_operations;
++	d_add(dentry, inode);
++
++	return 0;
++
++out_dput:
++	dput(lowerdentry);
++out_dput_upper:
++	dput(upperdentry);
++out_put_dir:
++	kfree(oe);
++out:
++	return err;
++}
++
++struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
++			  struct nameidata *nd)
++{
++	int err = ovl_do_lookup(dentry);
++
++	if (err)
++		return ERR_PTR(err);
++
++	return NULL;
++}
++
++struct file *ovl_path_open(struct path *path, int flags)
++{
++	path_get(path);
++	return dentry_open(path->dentry, path->mnt, flags, current_cred());
++}
++
++static void ovl_put_super(struct super_block *sb)
++{
++	struct ovl_fs *ufs = sb->s_fs_info;
++
++	if (!(sb->s_flags & MS_RDONLY))
++		mnt_drop_write(ufs->upper_mnt);
++
++	mntput(ufs->upper_mnt);
++	mntput(ufs->lower_mnt);
++
++	kfree(ufs->config.lowerdir);
++	kfree(ufs->config.upperdir);
++	kfree(ufs);
++}
++
++static int ovl_remount_fs(struct super_block *sb, int *flagsp, char *data)
++{
++	int flags = *flagsp;
++	struct ovl_fs *ufs = sb->s_fs_info;
++
++	/* When remounting rw or ro, we need to adjust the write access to the
++	 * upper fs.
++	 */
++	if (((flags ^ sb->s_flags) & MS_RDONLY) == 0)
++		/* No change to readonly status */
++		return 0;
++
++	if (flags & MS_RDONLY) {
++		mnt_drop_write(ufs->upper_mnt);
++		return 0;
++	} else
++		return mnt_want_write(ufs->upper_mnt);
++}
++
++/**
++ * ovl_statfs
++ * @sb: The overlayfs super block
++ * @buf: The struct kstatfs to fill in with stats
++ *
++ * Get the filesystem statistics.  As writes always target the upper layer
++ * filesystem pass the statfs to the same filesystem.
++ */
++static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf)
++{
++	struct dentry *root_dentry = dentry->d_sb->s_root;
++	struct path path;
++	ovl_path_upper(root_dentry, &path);
++
++	if (!path.dentry->d_sb->s_op->statfs)
++		return -ENOSYS;
++	return path.dentry->d_sb->s_op->statfs(path.dentry, buf);
++}
++
++/**
++ * ovl_show_options
++ *
++ * Prints the mount options for a given superblock.
++ * Returns zero; does not fail.
++ */
++static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
++{
++	struct super_block *sb = dentry->d_sb;
++	struct ovl_fs *ufs = sb->s_fs_info;
++
++	seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir);
++	seq_printf(m, ",upperdir=%s", ufs->config.upperdir);
++	return 0;
++}
++
++static const struct super_operations ovl_super_operations = {
++	.put_super	= ovl_put_super,
++	.remount_fs	= ovl_remount_fs,
++	.statfs		= ovl_statfs,
++	.show_options	= ovl_show_options,
++};
++
++enum {
++	Opt_lowerdir,
++	Opt_upperdir,
++	Opt_err,
++};
++
++static const match_table_t ovl_tokens = {
++	{Opt_lowerdir,			"lowerdir=%s"},
++	{Opt_upperdir,			"upperdir=%s"},
++	{Opt_err,			NULL}
++};
++
++static int ovl_parse_opt(char *opt, struct ovl_config *config)
++{
++	char *p;
++
++	config->upperdir = NULL;
++	config->lowerdir = NULL;
++
++	while ((p = strsep(&opt, ",")) != NULL) {
++		int token;
++		substring_t args[MAX_OPT_ARGS];
++
++		if (!*p)
++			continue;
++
++		token = match_token(p, ovl_tokens, args);
++		switch (token) {
++		case Opt_upperdir:
++			kfree(config->upperdir);
++			config->upperdir = match_strdup(&args[0]);
++			if (!config->upperdir)
++				return -ENOMEM;
++			break;
++
++		case Opt_lowerdir:
++			kfree(config->lowerdir);
++			config->lowerdir = match_strdup(&args[0]);
++			if (!config->lowerdir)
++				return -ENOMEM;
++			break;
++
++		default:
++			return -EINVAL;
++		}
++	}
++	return 0;
++}
++
++static int ovl_fill_super(struct super_block *sb, void *data, int silent)
++{
++	struct path lowerpath;
++	struct path upperpath;
++	struct inode *root_inode;
++	struct dentry *root_dentry;
++	struct ovl_entry *oe;
++	struct ovl_fs *ufs;
++	int err;
++
++	err = -ENOMEM;
++	ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL);
++	if (!ufs)
++		goto out;
++
++	err = ovl_parse_opt((char *) data, &ufs->config);
++	if (err)
++		goto out_free_ufs;
++
++	err = -EINVAL;
++	if (!ufs->config.upperdir || !ufs->config.lowerdir) {
++		printk(KERN_ERR "overlayfs: missing upperdir or lowerdir\n");
++		goto out_free_config;
++	}
++
++	oe = ovl_alloc_entry();
++	if (oe == NULL)
++		goto out_free_config;
++
++	err = kern_path(ufs->config.upperdir, LOOKUP_FOLLOW, &upperpath);
++	if (err)
++		goto out_free_oe;
++
++	err = kern_path(ufs->config.lowerdir, LOOKUP_FOLLOW, &lowerpath);
++	if (err)
++		goto out_put_upperpath;
++
++	err = -ENOTDIR;
++	if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) ||
++	    !S_ISDIR(lowerpath.dentry->d_inode->i_mode))
++		goto out_put_lowerpath;
++
++	sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth,
++				lowerpath.mnt->mnt_sb->s_stack_depth) + 1;
++
++	err = -EINVAL;
++	if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) {
++		printk(KERN_ERR "overlayfs: maximum fs stacking depth exceeded\n");
++		goto out_put_lowerpath;
++	}
++
++
++	ufs->upper_mnt = clone_private_mount(&upperpath);
++	err = PTR_ERR(ufs->upper_mnt);
++	if (IS_ERR(ufs->upper_mnt)) {
++		printk(KERN_ERR "overlayfs: failed to clone upperpath\n");
++		goto out_put_lowerpath;
++	}
++
++	ufs->lower_mnt = clone_private_mount(&lowerpath);
++	err = PTR_ERR(ufs->lower_mnt);
++	if (IS_ERR(ufs->lower_mnt)) {
++		printk(KERN_ERR "overlayfs: failed to clone lowerpath\n");
++		goto out_put_upper_mnt;
++	}
++
++	/*
++	 * Make lower_mnt R/O.  That way fchmod/fchown on lower file
++	 * will fail instead of modifying lower fs.
++	 */
++	ufs->lower_mnt->mnt_flags |= MNT_READONLY;
++
++	/* If the upper fs is r/o, we mark overlayfs r/o too */
++	if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)
++		sb->s_flags |= MS_RDONLY;
++
++	if (!(sb->s_flags & MS_RDONLY)) {
++		err = mnt_want_write(ufs->upper_mnt);
++		if (err)
++			goto out_put_lower_mnt;
++	}
++
++	err = -ENOMEM;
++	root_inode = ovl_new_inode(sb, S_IFDIR, oe);
++	if (!root_inode)
++		goto out_drop_write;
++
++	root_dentry = d_make_root(root_inode);
++	if (!root_dentry)
++		goto out_drop_write;
++
++	mntput(upperpath.mnt);
++	mntput(lowerpath.mnt);
++
++	oe->__upperdentry = dget(upperpath.dentry);
++	oe->lowerdentry = lowerpath.dentry;
++
++	root_dentry->d_fsdata = oe;
++	root_dentry->d_op = &ovl_dentry_operations;
++
++	sb->s_op = &ovl_super_operations;
++	sb->s_root = root_dentry;
++	sb->s_fs_info = ufs;
++
++	return 0;
++
++out_drop_write:
++	if (!(sb->s_flags & MS_RDONLY))
++		mnt_drop_write(ufs->upper_mnt);
++out_put_lower_mnt:
++	mntput(ufs->lower_mnt);
++out_put_upper_mnt:
++	mntput(ufs->upper_mnt);
++out_put_lowerpath:
++	path_put(&lowerpath);
++out_put_upperpath:
++	path_put(&upperpath);
++out_free_oe:
++	kfree(oe);
++out_free_config:
++	kfree(ufs->config.lowerdir);
++	kfree(ufs->config.upperdir);
++out_free_ufs:
++	kfree(ufs);
++out:
++	return err;
++}
++
++static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags,
++				const char *dev_name, void *raw_data)
++{
++	return mount_nodev(fs_type, flags, raw_data, ovl_fill_super);
++}
++
++static struct file_system_type ovl_fs_type = {
++	.owner		= THIS_MODULE,
++	.name		= "overlayfs",
++	.mount		= ovl_mount,
++	.kill_sb	= kill_anon_super,
++};
++
++static int __init ovl_init(void)
++{
++	return register_filesystem(&ovl_fs_type);
++}
++
++static void __exit ovl_exit(void)
++{
++	unregister_filesystem(&ovl_fs_type);
++}
++
++module_init(ovl_init);
++module_exit(ovl_exit);
+diff --git a/fs/splice.c b/fs/splice.c
+index f847684..c124964 100644
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -1299,6 +1299,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
+ 
+ 	return ret;
+ }
++EXPORT_SYMBOL(do_splice_direct);
+ 
+ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
+ 			       struct pipe_inode_info *opipe,
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 8de6755..0b531ab 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -489,6 +489,12 @@ struct iattr {
+  */
+ #include <linux/quota.h>
+ 
++/*
++ * Maximum number of layers of fs stack.  Needs to be limited to
++ * prevent kernel stack overflow
++ */
++#define FILESYSTEM_MAX_STACK_DEPTH 2
++
+ /** 
+  * enum positive_aop_returns - aop return codes with specific semantics
+  *
+@@ -1507,6 +1513,11 @@ struct super_block {
+ 
+ 	/* Being remounted read-only */
+ 	int s_readonly_remount;
++
++	/*
++	 * Indicates how deep in a filesystem stack this SB is
++	 */
++	int s_stack_depth;
+ };
+ 
+ /* superblock cache pruning functions */
+@@ -1664,6 +1675,8 @@ struct inode_operations {
+ 	void (*truncate_range)(struct inode *, loff_t, loff_t);
+ 	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
+ 		      u64 len);
++	struct file *(*open) (struct dentry *, struct file *,
++			      const struct cred *);
+ } ____cacheline_aligned;
+ 
+ struct seq_file;
+@@ -2021,6 +2034,7 @@ extern long do_sys_open(int dfd, const char __user *filename, int flags,
+ extern struct file *filp_open(const char *, int, umode_t);
+ extern struct file *file_open_root(struct dentry *, struct vfsmount *,
+ 				   const char *, int);
++extern struct file *vfs_open(struct path *, struct file *, const struct cred *);
+ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
+ 				 const struct cred *);
+ extern int filp_close(struct file *, fl_owner_t id);
+@@ -2212,6 +2226,7 @@ extern sector_t bmap(struct inode *, sector_t);
+ #endif
+ extern int notify_change(struct dentry *, struct iattr *);
+ extern int inode_permission(struct inode *, int);
++extern int inode_only_permission(struct inode *, int);
+ extern int generic_permission(struct inode *, int);
+ 
+ static inline bool execute_ok(struct inode *inode)
+diff --git a/include/linux/mount.h b/include/linux/mount.h
+index d7029f4..344a262 100644
+--- a/include/linux/mount.h
++++ b/include/linux/mount.h
+@@ -66,6 +66,9 @@ extern void mnt_pin(struct vfsmount *mnt);
+ extern void mnt_unpin(struct vfsmount *mnt);
+ extern int __mnt_is_readonly(struct vfsmount *mnt);
+ 
++struct path;
++extern struct vfsmount *clone_private_mount(struct path *path);
++
+ struct file_system_type;
+ extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
+ 				      int flags, const char *name,
diff --git a/br-ext-chip-grainmedia/board/gm8136/kernel/patches/10_uimage_makefile.patch b/br-ext-chip-grainmedia/board/gm8136/kernel/patches/10_uimage_makefile.patch
deleted file mode 100644
index 428b5a73..00000000
--- a/br-ext-chip-grainmedia/board/gm8136/kernel/patches/10_uimage_makefile.patch
+++ /dev/null
@@ -1,62 +0,0 @@
---- linux-3.0.101/arch/arm/boot/Makefile	2013-10-22 11:58:59.000000000 +0400
-+++ linux-3.0.101/arch/arm/boot/Makefile	2021-12-15 10:51:15.956535987 +0300
-@@ -59,15 +59,19 @@
- 
- endif
- 
--quiet_cmd_uimage = UIMAGE  $@
--      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
--		   -C none -a $(LOADADDR) -e $(STARTADDR) \
--		   -n 'Linux-$(KERNELRELEASE)' -d $< $@
-+#quiet_cmd_uimage = UIMAGE  $@
-+#      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
-+#		   -C none -a $(LOADADDR) -e $(STARTADDR) \
-+#		   -n 'Linux-$(KERNELRELEASE)' -d $< $@
- 
--ifeq ($(CONFIG_ZBOOT_ROM),y)
--$(obj)/uImage: LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
-+ifneq ($(LOADADDR),)
-+  UIMAGE_LOADADDR=$(LOADADDR)
- else
--$(obj)/uImage: LOADADDR=$(ZRELADDR)
-+  ifeq ($(CONFIG_ZBOOT_ROM),y)
-+    UIMAGE_LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
-+  else
-+    UIMAGE_LOADADDR=$(ZRELADDR)
-+  endif
- endif
- 
- $(obj)/uImage: STARTADDR=$(LOADADDR)
---- linux-3.0.101/scripts/Makefile.lib	2013-10-22 11:58:59.000000000 +0400
-+++ linux-3.0.101/scripts/Makefile.lib	2021-12-15 10:53:24.551357718 +0300
-@@ -262,6 +262,30 @@
- 	lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
- 	(rm -f $@ ; false)
- 
-+# U-Boot mkimage
-+# ---------------------------------------------------------------------------
-+
-+MKIMAGE := $(srctree)/scripts/mkuboot.sh
-+
-+# SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces
-+# the number of overrides in arch makefiles
-+UIMAGE_ARCH ?= $(SRCARCH)
-+UIMAGE_COMPRESSION ?= $(if $(2),$(2),none)
-+UIMAGE_OPTS-y ?=
-+UIMAGE_TYPE ?= kernel
-+UIMAGE_LOADADDR ?= arch_must_set_this
-+UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR)
-+UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)'
-+UIMAGE_IN ?= $<
-+UIMAGE_OUT ?= $@
-+
-+quiet_cmd_uimage = UIMAGE  $(UIMAGE_OUT)
-+      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \
-+			-C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) \
-+			-T $(UIMAGE_TYPE) \
-+			-a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \
-+			-n $(UIMAGE_NAME) -d $(UIMAGE_IN) $(UIMAGE_OUT)
-+
- # XZ
- # ---------------------------------------------------------------------------
- # Use xzkern to compress the kernel image and xzmisc to compress other things.
diff --git a/br-ext-chip-grainmedia/board/gm8136/kernel/patches/11_fix_yylloc_for_modern_computers.patch b/br-ext-chip-grainmedia/board/gm8136/kernel/patches/11_fix_yylloc_for_modern_computers.patch
new file mode 100644
index 00000000..d7088f90
--- /dev/null
+++ b/br-ext-chip-grainmedia/board/gm8136/kernel/patches/11_fix_yylloc_for_modern_computers.patch
@@ -0,0 +1,11 @@
+--- a/scripts/dtc/dtc-lexer.lex.c_shipped	2015-08-07 22:08:04.000000000 +0300
++++ b/scripts/dtc/dtc-lexer.lex.c_shipped	2021-11-01 22:15:12.347053553 +0300
+@@ -637,7 +637,7 @@
+ #include "srcpos.h"
+ #include "dtc-parser.tab.h"
+ 
+-YYLTYPE yylloc;
++extern YYLTYPE yylloc;
+ 
+ /* CAUTION: this will stop working if we ever use yyless() or yyunput() */
+ #define	YY_USER_ACTION \