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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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 = ®INFO_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, ®INFO_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, ®INFO_LIST, list) { ++ if (node->fd == fd) { ++ for (i = 0; i < REGINFO_REGCNT(node); i++) { ++ if (REGINFO_OFFSET(node, i) != reg_off) ++ continue; ++ ++ pLock_bits = ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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 = ®INFO_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, ®INFO_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, ®INFO_LIST, list) { ++ if (node->fd == fd) { ++ for (i = 0; i < REGINFO_REGCNT(node); i++) { ++ if (REGINFO_OFFSET(node, i) != reg_off) ++ continue; ++ ++ pLock_bits = ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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 = ®INFO_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, ®INFO_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, ®INFO_LIST, list) { ++ if (node->fd == fd) { ++ for (i = 0; i < REGINFO_REGCNT(node); i++) { ++ if (REGINFO_OFFSET(node, i) != reg_off) ++ continue; ++ ++ pLock_bits = ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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, ®INFO_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", ®off, &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 \