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: + + +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: + + +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: + + +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: + + 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 + + .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 + + .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 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 + +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 +//#include #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 -#include 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 #include #include +#include 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//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 +#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 #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 +#endif + +#if (defined(CONFIG_ARCH_GM) || defined(CONFIG_ARCH_GM_DUO) || defined(CONFIG_ARCH_GM_SMP)) +#include +#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 -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 -#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 #include #include +#include #include #include #include @@ -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//mem. + * atomic helpers and the signal restart code. Insert it into the + * gate_vma so that it is visible through ptrace and /proc//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 #include +#include #include #include #include @@ -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 #include #include -#include +#include #include +#include +#include #include #include #include /* 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 #include +#include #include /* @@ -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 + * + * This program is free software; 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +#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 "); +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PLATFORM_GM8210 +#include +#include +#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 "); +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 +#include +#include + +#include +#include +#include + +#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 +#include +#include +#include + +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PLATFORM_GM8210 +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include + + .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 +#include +#include + + .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 +#include + + .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 +#include +#include +#include +#include + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + +#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 + +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 + +#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 + +#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 +#include +#include + +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 + * + * 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 + +#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 +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +/* Include platform *dependent* UART console configuration */ +#include + +#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 + +#include +#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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_GM8312 +#include +#include +#endif +#include +#include +#ifdef CONFIG_FTDMAC030 +#include +#endif + +#include +#include + +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#ifdef CONFIG_GM8312 +#include +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_GM8312 +#include +#endif +#include +#include +#include +#include +#include /* for init_consistent_dma_size() */ +#ifdef CONFIG_FTDMAC030 +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#ifdef CONFIG_GM8312 +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_GM8312 +#include +#include +#endif +#include +#include +#ifdef CONFIG_FTDMAC030 +#include +#endif + +#include +#include + +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_GM8312 +#include +#endif +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include + +#include "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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 +#include +#include +#include +#include +#include +#include + +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 + * + * This program is free software; 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 +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FTDMAC030 +#include +#endif +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#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 "); +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include + + __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 +#include +#include + +#include +#include + +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 +#include +#include + + .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 +#include +#include + + .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 +#include + + .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 +#include +#include +#include +#include + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + +#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 + +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 + +#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 +#include +#include + +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 + * + * 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 + +#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 +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +/* Include platform *dependent* UART console configuration */ +#include + +#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 + +#include +#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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +//#include +#include +#include + +#ifdef CONFIG_CPU_HAS_GIC +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//#include +//#include +//#include +//#include + +//#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 +#include +#include +#include +#include +#include +#include + +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 + * + * This program is free software; 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 +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FTDMAC030 +#include +#endif +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + +#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 "); +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 +#include +#include + +#include +#include + +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 +#include +#include + +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include + + .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 +#include +#include + + .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 +#include + + .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 +#include +#include +#include +#include + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + +#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 + +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 + +#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 +#include +#include + +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 + * + * 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 + +#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 +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +//#include + +#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 + +/* 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 + +#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 +#include +#include +#include + +#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 +#include +/* Include platform *dependent* UART console configuration */ +#include + +#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 + +#include +#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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * 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 +#include +#include +#include +#include + +#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 \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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0//def CONFIG_CACHE_FTL2CC031 +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_CACHE_FTL2CC031 +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include +#ifdef CONFIG_CPU_FMP626 +#include +#include +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef CONFIG_CPU_FMP626 +#include +#include +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +/****************************************************************************** + * 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include + +#include "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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 "); +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 "); +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 "); +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include + +#include + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include + +/****************************************************************************** + * 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include + +/****************************************************************************** + * 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 +#include + + __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 +#include +#include + +#include + +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 +#include +#include + + .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 + + .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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 +#include +#include + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 +#include +#include + +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 +#include +#include + +#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 +#include + +#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 +#include + +#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 +#include + +#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 + +/* + * 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 +#include +#include + +#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 + +/* + * 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 + +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 +#include +#include + +#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 + +#include +#include +#include + +#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 +#include +#include + +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 #include "fault.h" - +#include /* * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 #include #include +#include #include #include @@ -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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 +#include +#include +#include +#include +#include +#include +#include +#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 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 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 +#include +#include +#include +#include +#include +#include +#include +#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 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 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 #include #include "ahci.h" +#include +#include +#include +#ifdef CONFIG_PLATFORM_GM8210 +#include +#include +#endif +#ifdef CONFIG_PLATFORM_GM8287 +#include +#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; iaddr); + 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 "); 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 #include #include "ahci.h" +#ifdef CONFIG_SATA_AHCI_PLATFORM // chris add +#ifdef CONFIG_PLATFORM_GM8210 +#include +#endif +#ifdef CONFIG_PLATFORM_GM8287 +#include +#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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 +#include +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#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 "); +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#endif + +#include + +#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 "); +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 + +/* 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 #include +#include #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 +#include +#include + +#if defined(CONFIG_MMC_FTSDC021_VEND_TUNE) +#include +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 +#include + +#include +#include "sdhci-pltfm.h" + +#if defined(CONFIG_PLATFORM_GM8210) +#include +#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 "); +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 #include +#include + +#include +#include #include "sdhci.h" +#if defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136) +#include +#include +#include +#include +#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 +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 + * - Modify for FTSPI020 Faraday SPI flash controller. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#ifdef MODULE +#include "ftspi020.h" +#else +#include +#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 + * - Modify for FTSPI020 Faraday SPI flash controller. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#ifdef MODULE +#include "ftspi020.h" +#else +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 #include #include +#include #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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ftnandc023v2_nand.h" +#include +/* + * Local function or variables declaration + */ +//#define CONFIG_NAND_USE_AXIDMA +#if defined(CONFIG_NAND_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA) +#include + +#ifdef CONFIG_NAND_USE_AHBDMA +#include +#else +#include +#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("", tmp_addr); + } + + tmp_addr += (0x1 << chip->bbt_erase_shift); + } + + /* move n good block */ + if(bad_num) { + //printk("",page_addr,bad_num); + while(bad_num) { + //printk("", 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("\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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ftnandc024v2_nand.h" +#include +/* + * Local function or variables declaration + */ +//#undef CONFIG_NAND_V2_USE_AHBDMA//??? +#if defined(CONFIG_NAND_V2_USE_AHBDMA) || defined(CONFIG_NAND_USE_AXIDMA) +#include + +#ifdef CONFIG_NAND_V2_USE_AHBDMA +#include +#else +#include +#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_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("", tmp_addr); + } + + tmp_addr += (0x1 << chip->bbt_erase_shift); + } + + /* move n good block */ + if(bad_num) { + //printk("",page_addr,bad_num); + while(bad_num) { + //printk("", 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("\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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include "ftspi020_nand.h" +#include + +//#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 + +#ifdef CONFIG_SPI_NAND_USE_AHBDMA +#include +#else +#include +#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("",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("\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("", 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("", tmp_addr); + } + + tmp_addr += (0x1 << chip->bbt_erase_shift); + } + + /* move n good block */ + if(bad_num) { + //printk("",page_addr,bad_num); + while(bad_num) { + //printk("", 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("\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("", 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include "ftspi020_nand.h" +#include + +#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 + +#ifdef CONFIG_SPI_NAND_USE_AHBDMA +#include +#else +#include +#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("",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("\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("", 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("", tmp_addr); + } + + tmp_addr += (0x1 << chip->bbt_erase_shift); + } + + /* move n good block */ + if(bad_num) { + //printk("",page_addr,bad_num); + while(bad_num) { + //printk("", 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("\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("", 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 #include #include +#include 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: + + + To compile this driver as a module, choose M here and read + . 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: + + + To compile this driver as a module, choose M here and read + . 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: + + + To compile this driver as a module, choose M here and read + . 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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("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("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("", 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("", 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 "); +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You 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 +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ftgmac030.h" +#include +#include +#include + +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 #include #include #include @@ -31,69 +32,157 @@ #include #include #include +#include #include - +#include +#include +#include +#include +#include #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("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("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("", 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("", 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("", 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("", 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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ftgmac100.h" +#include +#include +#include + +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 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#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: \n"); + } else { + EMAC_REG32(priv, MACCR_REG) = data & (~Speed_100_bit); + printk("Link Change: \n"); + } + + if (phy_read_duplex(dev)) { + EMAC_REG32(priv, MACCR_REG) = data | FULLDUP_bit; + printk("Link Change: \n"); + } else { + EMAC_REG32(priv, MACCR_REG) = data & (~FULLDUP_bit); + printk("Link Change: \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 "); +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 + e0300-devel Mailing List + 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 + */ +#include +#include +#include + +#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 -#include -#include -#include - -/* 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 +#include +#include +#include + +/* 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 + * Copyright (c) 2009 Po-Yu Chuang + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ftspi020.h" +#include + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) +#include +#else +#include +#endif + +//#define CONFIG_FTSPI020_USE_AHBDMA//??? + +#if defined(CONFIG_FTSPI020_USE_AHBDMA) || defined(CONFIG_FTSPI020_USE_AXIDMA) +#include +#include + +#ifdef CONFIG_FTSPI020_USE_AHBDMA +#include +#else +#include +#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 "); +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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include "ftssp010_spi.h" +#include +#include + +#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("", 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(""); + 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("", 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 +#include +#include +#include + +#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 #include +#include #include "8250.h" +#include #ifdef CONFIG_SPARC #include "../suncore.h" #endif +#ifdef CONFIG_SERIAL_CTSRTS +#include +#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("",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(""); + 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(""); + 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 - * + * 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 @@ -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 +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#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 + +/* //////////////////////////////////////////////////////////////////////////////// +// +// 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;iactual;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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GM_udc.h" +//#include "../host/fotg2xx_opt-macro.h" + +#if defined(CONFIG_PLATFORM_GM8210) +#include +#endif +#if defined(CONFIG_PLATFORM_GM8136) +#include +#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(""); +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 + // 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 #endif +#if defined(CONFIG_GM_FOTG2XX) || defined(CONFIG_GM_FUSBH200) +#include +#include "fotg2xx_opt-macro.h" +//#include "../gadget/GM_udc.h" +#include +#include +#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 +#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 + Li-Chun Chen + * Feng-Hsin Chiang + * Po-Yu Chuang + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/*-------------------------------------------------------------------------*/ +#define 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 +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 +/*-------------------------------------------------------------------------*/ + +#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 + #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 +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fotg2xx-config.h" +#include "fotg2xx-ehci-macro.h" +#include "fotg2xx_opt-macro.h" +#include "../gadget/fotg2xx-peri-macro.h" + +#include +#include +#include +#include +#include +#if defined(CONFIG_PLATFORM_GM8126) || defined(CONFIG_PLATFORM_GM8287) || defined(CONFIG_PLATFORM_GM8139) || defined(CONFIG_PLATFORM_GM8136) +#include +#endif +#if defined(CONFIG_PLATFORM_GM8210) +#include +#include +#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(""); +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 + * Based on SoftDog driver by Alan Cox + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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 +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_PLATFORM_GM8210) +#include +#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 +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 #include #include +#include #include #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 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 +#include -#endif /*_XT_CONNMARK_H_target*/ +/* Copyright (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 - * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh * 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 +#ifndef _XT_DSCP_H +#define _XT_DSCP_H + #include -/* 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 -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 + * + * 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 - * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh - * - * 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 -#include -#include -#include -#include - -#include -#include - -MODULE_AUTHOR("Harald Welte "); -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 +/* Kernel module to match TCP MSS values. */ + +/* Copyright (C) 2000 Marc Boucher + * Portions (C) 2005 by Harald Welte * * 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 #include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include + #include #include -#include -#include -#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Boucher "); -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 " >&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);