ramips: add linux 4.4 support, update mt7621 subtarget to 4.4
authorFelix Fietkau <nbd@openwrt.org>
Mon, 7 Mar 2016 16:33:34 +0000 (16:33 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 7 Mar 2016 16:33:34 +0000 (16:33 +0000)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
SVN-Revision: 48951

71 files changed:
package/kernel/linux/modules/usb.mk
target/linux/ramips/Makefile
target/linux/ramips/dts/mt7621.dtsi
target/linux/ramips/mt7621/config-4.3 [deleted file]
target/linux/ramips/mt7621/config-4.4 [new file with mode: 0644]
target/linux/ramips/patches-4.4/0001-arch-mips-ralink-add-mt7621-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0002-MIPS-ralink-add-MT7621-defconfig.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0004-MIPS-ralink-add-MT7621-pcie-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0005-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0006-MIPS-ralink-add-cpu-frequency-scaling.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0009-PCI-MIPS-adds-mt7620a-pcie-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0010-arch-mips-ralink-add-spi1-clocks.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0013-owrt-hack-fix-mt7688-cache-issue.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0014-arch-mips-cleanup-cevt-rt3352.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0015-arch-mips-do-not-select-illegal-access-driver-by-def.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0019-arch-mips-ralink-add-mt7621-cpu-feature-overrides.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0022-arch-mips-ralink-proper-vendor-id-srtring.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0024-GPIO-add-named-gpio-exports.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0025-pinctrl-ralink-add-pinctrl-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0026-DT-Add-documentation-for-gpio-ralink.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0028-GPIO-ralink-add-mt7621-gpio-controller.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0029-phy-usb-add-ralink-phy.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0031-uvc-add-iPassion-iP2970-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0032-USB-dwc2-add-device_reset.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0033-xhci-mediatek-support-MTK-xHCI-host-controller.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0034-NET-multi-phy-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0036-mtd-fix-cfi-cmdset-0002-erase-status-check.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0037-mtd-cfi-cmdset-0002-force-word-write.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0038-mtd-ralink-add-mt7620-nand-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0039-mtd-add-mt7621-nand-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0040-nand-add-mtk-nand-hack-hook.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0041-DT-Add-documentation-for-spi-rt2880.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0042-SPI-ralink-add-Ralink-SoC-spi-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0043-spi-add-mt7621-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0044-i2c-MIPS-adds-ralink-I2C-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0045-i2c-add-mt7621-driver.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0046-mmc-MIPS-ralink-add-sdhci-for-mt7620a-SoC.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0047-DMA-ralink-add-rt2880-dma-engine.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0048-asoc-add-mt7620-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0049-watchdog-add-MT7621-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0051-serial-add-ugly-custom-baud-rate-hack.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0052-pwm-add-mediatek-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0054-mtd-add-chunked-read-io-to-m25p80.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0059-correct-CPC_BASE_MASK.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0063-set-CM_GCR_BASE_CMDEFTGT_MEM-according-to-datasheet.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0064-add_clk_round_rate.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0066-mt7621-enable-highmem.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0067-enable-mt7621-xhci.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0068-fix-ralink-prom.c [new file with mode: 0644]
target/linux/ramips/patches-4.4/0103-MIPS-OWRTDTB.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0104-fix_bootargs_handling.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0200-linkit_bootstrap.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0500-Documentation-DT-net-add-docs-for-ralink-mediatek-So.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0501-net-next-mediatek-add-the-drivers-core-files.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0502-net-next-mediatek-add-switch-driver-for-rt3050.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0503-net-next-mediatek-add-switch-driver-for-mt7620.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0504-net-next-mediatek-add-switch-driver-for-mt7621.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0505-net-next-mediatek-add-support-for-rt2880.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0506-net-next-mediatek-add-support-for-rt3050.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0507-net-next-mediatek-add-support-for-rt3883.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0508-net-next-mediatek-add-support-for-mt7620.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0509-net-next-mediatek-add-support-for-mt7621.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0510-net-next-mediatek-add-Kconfig-and-Makefile.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0511-net-mediatek-add-support-for-the-multiphy-carrier-pa.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0512-net-mediatek-add-swconfig-driver-for-esw_rt3050.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0513-net-mediatek-add-swconfig-driver-for-gsw_mt762x.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0514-net-mediatek-fix_esw.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0601-net-mediatke-add-phy_ethtool_ioctl-support.patch [new file with mode: 0644]
target/linux/ramips/patches-4.4/0901-spansion_nand_id_fix.patch [new file with mode: 0644]

index 63d94bf..8c5a2ab 100644 (file)
@@ -1596,7 +1596,11 @@ endef
 
 $(eval $(call KernelPackage,usbmon))
 
-XHCI_FILES := $(wildcard $(patsubst %,$(LINUX_DIR)/drivers/usb/host/%.ko,xhci-hcd xhci-pci xhci-plat-hcd))
+XHCI_MODULES := xhci-hcd xhci-pci xhci-plat-hcd
+ifdef CONFIG_TARGET_ramips_mt7621
+  XHCI_MODULES += xhci-mtk
+endif
+XHCI_FILES := $(wildcard $(patsubst %,$(LINUX_DIR)/drivers/usb/host/%.ko,$(XHCI_MODULES)))
 XHCI_AUTOLOAD := $(patsubst $(LINUX_DIR)/drivers/usb/host/%.ko,%,$(XHCI_FILES))
 
 define KernelPackage/usb3
@@ -1609,6 +1613,7 @@ define KernelPackage/usb3
        CONFIG_USB_XHCI_PCI \
        CONFIG_USB_XHCI_PLATFORM \
        CONFIG_USB_XHCI_MVEBU=y \
+       CONFIG_USB_XHCI_MTK \
        CONFIG_USB_XHCI_HCD_DEBUGGING=n
   FILES:= \
        $(XHCI_FILES)
index 378e2f5..55a8fd6 100644 (file)
@@ -13,7 +13,7 @@ SUBTARGETS:=rt305x mt7620 mt7621 mt7628 mt7688 rt3883 rt288x
 FEATURES:=squashfs gpio mips16
 MAINTAINER:=John Crispin <blogic@openwrt.org>
 
-KERNEL_PATCHVER:=4.3
+KERNEL_PATCHVER:=4.4
 
 include $(INCLUDE_DIR)/target.mk
 DEFAULT_PACKAGES += \
index 3dd7bd0..24e0459 100644 (file)
        xhci@1E1C0000 {
                status = "okay";
 
-               compatible = "xhci-platform";
-               reg = <0x1E1C0000 4000>;
+               compatible = "mediatek,mt8173-xhci";
+               reg = <0x1e1c0000 0x1000
+                      0x1e1d0700 0x0100>;
+
+               clocks = <&sysclock>;
+               clock-names = "sys_ck";
 
                interrupt-parent = <&gic>;
                interrupts = <GIC_SHARED 22 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/target/linux/ramips/mt7621/config-4.3 b/target/linux/ramips/mt7621/config-4.3
deleted file mode 100644 (file)
index a70dc26..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-CONFIG_ARCH_BINFMT_ELF_STATE=y
-CONFIG_ARCH_DISCARD_MEMBLOCK=y
-CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
-CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
-# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
-CONFIG_ARCH_HAS_RESET_CONTROLLER=y
-# CONFIG_ARCH_HAS_SG_CHAIN is not set
-CONFIG_ARCH_HIBERNATION_POSSIBLE=y
-CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
-CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
-CONFIG_ARCH_REQUIRE_GPIOLIB=y
-CONFIG_ARCH_SUPPORTS_UPROBES=y
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
-CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
-CONFIG_BOARD_SCACHE=y
-CONFIG_BOUNCE=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_CEVT_R4K=y
-# CONFIG_CEVT_SYSTICK_QUIRK is not set
-CONFIG_CLKDEV_LOOKUP=y
-CONFIG_CLKSRC_MIPS_GIC=y
-CONFIG_CLKSRC_OF=y
-CONFIG_CLONE_BACKWARDS=y
-CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
-CONFIG_CMDLINE_BOOL=y
-# CONFIG_CMDLINE_OVERRIDE is not set
-CONFIG_COMMON_CLK=y
-CONFIG_CPU_GENERIC_DUMP_TLB=y
-CONFIG_CPU_HAS_PREFETCH=y
-CONFIG_CPU_HAS_SYNC=y
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_CPU_MIPS32=y
-# CONFIG_CPU_MIPS32_R1 is not set
-CONFIG_CPU_MIPS32_R2=y
-CONFIG_CPU_MIPSR2=y
-CONFIG_CPU_MIPSR2_IRQ_EI=y
-CONFIG_CPU_MIPSR2_IRQ_VI=y
-CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
-CONFIG_CPU_R4K_CACHE_TLB=y
-CONFIG_CPU_R4K_FPU=y
-CONFIG_CPU_RMAP=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_HIGHMEM=y
-CONFIG_CPU_SUPPORTS_MSA=y
-CONFIG_CRC16=y
-CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_LZO=y
-CONFIG_CRYPTO_RNG2=y
-CONFIG_CRYPTO_WORKQUEUE=y
-CONFIG_CSRC_R4K=y
-CONFIG_DEBUG_PINCTRL=y
-CONFIG_DMA_NONCOHERENT=y
-# CONFIG_DTB_MT7621_EVAL is not set
-CONFIG_DTB_RT_NONE=y
-CONFIG_DTC=y
-CONFIG_EARLY_PRINTK=y
-CONFIG_GENERIC_ATOMIC64=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_GENERIC_CMOS_UPDATE=y
-CONFIG_GENERIC_IO=y
-CONFIG_GENERIC_IRQ_CHIP=y
-CONFIG_GENERIC_IRQ_SHOW=y
-CONFIG_GENERIC_PCI_IOMAP=y
-CONFIG_GENERIC_SCHED_CLOCK=y
-CONFIG_GENERIC_SMP_IDLE_THREAD=y
-CONFIG_GPIOLIB=y
-CONFIG_GPIO_DEVRES=y
-CONFIG_GPIO_MT7621=y
-# CONFIG_GPIO_RALINK is not set
-CONFIG_GPIO_SYSFS=y
-CONFIG_HARDWARE_WATCHPOINTS=y
-CONFIG_HAS_DMA=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT_MAP=y
-# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
-# CONFIG_HAVE_ARCH_BITREVERSE is not set
-CONFIG_HAVE_ARCH_JUMP_LABEL=y
-CONFIG_HAVE_ARCH_KGDB=y
-CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
-CONFIG_HAVE_ARCH_TRACEHOOK=y
-# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
-CONFIG_HAVE_BPF_JIT=y
-CONFIG_HAVE_CC_STACKPROTECTOR=y
-CONFIG_HAVE_CLK=y
-CONFIG_HAVE_CLK_PREPARE=y
-CONFIG_HAVE_CONTEXT_TRACKING=y
-CONFIG_HAVE_C_RECORDMCOUNT=y
-CONFIG_HAVE_DEBUG_KMEMLEAK=y
-CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
-CONFIG_HAVE_DMA_API_DEBUG=y
-CONFIG_HAVE_DMA_ATTRS=y
-CONFIG_HAVE_DMA_CONTIGUOUS=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-CONFIG_HAVE_FUNCTION_TRACER=y
-CONFIG_HAVE_GENERIC_DMA_COHERENT=y
-CONFIG_HAVE_IDE=y
-CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
-CONFIG_HAVE_KVM=y
-CONFIG_HAVE_MACH_CLKDEV=y
-CONFIG_HAVE_MEMBLOCK=y
-CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
-CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
-CONFIG_HAVE_NET_DSA=y
-CONFIG_HAVE_OPROFILE=y
-CONFIG_HAVE_PERF_EVENTS=y
-CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
-CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
-CONFIG_HIGHMEM=y
-CONFIG_HW_HAS_PCI=y
-CONFIG_HZ_PERIODIC=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_IRQCHIP=y
-CONFIG_IRQ_DOMAIN=y
-CONFIG_IRQ_FORCED_THREADING=y
-CONFIG_IRQ_MIPS_CPU=y
-CONFIG_IRQ_WORK=y
-CONFIG_LIBFDT=y
-CONFIG_LZO_COMPRESS=y
-CONFIG_LZO_DECOMPRESS=y
-# CONFIG_MACH_INGENIC is not set
-# CONFIG_MACH_LOONGSON32 is not set
-# CONFIG_MACH_LOONGSON64 is not set
-CONFIG_MDIO_BOARDINFO=y
-CONFIG_MIPS=y
-CONFIG_MIPS_CM=y
-CONFIG_MIPS_CPC=y
-CONFIG_MIPS_CPS=y
-CONFIG_MIPS_CPU_SCACHE=y
-CONFIG_MIPS_GIC=y
-CONFIG_MIPS_GIC_IPI=y
-# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_MIPS_MACHINE is not set
-CONFIG_MIPS_MT=y
-CONFIG_MIPS_MT_FPAFF=y
-CONFIG_MIPS_MT_SMP=y
-CONFIG_MIPS_NO_APPENDED_DTB=y
-CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y
-# CONFIG_MIPS_RAW_APPENDED_DTB is not set
-CONFIG_MIPS_SPRAM=y
-# CONFIG_MIPS_VPE_LOADER is not set
-CONFIG_MODULES_USE_ELF_REL=y
-CONFIG_MT7621_WDT=y
-# CONFIG_MTD_CFI_INTELEXT is not set
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_SPI_NOR=y
-CONFIG_MTD_SPLIT_FIRMWARE=y
-CONFIG_MTD_SPLIT_SEAMA_FW=y
-CONFIG_MTD_SPLIT_TRX_FW=y
-CONFIG_MTD_SPLIT_UIMAGE_FW=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_BEB_LIMIT=20
-CONFIG_MTD_UBI_BLOCK=y
-# CONFIG_MTD_UBI_FASTMAP is not set
-# CONFIG_MTD_UBI_GLUEBI is not set
-CONFIG_MTD_UBI_WL_THRESHOLD=4096
-CONFIG_MTK_MTD_NAND=y
-CONFIG_NEED_DMA_MAP_STATE=y
-CONFIG_NET_FLOW_LIMIT=y
-CONFIG_NET_MEDIATEK_GSW_MT7621=y
-CONFIG_NET_MEDIATEK_MDIO=y
-CONFIG_NET_MEDIATEK_MDIO_MT7620=y
-CONFIG_NET_MEDIATEK_MT7621=y
-CONFIG_NET_MEDIATEK_SOC=y
-CONFIG_NET_VENDOR_MEDIATEK=y
-CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
-# CONFIG_NO_IOPORT_MAP is not set
-CONFIG_NR_CPUS=4
-CONFIG_OF=y
-CONFIG_OF_ADDRESS=y
-CONFIG_OF_ADDRESS_PCI=y
-CONFIG_OF_EARLY_FLATTREE=y
-CONFIG_OF_FLATTREE=y
-CONFIG_OF_GPIO=y
-CONFIG_OF_IRQ=y
-CONFIG_OF_MDIO=y
-CONFIG_OF_MTD=y
-CONFIG_OF_NET=y
-CONFIG_OF_PCI=y
-CONFIG_OF_PCI_IRQ=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_PCI=y
-CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
-CONFIG_PCI_DOMAINS=y
-CONFIG_PERF_USE_VMALLOC=y
-CONFIG_PGTABLE_LEVELS=2
-CONFIG_PHYLIB=y
-# CONFIG_PHY_RALINK_USB is not set
-CONFIG_PINCTRL=y
-CONFIG_PINCTRL_RT2880=y
-# CONFIG_PINCTRL_SINGLE is not set
-CONFIG_POWER_RESET=y
-CONFIG_POWER_RESET_GPIO=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_RALINK=y
-# CONFIG_RALINK_WDT is not set
-CONFIG_RCU_STALL_COMMON=y
-CONFIG_RESET_CONTROLLER=y
-CONFIG_RFS_ACCEL=y
-CONFIG_RPS=y
-CONFIG_RTC_CLASS=y
-CONFIG_SCHED_HRTICK=y
-# CONFIG_SCHED_INFO is not set
-CONFIG_SCHED_SMT=y
-# CONFIG_SCSI_DMA is not set
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_OF_PLATFORM=y
-# CONFIG_SG_SPLIT is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
-CONFIG_SLUB_CPU_PARTIAL=y
-CONFIG_SMP=y
-CONFIG_SMP_UP=y
-# CONFIG_SOC_MT7620 is not set
-CONFIG_SOC_MT7621=y
-# CONFIG_SOC_RT288X is not set
-# CONFIG_SOC_RT305X is not set
-# CONFIG_SOC_RT3883 is not set
-CONFIG_SPI=y
-CONFIG_SPI_MASTER=y
-CONFIG_SPI_MT7621=y
-# CONFIG_SPI_RT2880 is not set
-CONFIG_SRCU=y
-CONFIG_STOP_MACHINE=y
-# CONFIG_SUNXI_SRAM is not set
-CONFIG_SWCONFIG=y
-CONFIG_SYNC_R4K=y
-CONFIG_SYSCTL_EXCEPTION_TRACE=y
-CONFIG_SYS_HAS_CPU_MIPS32_R1=y
-CONFIG_SYS_HAS_CPU_MIPS32_R2=y
-CONFIG_SYS_HAS_EARLY_PRINTK=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_SYS_SUPPORTS_HIGHMEM=y
-CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
-CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
-CONFIG_SYS_SUPPORTS_MIPS16=y
-CONFIG_SYS_SUPPORTS_MIPS_CPS=y
-CONFIG_SYS_SUPPORTS_MULTITHREADING=y
-CONFIG_SYS_SUPPORTS_SCHED_SMT=y
-CONFIG_SYS_SUPPORTS_SMP=y
-CONFIG_TICK_CPU_ACCOUNTING=y
-CONFIG_TREE_RCU=y
-CONFIG_UBIFS_FS=y
-CONFIG_UBIFS_FS_ADVANCED_COMPR=y
-CONFIG_UBIFS_FS_LZO=y
-# CONFIG_UBIFS_FS_XZ is not set
-CONFIG_UBIFS_FS_ZLIB=y
-CONFIG_USB_SUPPORT=y
-CONFIG_USE_OF=y
-CONFIG_WATCHDOG_CORE=y
-CONFIG_WEAK_ORDERING=y
-CONFIG_XPS=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/ramips/mt7621/config-4.4 b/target/linux/ramips/mt7621/config-4.4
new file mode 100644 (file)
index 0000000..862c8e9
--- /dev/null
@@ -0,0 +1,265 @@
+CONFIG_ARCH_BINFMT_ELF_STATE=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_BOARD_SCACHE=y
+CONFIG_BOUNCE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CEVT_R4K=y
+# CONFIG_CEVT_SYSTICK_QUIRK is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MIPS_GIC=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMMON_CLK=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_MIPSR2_IRQ_EI=y
+CONFIG_CPU_MIPSR2_IRQ_VI=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_MSA=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CSRC_R4K=y
+CONFIG_DEBUG_PINCTRL=y
+CONFIG_DMA_NONCOHERENT=y
+# CONFIG_DTB_MT7621_EVAL is not set
+CONFIG_DTB_RT_NONE=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_MT7621=y
+# CONFIG_GPIO_RALINK is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+# CONFIG_HAVE_ARCH_BITREVERSE is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KVM=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_HAVE_MACH_CLKDEV=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HIGHMEM=y
+CONFIG_HW_HAS_PCI=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_MIPS_CPU=y
+CONFIG_IRQ_WORK=y
+CONFIG_LIBFDT=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MIPS=y
+CONFIG_MIPS_CLOCK_VSYSCALL=y
+CONFIG_MIPS_CM=y
+# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
+# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_MIPS_CMDLINE_FROM_DTB=y
+CONFIG_MIPS_CPC=y
+CONFIG_MIPS_CPS=y
+# CONFIG_MIPS_CPS_NS16550 is not set
+CONFIG_MIPS_CPU_SCACHE=y
+# CONFIG_MIPS_ELF_APPENDED_DTB is not set
+CONFIG_MIPS_GIC=y
+CONFIG_MIPS_GIC_IPI=y
+# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_MACHINE is not set
+CONFIG_MIPS_MT=y
+CONFIG_MIPS_MT_FPAFF=y
+CONFIG_MIPS_MT_SMP=y
+CONFIG_MIPS_NO_APPENDED_DTB=y
+CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y
+# CONFIG_MIPS_RAW_APPENDED_DTB is not set
+CONFIG_MIPS_SPRAM=y
+# CONFIG_MIPS_VPE_LOADER is not set
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MT7621_WDT=y
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_SEAMA_FW=y
+CONFIG_MTD_SPLIT_TRX_FW=y
+CONFIG_MTD_SPLIT_UIMAGE_FW=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTK_MTD_NAND=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_MEDIATEK_GSW_MT7621=y
+CONFIG_NET_MEDIATEK_MDIO=y
+CONFIG_NET_MEDIATEK_MDIO_MT7620=y
+CONFIG_NET_MEDIATEK_MT7621=y
+CONFIG_NET_MEDIATEK_SOC=y
+CONFIG_NET_VENDOR_MEDIATEK=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+# CONFIG_NO_IOPORT_MAP is not set
+CONFIG_NR_CPUS=4
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_PCI=y
+CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+# CONFIG_PHY_RALINK_USB is not set
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_RT2880=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_RALINK=y
+# CONFIG_RALINK_WDT is not set
+CONFIG_RATIONAL=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+CONFIG_SCHED_SMT=y
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_8250_FSL is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SMP=y
+CONFIG_SMP_UP=y
+# CONFIG_SOC_MT7620 is not set
+CONFIG_SOC_MT7621=y
+# CONFIG_SOC_RT288X is not set
+# CONFIG_SOC_RT305X is not set
+# CONFIG_SOC_RT3883 is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MT7621=y
+# CONFIG_SPI_RT2880 is not set
+CONFIG_SRCU=y
+CONFIG_SWCONFIG=y
+CONFIG_SYNC_R4K=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R2=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MIPS16=y
+CONFIG_SYS_SUPPORTS_MIPS_CPS=y
+CONFIG_SYS_SUPPORTS_MULTITHREADING=y
+CONFIG_SYS_SUPPORTS_SCHED_SMT=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TREE_RCU=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+# CONFIG_UBIFS_FS_XZ is not set
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_XPS=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/ramips/patches-4.4/0001-arch-mips-ralink-add-mt7621-support.patch b/target/linux/ramips/patches-4.4/0001-arch-mips-ralink-add-mt7621-support.patch
new file mode 100644 (file)
index 0000000..9f3d241
--- /dev/null
@@ -0,0 +1,437 @@
+From 450b6e8257e22708173d0c1c86d34394fba0c5eb Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:08:31 +0100
+Subject: [PATCH 01/53] arch: mips: ralink: add mt7621 support
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/include/asm/mach-ralink/irq.h    |    9 +
+ arch/mips/include/asm/mach-ralink/mt7621.h |   39 ++++
+ arch/mips/kernel/mips-cm.c                 |    4 +-
+ arch/mips/kernel/vmlinux.lds.S             |    1 +
+ arch/mips/ralink/Kconfig                   |   18 ++
+ arch/mips/ralink/Makefile                  |    7 +-
+ arch/mips/ralink/Platform                  |    5 +
+ arch/mips/ralink/irq-gic.c                 |  268 ++++++++++++++++++++++++++++
+ arch/mips/ralink/malta-amon.c              |   81 +++++++++
+ arch/mips/ralink/mt7621.c                  |  209 ++++++++++++++++++++++
+ 10 files changed, 638 insertions(+), 3 deletions(-)
+ create mode 100644 arch/mips/include/asm/mach-ralink/irq.h
+ create mode 100644 arch/mips/include/asm/mach-ralink/mt7621.h
+ create mode 100644 arch/mips/ralink/irq-gic.c
+ create mode 100644 arch/mips/ralink/malta-amon.c
+ create mode 100644 arch/mips/ralink/mt7621.c
+
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ralink/irq.h
+@@ -0,0 +1,9 @@
++#ifndef __ASM_MACH_RALINK_IRQ_H
++#define __ASM_MACH_RALINK_IRQ_H
++
++#define GIC_NUM_INTRS 64
++#define NR_IRQS 256
++
++#include_next <irq.h>
++
++#endif
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ralink/mt7621.h
+@@ -0,0 +1,42 @@
++/*
++ * 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.
++ *
++ * Parts of this file are based on Ralink's 2.6.21 BSP
++ *
++ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
++
++#ifndef _MT7621_REGS_H_
++#define _MT7621_REGS_H_
++
++#define MT7621_PALMBUS_BASE           0x1C000000
++#define MT7621_PALMBUS_SIZE           0x03FFFFFF
++
++#define MT7621_SYSC_BASE              0x1E000000
++
++#define SYSC_REG_CHIP_NAME0           0x00
++#define SYSC_REG_CHIP_NAME1           0x04
++#define SYSC_REG_CHIP_REV             0x0c
++#define SYSC_REG_SYSTEM_CONFIG0               0x10
++#define SYSC_REG_SYSTEM_CONFIG1               0x14
++
++#define CHIP_REV_PKG_MASK             0x1
++#define CHIP_REV_PKG_SHIFT            16
++#define CHIP_REV_VER_MASK             0xf
++#define CHIP_REV_VER_SHIFT            8
++#define CHIP_REV_ECO_MASK             0xf
++
++#define MT7621_DRAM_BASE                0x0
++#define MT7621_DDR2_SIZE_MIN          32
++#define MT7621_DDR2_SIZE_MAX          256
++
++#define MT7621_CHIP_NAME0             0x3637544D
++#define MT7621_CHIP_NAME1             0x20203132
++
++#define MIPS_GIC_IRQ_BASE           (MIPS_CPU_IRQ_BASE + 8)
++
++#endif
+--- a/arch/mips/kernel/vmlinux.lds.S
++++ b/arch/mips/kernel/vmlinux.lds.S
+@@ -53,6 +53,7 @@ SECTIONS
+       /* read-only */
+       _text = .;      /* Text and read-only data */
+       .text : {
++              /*. = . + 0x8000; */
+               TEXT_TEXT
+               SCHED_TEXT
+               LOCK_TEXT
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -12,6 +12,11 @@ config RALINK_ILL_ACC
+       depends on SOC_RT305X
+       default y
++config IRQ_INTC
++      bool
++      default y
++      depends on !SOC_MT7621
++
+ choice
+       prompt "Ralink SoC selection"
+       default SOC_RT305X
+@@ -34,6 +39,16 @@ choice
+       config SOC_MT7620
+               bool "MT7620/8"
++      config SOC_MT7621
++              bool "MT7621"
++              select MIPS_CPU_SCACHE
++              select SYS_SUPPORTS_MULTITHREADING
++              select SYS_SUPPORTS_SMP
++              select SYS_SUPPORTS_MIPS_CPS
++              select MIPS_GIC
++              select COMMON_CLK
++              select CLKSRC_MIPS_GIC
++              select HW_HAS_PCI
+ endchoice
+ choice
+@@ -65,6 +80,10 @@ choice
+               depends on SOC_MT7620
+               select BUILTIN_DTB
++      config DTB_MT7621_EVAL
++              bool "MT7621 eval kit"
++              depends on SOC_MT7621
++
+ endchoice
+ endif
+--- a/arch/mips/ralink/Makefile
++++ b/arch/mips/ralink/Makefile
+@@ -6,16 +6,24 @@
+ # Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ # Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+-obj-y := prom.o of.o reset.o clk.o irq.o timer.o
++obj-y := prom.o of.o reset.o
++
++ifndef CONFIG_MIPS_GIC
++      obj-y += clk.o timer.o
++endif
+ obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o
+ obj-$(CONFIG_RALINK_ILL_ACC) += ill_acc.o
++obj-$(CONFIG_IRQ_INTC) += irq.o
++obj-$(CONFIG_MIPS_GIC) += irq-gic.o timer-gic.o
++
+ obj-$(CONFIG_SOC_RT288X) += rt288x.o
+ obj-$(CONFIG_SOC_RT305X) += rt305x.o
+ obj-$(CONFIG_SOC_RT3883) += rt3883.o
+ obj-$(CONFIG_SOC_MT7620) += mt7620.o
++obj-$(CONFIG_SOC_MT7621) += mt7621.o
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+--- a/arch/mips/ralink/Platform
++++ b/arch/mips/ralink/Platform
+@@ -27,3 +27,8 @@ cflags-$(CONFIG_SOC_RT3883)  += -I$(srctr
+ #
+ load-$(CONFIG_SOC_MT7620)     += 0xffffffff80000000
+ cflags-$(CONFIG_SOC_MT7620)   += -I$(srctree)/arch/mips/include/asm/mach-ralink/mt7620
++
++# Ralink MT7621
++#
++load-$(CONFIG_SOC_MT7621)     += 0xffffffff80001000
++cflags-$(CONFIG_SOC_MT7621)   += -I$(srctree)/arch/mips/include/asm/mach-ralink/mt7621
+--- /dev/null
++++ b/arch/mips/ralink/irq-gic.c
+@@ -0,0 +1,18 @@
++#include <linux/init.h>
++
++#include <linux/of.h>
++#include <linux/irqchip.h>
++#include <linux/irqchip/mips-gic.h>
++
++int get_c0_perfcount_int(void)
++{
++      return gic_get_c0_perfcount_int();
++}
++EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
++
++void __init
++arch_init_irq(void)
++{
++      irqchip_init();
++}
++
+--- /dev/null
++++ b/arch/mips/ralink/mt7621.c
+@@ -0,0 +1,223 @@
++/*
++ * 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.
++ *
++ * Parts of this file are based on Ralink's 2.6.21 BSP
++ *
++ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++
++#include <asm/mipsregs.h>
++#include <asm/smp-ops.h>
++#include <asm/mips-cm.h>
++#include <asm/mips-cpc.h>
++#include <asm/mach-ralink/ralink_regs.h>
++#include <asm/mach-ralink/mt7621.h>
++
++#include <pinmux.h>
++
++#include "common.h"
++
++#define SYSC_REG_SYSCFG               0x10
++#define SYSC_REG_CPLL_CLKCFG0 0x2c
++#define SYSC_REG_CUR_CLK_STS  0x44
++#define CPU_CLK_SEL           (BIT(30) | BIT(31))
++
++#define MT7621_GPIO_MODE_UART1                1
++#define MT7621_GPIO_MODE_I2C          2
++#define MT7621_GPIO_MODE_UART3_MASK   0x3
++#define MT7621_GPIO_MODE_UART3_SHIFT  3
++#define MT7621_GPIO_MODE_UART3_GPIO   1
++#define MT7621_GPIO_MODE_UART2_MASK   0x3
++#define MT7621_GPIO_MODE_UART2_SHIFT  5
++#define MT7621_GPIO_MODE_UART2_GPIO   1
++#define MT7621_GPIO_MODE_JTAG         7
++#define MT7621_GPIO_MODE_WDT_MASK     0x3
++#define MT7621_GPIO_MODE_WDT_SHIFT    8
++#define MT7621_GPIO_MODE_WDT_GPIO     1
++#define MT7621_GPIO_MODE_PCIE_RST     0
++#define MT7621_GPIO_MODE_PCIE_REF     2
++#define MT7621_GPIO_MODE_PCIE_MASK    0x3
++#define MT7621_GPIO_MODE_PCIE_SHIFT   10
++#define MT7621_GPIO_MODE_PCIE_GPIO    1
++#define MT7621_GPIO_MODE_MDIO_MASK    0x3
++#define MT7621_GPIO_MODE_MDIO_SHIFT   12
++#define MT7621_GPIO_MODE_MDIO_GPIO    1
++#define MT7621_GPIO_MODE_RGMII1               14
++#define MT7621_GPIO_MODE_RGMII2               15
++#define MT7621_GPIO_MODE_SPI_MASK     0x3
++#define MT7621_GPIO_MODE_SPI_SHIFT    16
++#define MT7621_GPIO_MODE_SPI_GPIO     1
++#define MT7621_GPIO_MODE_SDHCI_MASK   0x3
++#define MT7621_GPIO_MODE_SDHCI_SHIFT  18
++#define MT7621_GPIO_MODE_SDHCI_GPIO   1
++
++static struct rt2880_pmx_func uart1_grp[] =  { FUNC("uart1", 0, 1, 2) };
++static struct rt2880_pmx_func i2c_grp[] =  { FUNC("i2c", 0, 3, 2) };
++static struct rt2880_pmx_func uart3_grp[] = {
++      FUNC("uart3", 0, 5, 4),
++      FUNC("i2s", 2, 5, 4),
++      FUNC("spdif3", 3, 5, 4),
++};
++static struct rt2880_pmx_func uart2_grp[] = {
++      FUNC("uart2", 0, 9, 4),
++      FUNC("pcm", 2, 9, 4),
++      FUNC("spdif2", 3, 9, 4),
++};
++static struct rt2880_pmx_func jtag_grp[] = { FUNC("jtag", 0, 13, 5) };
++static struct rt2880_pmx_func wdt_grp[] = {
++      FUNC("wdt rst", 0, 18, 1),
++      FUNC("wdt refclk", 2, 18, 1),
++};
++static struct rt2880_pmx_func pcie_rst_grp[] = {
++      FUNC("pcie rst", MT7621_GPIO_MODE_PCIE_RST, 19, 1),
++      FUNC("pcie refclk", MT7621_GPIO_MODE_PCIE_REF, 19, 1)
++};
++static struct rt2880_pmx_func mdio_grp[] = { FUNC("mdio", 0, 20, 2) };
++static struct rt2880_pmx_func rgmii2_grp[] = { FUNC("rgmii2", 0, 22, 12) };
++static struct rt2880_pmx_func spi_grp[] = {
++      FUNC("spi", 0, 34, 7),
++      FUNC("nand1", 2, 34, 7),
++};
++static struct rt2880_pmx_func sdhci_grp[] = {
++      FUNC("sdhci", 0, 41, 8),
++      FUNC("nand2", 2, 41, 8),
++};
++static struct rt2880_pmx_func rgmii1_grp[] = { FUNC("rgmii1", 0, 49, 12) };
++
++static struct rt2880_pmx_group mt7621_pinmux_data[] = {
++      GRP("uart1", uart1_grp, 1, MT7621_GPIO_MODE_UART1),
++      GRP("i2c", i2c_grp, 1, MT7621_GPIO_MODE_I2C),
++      GRP_G("uart3", uart3_grp, MT7621_GPIO_MODE_UART3_MASK,
++              MT7621_GPIO_MODE_UART3_GPIO, MT7621_GPIO_MODE_UART3_SHIFT),
++      GRP_G("uart2", uart2_grp, MT7621_GPIO_MODE_UART2_MASK,
++              MT7621_GPIO_MODE_UART2_GPIO, MT7621_GPIO_MODE_UART2_SHIFT),
++      GRP("jtag", jtag_grp, 1, MT7621_GPIO_MODE_JTAG),
++      GRP_G("wdt", wdt_grp, MT7621_GPIO_MODE_WDT_MASK,
++              MT7621_GPIO_MODE_WDT_GPIO, MT7621_GPIO_MODE_WDT_SHIFT),
++      GRP_G("pcie", pcie_rst_grp, MT7621_GPIO_MODE_PCIE_MASK,
++              MT7621_GPIO_MODE_PCIE_GPIO, MT7621_GPIO_MODE_PCIE_SHIFT),
++      GRP_G("mdio", mdio_grp, MT7621_GPIO_MODE_MDIO_MASK,
++              MT7621_GPIO_MODE_MDIO_GPIO, MT7621_GPIO_MODE_MDIO_SHIFT),
++      GRP("rgmii2", rgmii2_grp, 1, MT7621_GPIO_MODE_RGMII2),
++      GRP_G("spi", spi_grp, MT7621_GPIO_MODE_SPI_MASK,
++              MT7621_GPIO_MODE_SPI_GPIO, MT7621_GPIO_MODE_SPI_SHIFT),
++      GRP_G("sdhci", sdhci_grp, MT7621_GPIO_MODE_SDHCI_MASK,
++              MT7621_GPIO_MODE_SDHCI_GPIO, MT7621_GPIO_MODE_SDHCI_SHIFT),
++      GRP("rgmii1", rgmii1_grp, 1, MT7621_GPIO_MODE_RGMII1),
++      { 0 }
++};
++
++phys_addr_t mips_cpc_default_phys_base() {
++      panic("Cannot detect cpc address");
++}
++
++void __init ralink_clk_init(void)
++{
++      int cpu_fdiv = 0;
++      int cpu_ffrac = 0;
++      int fbdiv = 0;
++      u32 clk_sts, syscfg;
++      u8 clk_sel = 0, xtal_mode;
++      u32 cpu_clk;
++
++      if ((rt_sysc_r32(SYSC_REG_CPLL_CLKCFG0) & CPU_CLK_SEL) != 0)
++              clk_sel = 1;
++
++      switch (clk_sel) {
++      case 0:
++              clk_sts = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
++              cpu_fdiv = ((clk_sts >> 8) & 0x1F);
++              cpu_ffrac = (clk_sts & 0x1F);
++              cpu_clk = (500 * cpu_ffrac / cpu_fdiv) * 1000 * 1000;
++              break;
++
++      case 1:
++              fbdiv = ((rt_sysc_r32(0x648) >> 4) & 0x7F) + 1;
++              syscfg = rt_sysc_r32(SYSC_REG_SYSCFG);
++              xtal_mode = (syscfg >> 6) & 0x7;
++              if(xtal_mode >= 6) { //25Mhz Xtal
++                      cpu_clk = 25 * fbdiv * 1000 * 1000;
++              } else if(xtal_mode >=3) { //40Mhz Xtal
++                      cpu_clk = 40 * fbdiv * 1000 * 1000;
++              } else { // 20Mhz Xtal
++                      cpu_clk = 20 * fbdiv * 1000 * 1000;
++              }
++              break;
++      }
++}
++
++void __init ralink_of_remap(void)
++{
++      rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc");
++      rt_memc_membase = plat_of_remap_node("mtk,mt7621-memc");
++
++      if (!rt_sysc_membase || !rt_memc_membase)
++              panic("Failed to remap core resources");
++}
++
++void prom_soc_init(struct ralink_soc_info *soc_info)
++{
++      void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
++      unsigned char *name = NULL;
++      u32 n0;
++      u32 n1;
++      u32 rev;
++
++      n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0);
++      n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1);
++
++      if (n0 == MT7621_CHIP_NAME0 && n1 == MT7621_CHIP_NAME1) {
++              name = "MT7621";
++              soc_info->compatible = "mtk,mt7621-soc";
++      } else {
++              panic("mt7621: unknown SoC, n0:%08x n1:%08x\n", n0, n1);
++      }
++
++      rev = __raw_readl(sysc + SYSC_REG_CHIP_REV);
++
++      snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN,
++              "MediaTek %s ver:%u eco:%u",
++              name,
++              (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK,
++              (rev & CHIP_REV_ECO_MASK));
++
++      soc_info->mem_size_min = MT7621_DDR2_SIZE_MIN;
++      soc_info->mem_size_max = MT7621_DDR2_SIZE_MAX;
++      soc_info->mem_base = MT7621_DRAM_BASE;
++
++      rt2880_pinmux_data = mt7621_pinmux_data;
++
++      /* Early detection of CMP support */
++      mips_cm_probe();
++      mips_cpc_probe();
++
++      if (mips_cm_numiocu()) {
++              /* mips_cm_probe() wipes out bootloader
++                 config for CM regions and we have to configure them
++                 again. This SoC cannot talk to pamlbus devices
++                 witout proper iocu region set up.
++
++                 FIXME: it would be better to do this with values
++                 from DT, but we need this very early because
++                 without this we cannot talk to pretty much anything
++                 including serial.
++              */
++              write_gcr_reg0_base(MT7621_PALMBUS_BASE);
++              write_gcr_reg0_mask(~MT7621_PALMBUS_SIZE | CM_GCR_REGn_MASK_CMTGT_IOCU0);
++      }
++
++      if (!register_cps_smp_ops())
++              return;
++      if (!register_cmp_smp_ops())
++              return;
++      if (!register_vsmp_smp_ops())
++              return;
++}
+--- /dev/null
++++ b/arch/mips/ralink/timer-gic.c
+@@ -0,0 +1,15 @@
++#include <linux/init.h>
++
++#include <linux/of.h>
++#include <linux/clk-provider.h>
++#include <linux/clocksource.h>
++
++#include "common.h"
++
++void __init plat_time_init(void)
++{
++      ralink_of_remap();
++
++      of_clk_init(NULL);
++      clocksource_probe();
++}
diff --git a/target/linux/ramips/patches-4.4/0002-MIPS-ralink-add-MT7621-defconfig.patch b/target/linux/ramips/patches-4.4/0002-MIPS-ralink-add-MT7621-defconfig.patch
new file mode 100644 (file)
index 0000000..d788f2f
--- /dev/null
@@ -0,0 +1,211 @@
+From c96f2cc4d5f6e1bb11f3e7e04a7e21503a214d7c Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 27 Jan 2014 13:12:41 +0000
+Subject: [PATCH 02/53] MIPS: ralink: add MT7621 defconfig
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/configs/mt7621_defconfig |  197 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 197 insertions(+)
+ create mode 100644 arch/mips/configs/mt7621_defconfig
+
+--- /dev/null
++++ b/arch/mips/configs/mt7621_defconfig
+@@ -0,0 +1,197 @@
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_SYSVIPC=y
++CONFIG_HIGH_RES_TIMERS=y
++CONFIG_RCU_FANOUT=32
++CONFIG_UIDGID_STRICT_TYPE_CHECKS=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE="/openwrt/trunk/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/root-ramips /openwrt/trunk/target/linux/generic/image/initramfs-base-files.txt"
++CONFIG_INITRAMFS_ROOT_UID=1000
++CONFIG_INITRAMFS_ROOT_GID=1000
++# CONFIG_RD_GZIP is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++# CONFIG_AIO is not set
++CONFIG_EMBEDDED=y
++# CONFIG_VM_EVENT_COUNTERS is not set
++# CONFIG_SLUB_DEBUG is not set
++# CONFIG_COMPAT_BRK is not set
++CONFIG_MODULES=y
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_BLK_DEV_BSG is not set
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_SMP=y
++CONFIG_NR_CPUS=4
++CONFIG_SCHED_SMT=y
++# CONFIG_COMPACTION is not set
++# CONFIG_CROSS_MEMORY_ATTACH is not set
++# CONFIG_SECCOMP is not set
++CONFIG_HZ_100=y
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="rootfstype=squashfs,jffs2"
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_NET=y
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++CONFIG_IP_ADVANCED_ROUTER=y
++CONFIG_IP_MULTIPLE_TABLES=y
++CONFIG_IP_ROUTE_MULTIPATH=y
++CONFIG_IP_ROUTE_VERBOSE=y
++CONFIG_IP_MROUTE=y
++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
++CONFIG_ARPD=y
++CONFIG_SYN_COOKIES=y
++# 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 is not set
++# CONFIG_INET_DIAG is not set
++CONFIG_TCP_CONG_ADVANCED=y
++# CONFIG_TCP_CONG_BIC is not set
++# CONFIG_TCP_CONG_WESTWOOD is not set
++# CONFIG_TCP_CONG_HTCP is not set
++CONFIG_IPV6_PRIVACY=y
++# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET6_XFRM_MODE_BEET is not set
++# CONFIG_IPV6_SIT is not set
++CONFIG_IPV6_MULTIPLE_TABLES=y
++CONFIG_IPV6_SUBTREES=y
++CONFIG_IPV6_MROUTE=y
++CONFIG_NETFILTER=y
++# CONFIG_BRIDGE_NETFILTER is not set
++CONFIG_NF_CONNTRACK=m
++CONFIG_NF_CONNTRACK_FTP=m
++CONFIG_NF_CONNTRACK_IRC=m
++CONFIG_NETFILTER_XT_MARK=m
++CONFIG_NETFILTER_XT_TARGET_LOG=m
++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
++CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
++CONFIG_NETFILTER_XT_MATCH_COMMENT=m
++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
++CONFIG_NETFILTER_XT_MATCH_LIMIT=m
++CONFIG_NETFILTER_XT_MATCH_MAC=m
++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
++CONFIG_NETFILTER_XT_MATCH_STATE=m
++CONFIG_NETFILTER_XT_MATCH_TIME=m
++CONFIG_NF_CONNTRACK_IPV4=m
++# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
++CONFIG_IP_NF_IPTABLES=m
++CONFIG_IP_NF_FILTER=m
++CONFIG_IP_NF_TARGET_REJECT=m
++CONFIG_NF_NAT_IPV4=m
++CONFIG_IP_NF_TARGET_MASQUERADE=m
++CONFIG_IP_NF_TARGET_REDIRECT=m
++CONFIG_IP_NF_MANGLE=m
++CONFIG_IP_NF_RAW=m
++CONFIG_NF_CONNTRACK_IPV6=m
++CONFIG_IP6_NF_IPTABLES=m
++CONFIG_IP6_NF_MATCH_AH=m
++CONFIG_IP6_NF_MATCH_EUI64=m
++CONFIG_IP6_NF_MATCH_FRAG=m
++CONFIG_IP6_NF_MATCH_OPTS=m
++CONFIG_IP6_NF_MATCH_IPV6HEADER=m
++CONFIG_IP6_NF_MATCH_MH=m
++CONFIG_IP6_NF_MATCH_RT=m
++CONFIG_IP6_NF_FILTER=m
++CONFIG_IP6_NF_TARGET_REJECT=m
++CONFIG_IP6_NF_MANGLE=m
++CONFIG_IP6_NF_RAW=m
++CONFIG_BRIDGE=m
++# CONFIG_BRIDGE_IGMP_SNOOPING is not set
++CONFIG_VLAN_8021Q=y
++CONFIG_NET_SCHED=y
++CONFIG_NET_SCH_FQ_CODEL=y
++CONFIG_HAMRADIO=y
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++# CONFIG_FIRMWARE_IN_KERNEL is not set
++CONFIG_MTD=y
++CONFIG_MTD_CMDLINE_PARTS=y
++CONFIG_MTD_BLOCK=y
++CONFIG_MTD_CFI=y
++CONFIG_MTD_CFI_AMDSTD=y
++CONFIG_MTD_COMPLEX_MAPPINGS=y
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_M25P80=y
++CONFIG_EEPROM_93CX6=m
++CONFIG_SCSI=y
++CONFIG_BLK_DEV_SD=y
++CONFIG_NETDEVICES=y
++# CONFIG_NET_PACKET_ENGINE is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++CONFIG_PHYLIB=y
++CONFIG_SWCONFIG=y
++CONFIG_PPP=m
++CONFIG_PPP_FILTER=y
++CONFIG_PPP_MULTILINK=y
++CONFIG_PPPOE=m
++CONFIG_PPP_ASYNC=m
++CONFIG_ISDN=y
++# CONFIG_INPUT is not set
++# CONFIG_SERIO is not set
++# CONFIG_VT is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_DEVKMEM is not set
++CONFIG_SERIAL_8250=y
++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
++CONFIG_SERIAL_8250_CONSOLE=y
++# CONFIG_SERIAL_8250_PCI is not set
++CONFIG_SERIAL_8250_RUNTIME_UARTS=2
++CONFIG_SPI=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_SYSFS=y
++# CONFIG_HWMON is not set
++CONFIG_WATCHDOG=y
++CONFIG_WATCHDOG_CORE=y
++# CONFIG_VGA_ARB is not set
++CONFIG_USB=y
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_PLATFORM=y
++CONFIG_USB_MT7621_XHCI_PLATFORM=y
++CONFIG_USB_STORAGE=y
++CONFIG_USB_PHY=y
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++CONFIG_LEDS_GPIO=m
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
++CONFIG_STAGING=y
++CONFIG_USB_DWC2=m
++# CONFIG_IOMMU_SUPPORT is not set
++CONFIG_RESET_CONTROLLER=y
++# CONFIG_FIRMWARE_MEMMAP is not set
++# CONFIG_DNOTIFY is not set
++# CONFIG_PROC_PAGE_MONITOR is not set
++CONFIG_TMPFS=y
++CONFIG_TMPFS_XATTR=y
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_SUMMARY=y
++CONFIG_JFFS2_FS_XATTR=y
++# CONFIG_JFFS2_FS_POSIX_ACL is not set
++# CONFIG_JFFS2_FS_SECURITY is not set
++CONFIG_JFFS2_COMPRESSION_OPTIONS=y
++# CONFIG_JFFS2_ZLIB is not set
++CONFIG_SQUASHFS=y
++# CONFIG_SQUASHFS_ZLIB is not set
++CONFIG_SQUASHFS_XZ=y
++CONFIG_PRINTK_TIME=y
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_STRIP_ASM_SYMS=y
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++# CONFIG_SCHED_DEBUG is not set
++CONFIG_DEBUG_INFO=y
++CONFIG_DEBUG_INFO_REDUCED=y
++CONFIG_RCU_CPU_STALL_TIMEOUT=60
++# CONFIG_FTRACE is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_VIRTUALIZATION is not set
++CONFIG_CRC_ITU_T=m
++CONFIG_CRC32_SARWATE=y
++# CONFIG_XZ_DEC_X86 is not set
++CONFIG_AVERAGE=y
diff --git a/target/linux/ramips/patches-4.4/0004-MIPS-ralink-add-MT7621-pcie-driver.patch b/target/linux/ramips/patches-4.4/0004-MIPS-ralink-add-MT7621-pcie-driver.patch
new file mode 100644 (file)
index 0000000..d4c1506
--- /dev/null
@@ -0,0 +1,857 @@
+From fec11d4e8dc5cc79bcd7c8fd55038ac21ac39965 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 16 Mar 2014 05:22:39 +0000
+Subject: [PATCH 04/53] MIPS: ralink: add MT7621 pcie driver
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/pci/Makefile     |    1 +
+ arch/mips/pci/pci-mt7621.c |  813 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 814 insertions(+)
+ create mode 100644 arch/mips/pci/pci-mt7621.c
+
+--- a/arch/mips/pci/Makefile
++++ b/arch/mips/pci/Makefile
+@@ -43,6 +43,7 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1
+ obj-$(CONFIG_SNI_RM)          += fixup-sni.o ops-sni.o
+ obj-$(CONFIG_LANTIQ)          += fixup-lantiq.o
+ obj-$(CONFIG_PCI_LANTIQ)      += pci-lantiq.o ops-lantiq.o
++obj-$(CONFIG_SOC_MT7621)      += pci-mt7621.o
+ obj-$(CONFIG_SOC_RT288X)      += pci-rt2880.o
+ obj-$(CONFIG_SOC_RT3883)      += pci-rt3883.o
+ obj-$(CONFIG_TANBAC_TB0219)   += fixup-tb0219.o
+--- /dev/null
++++ b/arch/mips/pci/pci-mt7621.c
+@@ -0,0 +1,832 @@
++/**************************************************************************
++ *
++ *  BRIEF MODULE DESCRIPTION
++ *     PCI init for Ralink RT2880 solution
++ *
++ *  Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw)
++ *
++ *  This program is free software; you can redistribute  it and/or modify it
++ *  under  the terms of  the GNU General  Public License as published by the
++ *  Free Software Foundation;  either version 2 of the  License, or (at your
++ *  option) any later version.
++ *
++ *  THIS  SOFTWARE  IS PROVIDED   ``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 AUTHOR  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.
++ *
++ *  You 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.
++ *
++ *
++ **************************************************************************
++ * May 2007 Bruce Chang
++ * Initial Release
++ *
++ * May 2009 Bruce Chang
++ * support RT2880/RT3883 PCIe
++ *
++ * May 2011 Bruce Chang
++ * support RT6855/MT7620 PCIe
++ *
++ **************************************************************************
++ */
++
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/version.h>
++#include <asm/pci.h>
++#include <asm/io.h>
++#include <asm/mips-cm.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/of.h>
++#include <linux/of_pci.h>
++#include <linux/platform_device.h>
++
++#include <ralink_regs.h>
++
++extern void pcie_phy_init(void);
++extern void chk_phy_pll(void);
++
++/*
++ * These functions and structures provide the BIOS scan and mapping of the PCI
++ * devices.
++ */
++
++#define CONFIG_PCIE_PORT0
++#define CONFIG_PCIE_PORT1
++#define CONFIG_PCIE_PORT2
++#define RALINK_PCIE0_CLK_EN             (1<<24)
++#define RALINK_PCIE1_CLK_EN             (1<<25)
++#define RALINK_PCIE2_CLK_EN             (1<<26)
++
++#define RALINK_PCI_CONFIG_ADDR                         0x20
++#define RALINK_PCI_CONFIG_DATA_VIRTUAL_REG     0x24
++#define SURFBOARDINT_PCIE0       11      /* PCIE0 */
++#define RALINK_INT_PCIE0         SURFBOARDINT_PCIE0
++#define RALINK_INT_PCIE1         SURFBOARDINT_PCIE1
++#define RALINK_INT_PCIE2         SURFBOARDINT_PCIE2
++#define SURFBOARDINT_PCIE1       31     /* PCIE1 */
++#define SURFBOARDINT_PCIE2       32     /* PCIE2 */
++#define RALINK_PCI_MEMBASE              *(volatile u32 *)(RALINK_PCI_BASE + 0x0028)
++#define RALINK_PCI_IOBASE               *(volatile u32 *)(RALINK_PCI_BASE + 0x002C)
++#define RALINK_PCIE0_RST                (1<<24)
++#define RALINK_PCIE1_RST                (1<<25)
++#define RALINK_PCIE2_RST                (1<<26)
++#define RALINK_SYSCTL_BASE              0xBE000000
++
++#define RALINK_PCI_PCICFG_ADDR          *(volatile u32 *)(RALINK_PCI_BASE + 0x0000)
++#define RALINK_PCI_PCIMSK_ADDR          *(volatile u32 *)(RALINK_PCI_BASE + 0x000C)
++#define RALINK_PCI_BASE                 0xBE140000
++
++#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000)
++#define RT6855_PCIE0_OFFSET     0x2000
++#define RT6855_PCIE1_OFFSET     0x3000
++#define RT6855_PCIE2_OFFSET     0x4000
++
++#define RALINK_PCI0_BAR0SETUP_ADDR      *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0010)
++#define RALINK_PCI0_IMBASEBAR0_ADDR     *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0018)
++#define RALINK_PCI0_ID                  *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0030)
++#define RALINK_PCI0_CLASS               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0034)
++#define RALINK_PCI0_SUBID               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0038)
++#define RALINK_PCI0_STATUS              *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0050)
++#define RALINK_PCI0_DERR                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0060)
++#define RALINK_PCI0_ECRC                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0064)
++
++#define RALINK_PCI1_BAR0SETUP_ADDR      *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0010)
++#define RALINK_PCI1_IMBASEBAR0_ADDR     *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0018)
++#define RALINK_PCI1_ID                  *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0030)
++#define RALINK_PCI1_CLASS               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0034)
++#define RALINK_PCI1_SUBID               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0038)
++#define RALINK_PCI1_STATUS              *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0050)
++#define RALINK_PCI1_DERR                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0060)
++#define RALINK_PCI1_ECRC                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0064)
++
++#define RALINK_PCI2_BAR0SETUP_ADDR      *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0010)
++#define RALINK_PCI2_IMBASEBAR0_ADDR     *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0018)
++#define RALINK_PCI2_ID                  *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0030)
++#define RALINK_PCI2_CLASS               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0034)
++#define RALINK_PCI2_SUBID               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0038)
++#define RALINK_PCI2_STATUS              *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0050)
++#define RALINK_PCI2_DERR                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0060)
++#define RALINK_PCI2_ECRC                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0064)
++
++#define RALINK_PCIEPHY_P0P1_CTL_OFFSET  (RALINK_PCI_BASE + 0x9000)
++#define RALINK_PCIEPHY_P2_CTL_OFFSET    (RALINK_PCI_BASE + 0xA000)
++
++
++#define MV_WRITE(ofs, data)  \
++        *(volatile u32 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le32(data)
++#define MV_READ(ofs, data)   \
++              *(data) = le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs)))
++#define MV_READ_DATA(ofs)    \
++                      le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs)))
++
++#define MV_WRITE_16(ofs, data)  \
++        *(volatile u16 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le16(data)
++#define MV_READ_16(ofs, data)   \
++              *(data) = le16_to_cpu(*(volatile u16 *)(RALINK_PCI_BASE+(ofs)))
++
++#define MV_WRITE_8(ofs, data)  \
++        *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) = data
++#define MV_READ_8(ofs, data)   \
++              *(data) = *(volatile u8 *)(RALINK_PCI_BASE+(ofs))
++
++
++
++#define RALINK_PCI_MM_MAP_BASE        0x60000000
++#define RALINK_PCI_IO_MAP_BASE        0x1e160000
++
++#define RALINK_SYSTEM_CONTROL_BASE    0xbe000000
++#define GPIO_PERST
++#define ASSERT_SYSRST_PCIE(val)               do {    \
++                                              if (*(unsigned int *)(0xbe00000c) == 0x00030101)        \
++                                                      RALINK_RSTCTRL |= val;  \
++                                              else    \
++                                                      RALINK_RSTCTRL &= ~val; \
++                                      } while(0)
++#define DEASSERT_SYSRST_PCIE(val)     do {    \
++                                              if (*(unsigned int *)(0xbe00000c) == 0x00030101)        \
++                                                      RALINK_RSTCTRL &= ~val; \
++                                              else    \
++                                                      RALINK_RSTCTRL |= val;  \
++                                      } while(0)
++#define RALINK_SYSCFG1                        *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x14)
++#define RALINK_CLKCFG1                        *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x30)
++#define RALINK_RSTCTRL                        *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x34)
++#define RALINK_GPIOMODE                       *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x60)
++#define RALINK_PCIE_CLK_GEN           *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x7c)
++#define RALINK_PCIE_CLK_GEN1          *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x80)
++#define PPLL_CFG1                     *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x9c)
++#define PPLL_DRV                      *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0xa0)
++//RALINK_SYSCFG1 bit
++#define RALINK_PCI_HOST_MODE_EN               (1<<7)
++#define RALINK_PCIE_RC_MODE_EN                (1<<8)
++//RALINK_RSTCTRL bit
++#define RALINK_PCIE_RST                       (1<<23)
++#define RALINK_PCI_RST                        (1<<24)
++//RALINK_CLKCFG1 bit
++#define RALINK_PCI_CLK_EN             (1<<19)
++#define RALINK_PCIE_CLK_EN            (1<<21)
++//RALINK_GPIOMODE bit
++#define PCI_SLOTx2                    (1<<11)
++#define PCI_SLOTx1                    (2<<11)
++//MTK PCIE PLL bit
++#define PDRV_SW_SET                   (1<<31)
++#define LC_CKDRVPD_                   (1<<19)
++
++#define MEMORY_BASE 0x0
++static int pcie_link_status = 0;
++
++#define PCI_ACCESS_READ_1  0
++#define PCI_ACCESS_READ_2  1
++#define PCI_ACCESS_READ_4  2
++#define PCI_ACCESS_WRITE_1 3
++#define PCI_ACCESS_WRITE_2 4
++#define PCI_ACCESS_WRITE_4 5
++
++static int config_access(unsigned char access_type, struct pci_bus *bus,
++                      unsigned int devfn, unsigned int where, u32 * data)
++{
++      unsigned int slot = PCI_SLOT(devfn);
++      u8 func = PCI_FUNC(devfn);
++      uint32_t address_reg, data_reg;
++      unsigned int address;
++
++      address_reg = RALINK_PCI_CONFIG_ADDR;
++      data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
++
++      address = (((where&0xF00)>>8)<<24) |(bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000;
++      MV_WRITE(address_reg, address);
++
++      switch(access_type) {
++      case PCI_ACCESS_WRITE_1:
++              MV_WRITE_8(data_reg+(where&0x3), *data);
++              break;
++      case PCI_ACCESS_WRITE_2:
++              MV_WRITE_16(data_reg+(where&0x3), *data);
++              break;
++      case PCI_ACCESS_WRITE_4:
++              MV_WRITE(data_reg, *data);
++              break;
++      case PCI_ACCESS_READ_1:
++              MV_READ_8( data_reg+(where&0x3), data);
++              break;
++      case PCI_ACCESS_READ_2:
++              MV_READ_16(data_reg+(where&0x3), data);
++              break;
++      case PCI_ACCESS_READ_4:
++              MV_READ(data_reg, data);
++              break;
++      default:
++              printk("no specify access type\n");
++              break;
++      }
++      return 0;
++}
++
++static int
++read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val)
++{
++      return config_access(PCI_ACCESS_READ_1, bus, devfn, (unsigned int)where, (u32 *)val);
++}
++
++static int
++read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val)
++{
++      return config_access(PCI_ACCESS_READ_2, bus, devfn, (unsigned int)where, (u32 *)val);
++}
++
++static int
++read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val)
++{
++      return config_access(PCI_ACCESS_READ_4, bus, devfn, (unsigned int)where, (u32 *)val);
++}
++
++static int
++write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val)
++{
++      if (config_access(PCI_ACCESS_WRITE_1, bus, devfn, (unsigned int)where, (u32 *)&val))
++              return -1;
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++static int
++write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val)
++{
++      if (config_access(PCI_ACCESS_WRITE_2, bus, devfn, where, (u32 *)&val))
++              return -1;
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++static int
++write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val)
++{
++      if (config_access(PCI_ACCESS_WRITE_4, bus, devfn, where, &val))
++              return -1;
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++
++static int
++pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val)
++{
++      switch (size) {
++      case 1:
++              return read_config_byte(bus, devfn, where, (u8 *) val);
++      case 2:
++              return read_config_word(bus, devfn, where, (u16 *) val);
++      default:
++              return read_config_dword(bus, devfn, where, val);
++      }
++}
++
++static int
++pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
++{
++      switch (size) {
++      case 1:
++              return write_config_byte(bus, devfn, where, (u8) val);
++      case 2:
++              return write_config_word(bus, devfn, where, (u16) val);
++      default:
++              return write_config_dword(bus, devfn, where, val);
++      }
++}
++
++struct pci_ops mt7621_pci_ops= {
++      .read           =  pci_config_read,
++      .write          = pci_config_write,
++};
++
++static struct resource mt7621_res_pci_mem1 = {
++      .name           = "PCI MEM1",
++      .start          = RALINK_PCI_MM_MAP_BASE,
++      .end            = (u32)((RALINK_PCI_MM_MAP_BASE + (unsigned char *)0x0fffffff)),
++      .flags          = IORESOURCE_MEM,
++};
++static struct resource mt7621_res_pci_io1 = {
++      .name           = "PCI I/O1",
++      .start          = RALINK_PCI_IO_MAP_BASE,
++      .end            = (u32)((RALINK_PCI_IO_MAP_BASE + (unsigned char *)0x0ffff)),
++      .flags          = IORESOURCE_IO,
++};
++
++static struct pci_controller mt7621_controller = {
++      .pci_ops        = &mt7621_pci_ops,
++      .mem_resource   = &mt7621_res_pci_mem1,
++      .io_resource    = &mt7621_res_pci_io1,
++      .mem_offset     = 0x00000000UL,
++      .io_offset      = 0x00000000UL,
++      .io_map_base    = 0xa0000000,
++};
++
++static void
++read_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long *val)
++{
++      unsigned int address_reg, data_reg, address;
++
++      address_reg = RALINK_PCI_CONFIG_ADDR;
++        data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
++      address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ;
++        MV_WRITE(address_reg, address);
++        MV_READ(data_reg, val);
++      return;
++}
++
++static void
++write_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long val)
++{
++      unsigned int address_reg, data_reg, address;
++
++      address_reg = RALINK_PCI_CONFIG_ADDR;
++      data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG;
++      address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ;
++      MV_WRITE(address_reg, address);
++      MV_WRITE(data_reg, val);
++      return;
++}
++
++
++int __init
++pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++      u16 cmd;
++      u32 val;
++      int irq = 0;
++
++      if ((dev->bus->number == 0) && (slot == 0)) {
++              write_config(0, 0, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
++              read_config(0, 0, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
++              printk("BAR0 at slot 0 = %x\n", val);
++              printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
++      } else if((dev->bus->number == 0) && (slot == 0x1)) {
++              write_config(0, 1, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
++              read_config(0, 1, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
++              printk("BAR0 at slot 1 = %x\n", val);
++              printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
++      } else if((dev->bus->number == 0) && (slot == 0x2)) {
++              write_config(0, 2, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE);
++              read_config(0, 2, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val);
++              printk("BAR0 at slot 2 = %x\n", val);
++              printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
++      } else if ((dev->bus->number == 1) && (slot == 0x0)) {
++              switch (pcie_link_status) {
++              case 2:
++              case 6:
++                      irq = RALINK_INT_PCIE1;
++                      break;
++              case 4:
++                      irq = RALINK_INT_PCIE2;
++                      break;
++              default:
++                      irq = RALINK_INT_PCIE0;
++              }
++              printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
++      } else if ((dev->bus->number == 2) && (slot == 0x0)) {
++              switch (pcie_link_status) {
++              case 5:
++              case 6:
++                      irq = RALINK_INT_PCIE2;
++                      break;
++              default:
++                      irq = RALINK_INT_PCIE1;
++              }
++              printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
++      } else if ((dev->bus->number == 2) && (slot == 0x1)) {
++              switch (pcie_link_status) {
++              case 5:
++              case 6:
++                      irq = RALINK_INT_PCIE2;
++                      break;
++              default:
++                      irq = RALINK_INT_PCIE1;
++              }
++              printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
++      } else if ((dev->bus->number ==3) && (slot == 0x0)) {
++              irq = RALINK_INT_PCIE2;
++              printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
++      } else if ((dev->bus->number ==3) && (slot == 0x1)) {
++              irq = RALINK_INT_PCIE2;
++              printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
++      } else if ((dev->bus->number ==3) && (slot == 0x2)) {
++              irq = RALINK_INT_PCIE2;
++              printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq);
++      } else {
++              printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot);
++              return 0;
++      }
++
++      pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14);  //configure cache line size 0x14
++      pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF);  //configure latency timer 0x10
++      pci_read_config_word(dev, PCI_COMMAND, &cmd);
++      cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
++      pci_write_config_word(dev, PCI_COMMAND, cmd);
++      pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
++      return irq;
++}
++
++void
++set_pcie_phy(u32 *addr, int start_b, int bits, int val)
++{
++//    printk("0x%p:", addr);
++//    printk(" %x", *addr);
++      *(unsigned int *)(addr) &= ~(((1<<bits) - 1)<<start_b);
++      *(unsigned int *)(addr) |= val << start_b;
++//    printk(" -> %x\n", *addr);
++}
++
++void
++bypass_pipe_rst(void)
++{
++#if defined (CONFIG_PCIE_PORT0)
++      /* PCIe Port 0 */
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 12, 1, 0x01);     // rg_pe1_pipe_rst_b
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c),  4, 1, 0x01);     // rg_pe1_pipe_cmd_frc[4]
++#endif
++#if defined (CONFIG_PCIE_PORT1)
++      /* PCIe Port 1 */
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 12, 1, 0x01);     // rg_pe1_pipe_rst_b
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c),  4, 1, 0x01);     // rg_pe1_pipe_cmd_frc[4]
++#endif
++#if defined (CONFIG_PCIE_PORT2)
++      /* PCIe Port 2 */
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 12, 1, 0x01);       // rg_pe1_pipe_rst_b
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c),  4, 1, 0x01);       // rg_pe1_pipe_cmd_frc[4]
++#endif
++}
++
++void
++set_phy_for_ssc(void)
++{
++      unsigned long reg = (*(volatile u32 *)(RALINK_SYSCTL_BASE + 0x10));
++
++      reg = (reg >> 6) & 0x7;
++#if defined (CONFIG_PCIE_PORT0) || defined (CONFIG_PCIE_PORT1)
++      /* Set PCIe Port0 & Port1 PHY to disable SSC */
++      /* Debug Xtal Type */
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400),  8, 1, 0x01);     // rg_pe1_frc_h_xtal_type
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400),  9, 2, 0x00);     // rg_pe1_h_xtal_type
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000),  4, 1, 0x01);     // rg_pe1_frc_phy_en               //Force Port 0 enable control
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100),  4, 1, 0x01);     // rg_pe1_frc_phy_en               //Force Port 1 enable control
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000),  5, 1, 0x00);     // rg_pe1_phy_en                   //Port 0 disable
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100),  5, 1, 0x00);     // rg_pe1_phy_en                   //Port 1 disable
++      if(reg <= 5 && reg >= 3) {      // 40MHz Xtal
++              set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490),  6, 2, 0x01);     // RG_PE1_H_PLL_PREDIV             //Pre-divider ratio (for host mode)
++              printk("***** Xtal 40MHz *****\n");
++      } else {                        // 25MHz | 20MHz Xtal
++              set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490),  6, 2, 0x00);     // RG_PE1_H_PLL_PREDIV             //Pre-divider ratio (for host mode)
++              if (reg >= 6) {         
++                      printk("***** Xtal 25MHz *****\n");
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4bc),  4, 2, 0x01);     // RG_PE1_H_PLL_FBKSEL             //Feedback clock select
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x49c),  0,31, 0x18000000);       // RG_PE1_H_LCDDS_PCW_NCPO         //DDS NCPO PCW (for host mode)
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a4),  0,16, 0x18d);    // RG_PE1_H_LCDDS_SSC_PRD          //DDS SSC dither period control
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8),  0,12, 0x4a);     // RG_PE1_H_LCDDS_SSC_DELTA        //DDS SSC dither amplitude control
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 16,12, 0x4a);     // RG_PE1_H_LCDDS_SSC_DELTA1       //DDS SSC dither amplitude control for initial
++              } else {
++                      printk("***** Xtal 20MHz *****\n");
++              }
++      }
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a0),  5, 1, 0x01);     // RG_PE1_LCDDS_CLK_PH_INV         //DDS clock inversion
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 22, 2, 0x02);     // RG_PE1_H_PLL_BC                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 18, 4, 0x06);     // RG_PE1_H_PLL_BP                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 12, 4, 0x02);     // RG_PE1_H_PLL_IR                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490),  8, 4, 0x01);     // RG_PE1_H_PLL_IC                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4ac), 16, 3, 0x00);     // RG_PE1_H_PLL_BR                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490),  1, 3, 0x02);     // RG_PE1_PLL_DIVEN                
++      if(reg <= 5 && reg >= 3) {      // 40MHz Xtal
++              set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414),  6, 2, 0x01);     // rg_pe1_mstckdiv              //value of da_pe1_mstckdiv when force mode enable
++              set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414),  5, 1, 0x01);     // rg_pe1_frc_mstckdiv          //force mode enable of da_pe1_mstckdiv      
++      }
++      /* Enable PHY and disable force mode */
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000),  5, 1, 0x01);     // rg_pe1_phy_en                   //Port 0 enable
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100),  5, 1, 0x01);     // rg_pe1_phy_en                   //Port 1 enable
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000),  4, 1, 0x00);     // rg_pe1_frc_phy_en               //Force Port 0 disable control
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100),  4, 1, 0x00);     // rg_pe1_frc_phy_en               //Force Port 1 disable control
++#endif
++#if defined (CONFIG_PCIE_PORT2)
++      /* Set PCIe Port2 PHY to disable SSC */
++      /* Debug Xtal Type */
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400),  8, 1, 0x01);       // rg_pe1_frc_h_xtal_type
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400),  9, 2, 0x00);       // rg_pe1_h_xtal_type
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000),  4, 1, 0x01);       // rg_pe1_frc_phy_en               //Force Port 0 enable control
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000),  5, 1, 0x00);       // rg_pe1_phy_en                   //Port 0 disable
++      if(reg <= 5 && reg >= 3) {      // 40MHz Xtal
++              set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490),  6, 2, 0x01);       // RG_PE1_H_PLL_PREDIV             //Pre-divider ratio (for host mode)
++      } else {                        // 25MHz | 20MHz Xtal
++              set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490),  6, 2, 0x00);       // RG_PE1_H_PLL_PREDIV             //Pre-divider ratio (for host mode)
++              if (reg >= 6) {         // 25MHz Xtal
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4bc),  4, 2, 0x01);       // RG_PE1_H_PLL_FBKSEL             //Feedback clock select
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x49c),  0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO         //DDS NCPO PCW (for host mode)
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a4),  0,16, 0x18d);      // RG_PE1_H_LCDDS_SSC_PRD          //DDS SSC dither period control
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8),  0,12, 0x4a);       // RG_PE1_H_LCDDS_SSC_DELTA        //DDS SSC dither amplitude control
++                      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 16,12, 0x4a);       // RG_PE1_H_LCDDS_SSC_DELTA1       //DDS SSC dither amplitude control for initial
++              }
++      }
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a0),  5, 1, 0x01);       // RG_PE1_LCDDS_CLK_PH_INV         //DDS clock inversion
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 22, 2, 0x02);       // RG_PE1_H_PLL_BC                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 18, 4, 0x06);       // RG_PE1_H_PLL_BP                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 12, 4, 0x02);       // RG_PE1_H_PLL_IR                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490),  8, 4, 0x01);       // RG_PE1_H_PLL_IC                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4ac), 16, 3, 0x00);       // RG_PE1_H_PLL_BR                 
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490),  1, 3, 0x02);       // RG_PE1_PLL_DIVEN                
++      if(reg <= 5 && reg >= 3) {      // 40MHz Xtal
++              set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414),  6, 2, 0x01);       // rg_pe1_mstckdiv              //value of da_pe1_mstckdiv when force mode enable
++              set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414),  5, 1, 0x01);       // rg_pe1_frc_mstckdiv          //force mode enable of da_pe1_mstckdiv      
++      }
++      /* Enable PHY and disable force mode */
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000),  5, 1, 0x01);       // rg_pe1_phy_en                   //Port 0 enable
++      set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000),  4, 1, 0x00);       // rg_pe1_frc_phy_en               //Force Port 0 disable control
++#endif
++}
++
++void setup_cm_memory_region(struct resource *mem_resource)
++{
++      resource_size_t mask;
++      if (mips_cm_numiocu()) {
++              /* FIXME: hardware doesn't accept mask values with 1s after
++                 0s (e.g. 0xffef), so it would be great to warn if that's
++                 about to happen */
++              mask = ~(mem_resource->end - mem_resource->start);
++
++              write_gcr_reg1_base(mem_resource->start);
++              write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0);
++              printk("PCI coherence region base: 0x%08lx, mask/settings: 0x%08lx\n",
++                     read_gcr_reg1_base(),
++                     read_gcr_reg1_mask());
++      }
++}
++
++static int mt7621_pci_probe(struct platform_device *pdev)
++{
++      unsigned long val = 0;
++
++      iomem_resource.start = 0;
++      iomem_resource.end= ~0;
++      ioport_resource.start= 0;
++      ioport_resource.end = ~0;
++
++#if defined (CONFIG_PCIE_PORT0)
++      val = RALINK_PCIE0_RST;
++#endif
++#if defined (CONFIG_PCIE_PORT1)
++      val |= RALINK_PCIE1_RST;
++#endif
++#if defined (CONFIG_PCIE_PORT2)
++      val |= RALINK_PCIE2_RST;
++#endif
++      ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST | RALINK_PCIE1_RST | RALINK_PCIE2_RST);
++      printk("pull PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
++#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/
++      *(unsigned int *)(0xbe000060) &= ~(0x3<<10 | 0x3<<3);
++      *(unsigned int *)(0xbe000060) |= 0x1<<10 | 0x1<<3;
++      mdelay(100);
++      *(unsigned int *)(0xbe000600) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // use GPIO19/GPIO8/GPIO7 (PERST_N/UART_RXD3/UART_TXD3)
++      mdelay(100);
++      *(unsigned int *)(0xbe000620) &= ~(0x1<<19 | 0x1<<8 | 0x1<<7);          // clear DATA
++
++      mdelay(100);
++#else
++      *(unsigned int *)(0xbe000060) &= ~0x00000c00;
++#endif
++#if defined (CONFIG_PCIE_PORT0)
++      val = RALINK_PCIE0_RST;
++#endif
++#if defined (CONFIG_PCIE_PORT1)
++      val |= RALINK_PCIE1_RST;
++#endif
++#if defined (CONFIG_PCIE_PORT2)
++      val |= RALINK_PCIE2_RST;
++#endif
++      DEASSERT_SYSRST_PCIE(val);
++      printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
++
++      if ((*(unsigned int *)(0xbe00000c)&0xFFFF) == 0x0101) // MT7621 E2
++              bypass_pipe_rst();
++      set_phy_for_ssc();
++      printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL);
++
++#if defined (CONFIG_PCIE_PORT0)
++      read_config(0, 0, 0, 0x70c, &val);
++      printk("Port 0 N_FTS = %x\n", (unsigned int)val);
++#endif
++#if defined (CONFIG_PCIE_PORT1)
++      read_config(0, 1, 0, 0x70c, &val);
++      printk("Port 1 N_FTS = %x\n", (unsigned int)val);
++#endif
++#if defined (CONFIG_PCIE_PORT2)
++      read_config(0, 2, 0, 0x70c, &val);
++      printk("Port 2 N_FTS = %x\n", (unsigned int)val);
++#endif
++
++      RALINK_RSTCTRL = (RALINK_RSTCTRL | RALINK_PCIE_RST);
++      RALINK_SYSCFG1 &= ~(0x30);
++      RALINK_SYSCFG1 |= (2<<4);
++      RALINK_PCIE_CLK_GEN &= 0x7fffffff;
++      RALINK_PCIE_CLK_GEN1 &= 0x80ffffff;
++      RALINK_PCIE_CLK_GEN1 |= 0xa << 24;
++      RALINK_PCIE_CLK_GEN |= 0x80000000;
++      mdelay(50);
++      RALINK_RSTCTRL = (RALINK_RSTCTRL & ~RALINK_PCIE_RST);
++      
++
++#if defined GPIO_PERST /* add GPIO control instead of PERST_N */  /*chhung*/
++      *(unsigned int *)(0xbe000620) |= 0x1<<19 | 0x1<<8 | 0x1<<7;             // set DATA
++      mdelay(100);
++#else
++      RALINK_PCI_PCICFG_ADDR &= ~(1<<1); //de-assert PERST
++#endif
++      mdelay(500);
++
++
++      mdelay(500);
++#if defined (CONFIG_PCIE_PORT0)
++      if(( RALINK_PCI0_STATUS & 0x1) == 0)
++      {
++              printk("PCIE0 no card, disable it(RST&CLK)\n");
++              ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST);
++              RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE0_CLK_EN);
++              pcie_link_status &= ~(1<<0);
++      } else {
++              pcie_link_status |= 1<<0;
++              RALINK_PCI_PCIMSK_ADDR |= (1<<20); // enable pcie1 interrupt
++      }
++#endif
++#if defined (CONFIG_PCIE_PORT1)
++      if(( RALINK_PCI1_STATUS & 0x1) == 0)
++      {
++              printk("PCIE1 no card, disable it(RST&CLK)\n");
++              ASSERT_SYSRST_PCIE(RALINK_PCIE1_RST);
++              RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE1_CLK_EN);
++              pcie_link_status &= ~(1<<1);
++      } else {
++              pcie_link_status |= 1<<1;
++              RALINK_PCI_PCIMSK_ADDR |= (1<<21); // enable pcie1 interrupt
++      }
++#endif
++#if defined (CONFIG_PCIE_PORT2)
++      if (( RALINK_PCI2_STATUS & 0x1) == 0) {
++              printk("PCIE2 no card, disable it(RST&CLK)\n");
++              ASSERT_SYSRST_PCIE(RALINK_PCIE2_RST);
++              RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE2_CLK_EN);
++              pcie_link_status &= ~(1<<2);
++      } else {
++              pcie_link_status |= 1<<2;
++              RALINK_PCI_PCIMSK_ADDR |= (1<<22); // enable pcie2 interrupt
++      }
++#endif
++      if (pcie_link_status == 0)
++              return 0;
++
++/*
++pcie(2/1/0) link status       pcie2_num       pcie1_num       pcie0_num
++3'b000                        x               x               x
++3'b001                        x               x               0
++3'b010                        x               0               x
++3'b011                        x               1               0
++3'b100                        0               x               x
++3'b101                        1               x               0
++3'b110                        1               0               x
++3'b111                        2               1               0
++*/
++      switch(pcie_link_status) {
++      case 2:
++              RALINK_PCI_PCICFG_ADDR &= ~0x00ff0000;
++              RALINK_PCI_PCICFG_ADDR |= 0x1 << 16;    //port0
++              RALINK_PCI_PCICFG_ADDR |= 0x0 << 20;    //port1
++              break;
++      case 4:
++              RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
++              RALINK_PCI_PCICFG_ADDR |= 0x1 << 16;    //port0
++              RALINK_PCI_PCICFG_ADDR |= 0x2 << 20;    //port1
++              RALINK_PCI_PCICFG_ADDR |= 0x0 << 24;    //port2
++              break;
++      case 5:
++              RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
++              RALINK_PCI_PCICFG_ADDR |= 0x0 << 16;    //port0
++              RALINK_PCI_PCICFG_ADDR |= 0x2 << 20;    //port1
++              RALINK_PCI_PCICFG_ADDR |= 0x1 << 24;    //port2
++              break;
++      case 6:
++              RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000;
++              RALINK_PCI_PCICFG_ADDR |= 0x2 << 16;    //port0
++              RALINK_PCI_PCICFG_ADDR |= 0x0 << 20;    //port1
++              RALINK_PCI_PCICFG_ADDR |= 0x1 << 24;    //port2
++              break;
++      }
++      printk(" -> %x\n", RALINK_PCI_PCICFG_ADDR);
++      //printk(" RALINK_PCI_ARBCTL = %x\n", RALINK_PCI_ARBCTL);
++
++/*
++      ioport_resource.start = mt7621_res_pci_io1.start;
++      ioport_resource.end = mt7621_res_pci_io1.end;
++*/
++
++      RALINK_PCI_MEMBASE = 0xffffffff; //RALINK_PCI_MM_MAP_BASE;
++      RALINK_PCI_IOBASE = RALINK_PCI_IO_MAP_BASE;
++
++#if defined (CONFIG_PCIE_PORT0)
++      //PCIe0
++      if((pcie_link_status & 0x1) != 0) {
++              RALINK_PCI0_BAR0SETUP_ADDR = 0x7FFF0001;        //open 7FFF:2G; ENABLE
++              RALINK_PCI0_IMBASEBAR0_ADDR = MEMORY_BASE;
++              RALINK_PCI0_CLASS = 0x06040001;
++              printk("PCIE0 enabled\n");
++      }
++#endif
++#if defined (CONFIG_PCIE_PORT1)
++      //PCIe1
++      if ((pcie_link_status & 0x2) != 0) {
++              RALINK_PCI1_BAR0SETUP_ADDR = 0x7FFF0001;        //open 7FFF:2G; ENABLE
++              RALINK_PCI1_IMBASEBAR0_ADDR = MEMORY_BASE;
++              RALINK_PCI1_CLASS = 0x06040001;
++              printk("PCIE1 enabled\n");
++      }
++#endif
++#if defined (CONFIG_PCIE_PORT2)
++      //PCIe2
++      if ((pcie_link_status & 0x4) != 0) {
++              RALINK_PCI2_BAR0SETUP_ADDR = 0x7FFF0001;        //open 7FFF:2G; ENABLE
++              RALINK_PCI2_IMBASEBAR0_ADDR = MEMORY_BASE;
++              RALINK_PCI2_CLASS = 0x06040001;
++              printk("PCIE2 enabled\n");
++      }
++#endif
++
++
++      switch(pcie_link_status) {
++      case 7:
++              read_config(0, 2, 0, 0x4, &val);
++              write_config(0, 2, 0, 0x4, val|0x4);
++              // write_config(0, 1, 0, 0x4, val|0x7);
++              read_config(0, 2, 0, 0x70c, &val);
++              val &= ~(0xff)<<8;
++              val |= 0x50<<8;
++              write_config(0, 2, 0, 0x70c, val);
++      case 3:
++      case 5:
++      case 6:
++              read_config(0, 1, 0, 0x4, &val);
++              write_config(0, 1, 0, 0x4, val|0x4);
++              // write_config(0, 1, 0, 0x4, val|0x7);
++              read_config(0, 1, 0, 0x70c, &val);
++              val &= ~(0xff)<<8;
++              val |= 0x50<<8;
++              write_config(0, 1, 0, 0x70c, val);
++      default:
++              read_config(0, 0, 0, 0x4, &val);
++              write_config(0, 0, 0, 0x4, val|0x4); //bus master enable
++              // write_config(0, 0, 0, 0x4, val|0x7); //bus master enable
++              read_config(0, 0, 0, 0x70c, &val);
++              val &= ~(0xff)<<8;
++              val |= 0x50<<8;
++              write_config(0, 0, 0, 0x70c, val);
++      }
++
++      pci_load_of_ranges(&mt7621_controller, pdev->dev.of_node);
++      setup_cm_memory_region(mt7621_controller.mem_resource);
++      register_pci_controller(&mt7621_controller);
++      return 0;
++
++}
++
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++      return 0;
++}
++
++static const struct of_device_id mt7621_pci_ids[] = {
++      { .compatible = "mediatek,mt7621-pci" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, mt7621_pci_ids);
++
++static struct platform_driver mt7621_pci_driver = {
++      .probe = mt7621_pci_probe,
++      .driver = {
++              .name = "mt7621-pci",
++              .owner = THIS_MODULE,
++              .of_match_table = of_match_ptr(mt7621_pci_ids),
++      },
++};
++
++static int __init mt7621_pci_init(void)
++{
++      return platform_driver_register(&mt7621_pci_driver);
++}
++
++arch_initcall(mt7621_pci_init);
diff --git a/target/linux/ramips/patches-4.4/0005-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch b/target/linux/ramips/patches-4.4/0005-MIPS-use-set_mode-to-enable-disable-the-cevt-r4k-irq.patch
new file mode 100644 (file)
index 0000000..248357a
--- /dev/null
@@ -0,0 +1,82 @@
+From ce3d4a4111a5f7e6b4e74bceae5faa6ce388e8ec Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 14 Jul 2013 23:08:11 +0200
+Subject: [PATCH 05/53] MIPS: use set_mode() to enable/disable the cevt-r4k
+ irq
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/Kconfig |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -1,11 +1,16 @@
+ if RALINK
++config CEVT_SYSTICK_QUIRK
++      bool
++      default n
++
+ config CLKEVT_RT3352
+       bool
+       depends on SOC_RT305X || SOC_MT7620
+       default y
+       select CLKSRC_OF
+       select CLKSRC_MMIO
++      select CEVT_SYSTICK_QUIRK
+ config RALINK_ILL_ACC
+       bool
+--- a/arch/mips/kernel/cevt-r4k.c
++++ b/arch/mips/kernel/cevt-r4k.c
+@@ -15,6 +15,26 @@
+ #include <asm/time.h>
+ #include <asm/cevt-r4k.h>
++static int mips_state_oneshot(struct clock_event_device *evt)
++{
++      if (!cp0_timer_irq_installed) {
++              cp0_timer_irq_installed = 1;
++              setup_irq(evt->irq, &c0_compare_irqaction);
++      }
++
++      return 0;
++}
++
++static int mips_state_shutdown(struct clock_event_device *evt)
++{
++      if (cp0_timer_irq_installed) {
++              cp0_timer_irq_installed = 0;
++              remove_irq(evt->irq, &c0_compare_irqaction);
++      }
++
++      return 0;
++}
++
+ static int mips_next_event(unsigned long delta,
+                          struct clock_event_device *evt)
+ {
+@@ -208,18 +228,21 @@ int r4k_clockevent_init(void)
+       cd->rating              = 300;
+       cd->irq                 = irq;
+       cd->cpumask             = cpumask_of(cpu);
++      cd->set_state_shutdown  = mips_state_shutdown;
++      cd->set_state_oneshot   = mips_state_oneshot;
+       cd->set_next_event      = mips_next_event;
+       cd->event_handler       = mips_event_handler;
+       clockevents_register_device(cd);
++#ifndef CONFIG_CEVT_SYSTICK_QUIRK
+       if (cp0_timer_irq_installed)
+               return 0;
+       cp0_timer_irq_installed = 1;
+       setup_irq(irq, &c0_compare_irqaction);
+-
++#endif
+       return 0;
+ }
diff --git a/target/linux/ramips/patches-4.4/0006-MIPS-ralink-add-cpu-frequency-scaling.patch b/target/linux/ramips/patches-4.4/0006-MIPS-ralink-add-cpu-frequency-scaling.patch
new file mode 100644 (file)
index 0000000..f953aee
--- /dev/null
@@ -0,0 +1,93 @@
+From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 28 Jul 2013 16:26:41 +0200
+Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling
+
+This feature will break udelay() and cause the delay loop to have longer delays
+when the frequency is scaled causing a performance hit.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/cevt-rt3352.c |   38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+--- a/arch/mips/ralink/cevt-rt3352.c
++++ b/arch/mips/ralink/cevt-rt3352.c
+@@ -29,6 +29,10 @@
+ /* enable the counter */
+ #define CFG_CNT_EN            0x1
++/* mt7620 frequency scaling defines */
++#define CLK_LUT_CFG   0x40
++#define SLEEP_EN      BIT(31)
++
+ struct systick_device {
+       void __iomem *membase;
+       struct clock_event_device dev;
+@@ -36,9 +40,26 @@ struct systick_device {
+       int freq_scale;
+ };
++static void (*systick_freq_scaling)(struct systick_device *sdev, int status);
++
+ static int systick_set_oneshot(struct clock_event_device *evt);
+ static int systick_shutdown(struct clock_event_device *evt);
++static inline void mt7620_freq_scaling(struct systick_device *sdev, int status)
++{
++      if (sdev->freq_scale == status)
++              return;
++
++      sdev->freq_scale = status;
++
++      pr_info("%s: %s autosleep mode\n", systick.dev.name,
++                      (status) ? ("enable") : ("disable"));
++      if (status)
++              rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
++      else
++              rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
++}
++
+ static int systick_next_event(unsigned long delta,
+                               struct clock_event_device *evt)
+ {
+@@ -99,6 +120,9 @@ static int systick_shutdown(struct clock
+       sdev->irq_requested = 0;
+       iowrite32(0, systick.membase + SYSTICK_CONFIG);
++      if (systick_freq_scaling)
++              systick_freq_scaling(sdev, 0);
++
+       return 0;
+ }
+@@ -114,15 +138,29 @@ static int systick_set_oneshot(struct cl
+       iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN,
+                 systick.membase + SYSTICK_CONFIG);
++      if (systick_freq_scaling)
++              systick_freq_scaling(sdev, 1);
++
+       return 0;
+ }
++static const struct of_device_id systick_match[] = {
++      { .compatible = "ralink,mt7620-systick", .data = mt7620_freq_scaling},
++      {},
++};
++
+ static void __init ralink_systick_init(struct device_node *np)
+ {
++      const struct of_device_id *match;
++
+       systick.membase = of_iomap(np, 0);
+       if (!systick.membase)
+               return;
++      match = of_match_node(systick_match, np);
++      if (match)
++              systick_freq_scaling = match->data;
++
+       systick_irqaction.name = np->name;
+       systick.dev.name = np->name;
+       clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
diff --git a/target/linux/ramips/patches-4.4/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch b/target/linux/ramips/patches-4.4/0007-MIPS-ralink-copy-the-commandline-from-the-devicetree.patch
new file mode 100644 (file)
index 0000000..4035a14
--- /dev/null
@@ -0,0 +1,21 @@
+From 67b7bff0fd364c194e653f69baa623ba2141bd4c Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 4 Aug 2014 18:46:02 +0200
+Subject: [PATCH 07/53] MIPS: ralink: copy the commandline from the devicetree
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/of.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/mips/ralink/of.c
++++ b/arch/mips/ralink/of.c
+@@ -74,6 +74,8 @@ void __init plat_mem_setup(void)
+        */
+       __dt_setup_arch(__dtb_start);
++      strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
++
+       of_scan_flat_dt(early_init_dt_find_memory, NULL);
+       if (memory_dtb)
+               of_scan_flat_dt(early_init_dt_scan_memory, NULL);
diff --git a/target/linux/ramips/patches-4.4/0009-PCI-MIPS-adds-mt7620a-pcie-driver.patch b/target/linux/ramips/patches-4.4/0009-PCI-MIPS-adds-mt7620a-pcie-driver.patch
new file mode 100644 (file)
index 0000000..96bf9d0
--- /dev/null
@@ -0,0 +1,433 @@
+From 41aa7fc236fdb1f4c9b8b10df9b71f0d248cb36b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:11:12 +0100
+Subject: [PATCH 09/53] PCI: MIPS: adds mt7620a pcie driver
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/include/asm/mach-ralink/mt7620.h |    1 +
+ arch/mips/pci/Makefile                     |    1 +
+ arch/mips/pci/pci-mt7620.c                 |  396 ++++++++++++++++++++++++++++
+ arch/mips/ralink/Kconfig                   |    1 +
+ 4 files changed, 399 insertions(+)
+ create mode 100644 arch/mips/pci/pci-mt7620.c
+
+--- a/arch/mips/pci/Makefile
++++ b/arch/mips/pci/Makefile
+@@ -43,6 +43,7 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1
+ obj-$(CONFIG_SNI_RM)          += fixup-sni.o ops-sni.o
+ obj-$(CONFIG_LANTIQ)          += fixup-lantiq.o
+ obj-$(CONFIG_PCI_LANTIQ)      += pci-lantiq.o ops-lantiq.o
++obj-$(CONFIG_SOC_MT7620)      += pci-mt7620.o
+ obj-$(CONFIG_SOC_MT7621)      += pci-mt7621.o
+ obj-$(CONFIG_SOC_RT288X)      += pci-rt2880.o
+ obj-$(CONFIG_SOC_RT3883)      += pci-rt3883.o
+--- /dev/null
++++ b/arch/mips/pci/pci-mt7620.c
+@@ -0,0 +1,396 @@
++/*
++ *  Ralink MT7620A SoC PCI support
++ *
++ *  Copyright (C) 2007-2013 Bruce Chang
++ *  Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_pci.h>
++#include <linux/reset.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-ralink/ralink_regs.h>
++#include <asm/mach-ralink/mt7620.h>
++
++#define RALINK_PCI_MM_MAP_BASE                0x20000000
++#define RALINK_PCI_IO_MAP_BASE                0x10160000
++
++#define RALINK_INT_PCIE0              4
++#define RALINK_SYSCFG1                        0x14
++#define RALINK_CLKCFG1                        0x30
++#define RALINK_GPIOMODE                       0x60
++#define RALINK_PCIE_CLK_GEN           0x7c
++#define RALINK_PCIE_CLK_GEN1          0x80
++#define PCIEPHY0_CFG                  0x90
++#define PPLL_CFG1                     0x9c
++#define PPLL_DRV                      0xa0
++#define PDRV_SW_SET                   (1<<31)
++#define LC_CKDRVPD_                   (1<<19)
++
++#define RALINK_PCI_CONFIG_ADDR                0x20
++#define RALINK_PCI_CONFIG_DATA_VIRT_REG       0x24
++#define MEMORY_BASE                   0x0
++#define RALINK_PCIE0_RST              (1<<26)
++#define RALINK_PCI_BASE                       0xB0140000
++#define RALINK_PCI_MEMBASE            0x28
++#define RALINK_PCI_IOBASE             0x2C
++
++#define RT6855_PCIE0_OFFSET           0x2000
++
++#define RALINK_PCI_PCICFG_ADDR                0x00
++#define RALINK_PCI0_BAR0SETUP_ADDR    0x10
++#define RALINK_PCI0_IMBASEBAR0_ADDR   0x18
++#define RALINK_PCI0_ID                        0x30
++#define RALINK_PCI0_CLASS             0x34
++#define RALINK_PCI0_SUBID             0x38
++#define RALINK_PCI0_STATUS            0x50
++#define RALINK_PCI_PCIMSK_ADDR                0x0C
++
++#define RALINK_PCIEPHY_P0_CTL_OFFSET  0x7498
++#define RALINK_PCIE0_CLK_EN           (1 << 26)
++
++#define BUSY                          0x80000000
++#define WAITRETRY_MAX                 10
++#define WRITE_MODE                    (1UL << 23)
++#define DATA_SHIFT                    0
++#define ADDR_SHIFT                    8
++
++static void __iomem *bridge_base;
++static void __iomem *pcie_base;
++
++static struct reset_control *rstpcie0;
++
++static inline void bridge_w32(u32 val, unsigned reg)
++{
++      iowrite32(val, bridge_base + reg);
++}
++
++static inline u32 bridge_r32(unsigned reg)
++{
++      return ioread32(bridge_base + reg);
++}
++
++static inline void pcie_w32(u32 val, unsigned reg)
++{
++      iowrite32(val, pcie_base + reg);
++}
++
++static inline u32 pcie_r32(unsigned reg)
++{
++      return ioread32(pcie_base + reg);
++}
++
++static inline void pcie_m32(u32 clr, u32 set, unsigned reg)
++{
++      u32 val = pcie_r32(reg);
++
++      val &= ~clr;
++      val |= set;
++      pcie_w32(val, reg);
++}
++
++static int wait_pciephy_busy(void)
++{
++      unsigned long reg_value = 0x0, retry = 0;
++
++      while (1) {
++              reg_value = pcie_r32(PCIEPHY0_CFG);
++
++              if (reg_value & BUSY)
++                      mdelay(100);
++              else
++                      break;
++              if (retry++ > WAITRETRY_MAX){
++                      printk("PCIE-PHY retry failed.\n");
++                      return -1;
++              }
++      }
++      return 0;
++}
++
++static void pcie_phy(unsigned long addr, unsigned long val)
++{
++      wait_pciephy_busy();
++      pcie_w32(WRITE_MODE | (val << DATA_SHIFT) | (addr << ADDR_SHIFT), PCIEPHY0_CFG);
++      mdelay(1);
++      wait_pciephy_busy();
++}
++
++static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val)
++{
++      unsigned int slot = PCI_SLOT(devfn);
++      u8 func = PCI_FUNC(devfn);
++      u32 address;
++      u32 data;
++      u32 num = 0;
++
++      if (bus)
++              num = bus->number;
++
++      address = (((where & 0xF00) >> 8) << 24) | (num << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000;
++      bridge_w32(address, RALINK_PCI_CONFIG_ADDR);
++      data = bridge_r32(RALINK_PCI_CONFIG_DATA_VIRT_REG);
++
++      switch (size) {
++      case 1:
++              *val = (data >> ((where & 3) << 3)) & 0xff;
++              break;
++      case 2:
++              *val = (data >> ((where & 3) << 3)) & 0xffff;
++              break;
++      case 4:
++              *val = data;
++              break;
++      }
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
++{
++      unsigned int slot = PCI_SLOT(devfn);
++      u8 func = PCI_FUNC(devfn);
++      u32 address;
++      u32 data;
++      u32 num = 0;
++
++      if (bus)
++              num = bus->number;
++
++      address = (((where & 0xF00) >> 8) << 24) | (num << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000;
++      bridge_w32(address, RALINK_PCI_CONFIG_ADDR);
++      data = bridge_r32(RALINK_PCI_CONFIG_DATA_VIRT_REG);
++
++      switch (size) {
++      case 1:
++              data = (data & ~(0xff << ((where & 3) << 3))) |
++                      (val << ((where & 3) << 3));
++              break;
++      case 2:
++              data = (data & ~(0xffff << ((where & 3) << 3))) |
++                      (val << ((where & 3) << 3));
++              break;
++      case 4:
++              data = val;
++              break;
++      }
++
++      bridge_w32(data, RALINK_PCI_CONFIG_DATA_VIRT_REG);
++
++      return PCIBIOS_SUCCESSFUL;
++}
++
++struct pci_ops mt7620_pci_ops= {
++      .read   = pci_config_read,
++      .write  = pci_config_write,
++};
++
++static struct resource mt7620_res_pci_mem1;
++static struct resource mt7620_res_pci_io1;
++struct pci_controller mt7620_controller = {
++      .pci_ops        = &mt7620_pci_ops,
++      .mem_resource   = &mt7620_res_pci_mem1,
++      .mem_offset     = 0x00000000UL,
++      .io_resource    = &mt7620_res_pci_io1,
++      .io_offset      = 0x00000000UL,
++      .io_map_base    = 0xa0000000,
++};
++
++static int mt7620_pci_hw_init(struct platform_device *pdev) {
++      /* PCIE: bypass PCIe DLL */
++      pcie_phy(0x0, 0x80);
++      pcie_phy(0x1, 0x04);
++
++      /* PCIE: Elastic buffer control */
++      pcie_phy(0x68, 0xB4);
++
++      pcie_m32(0, BIT(1), RALINK_PCI_PCICFG_ADDR);
++
++      reset_control_assert(rstpcie0);
++
++      rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
++      rt_sysc_m32(BIT(19), BIT(31), PPLL_DRV);
++
++      reset_control_deassert(rstpcie0);
++      rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
++
++      mdelay(100);
++
++      if (!(rt_sysc_r32(PPLL_CFG1) & BIT(23))) {
++              dev_err(&pdev->dev, "MT7620 PPLL unlock\n");
++              reset_control_assert(rstpcie0);
++              rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
++              return -1;
++      }
++      rt_sysc_m32(BIT(18) | BIT(17), BIT(19) | BIT(31), PPLL_DRV);
++
++      return 0;
++}
++
++static int mt7628_pci_hw_init(struct platform_device *pdev) {
++      u32 val = 0;
++
++      rt_sysc_m32(BIT(16), 0, RALINK_GPIOMODE);
++      reset_control_deassert(rstpcie0);
++      rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
++      mdelay(100);
++
++      pcie_m32(~0xff, 0x5, RALINK_PCIEPHY_P0_CTL_OFFSET);
++
++      pci_config_read(NULL, 0, 0x70c, 4, &val);
++      val &= ~(0xff) << 8;
++      val |= 0x50 << 8;
++      pci_config_write(NULL, 0, 0x70c, 4, val);
++
++      pci_config_read(NULL, 0, 0x70c, 4, &val);
++      dev_err(&pdev->dev, "Port 0 N_FTS = %x\n", (unsigned int) val);
++
++      return 0;
++}
++
++static int mt7620_pci_probe(struct platform_device *pdev)
++{
++      struct resource *bridge_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      struct resource *pcie_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++      u32 val = 0;
++
++      rstpcie0 = devm_reset_control_get(&pdev->dev, "pcie0");
++      if (IS_ERR(rstpcie0))
++              return PTR_ERR(rstpcie0);
++
++      bridge_base = devm_ioremap_resource(&pdev->dev, bridge_res);
++        if (!bridge_base)
++              return -ENOMEM;
++
++      pcie_base = devm_ioremap_resource(&pdev->dev, pcie_res);
++        if (!pcie_base)
++              return -ENOMEM;
++
++      iomem_resource.start = 0;
++      iomem_resource.end = ~0;
++      ioport_resource.start = 0;
++      ioport_resource.end = ~0;
++
++      /* bring up the pci core */
++      switch (ralink_soc) {
++      case MT762X_SOC_MT7620A:
++              if (mt7620_pci_hw_init(pdev))
++                      return -1;
++              break;
++
++      case MT762X_SOC_MT7628AN:
++              if (mt7628_pci_hw_init(pdev))
++                      return -1;
++              break;
++
++      default:
++              dev_err(&pdev->dev, "pcie is not supported on this hardware\n");
++              return -1;
++      }
++      mdelay(50);
++
++      /* enable write access */
++      pcie_m32(BIT(1), 0, RALINK_PCI_PCICFG_ADDR);
++      mdelay(100);
++
++      /* check if there is a card present */
++      if ((pcie_r32(RALINK_PCI0_STATUS) & 0x1) == 0) {
++              reset_control_assert(rstpcie0);
++              rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
++              if (ralink_soc == MT762X_SOC_MT7620A)
++                      rt_sysc_m32(LC_CKDRVPD_, PDRV_SW_SET, PPLL_DRV);
++              dev_err(&pdev->dev, "PCIE0 no card, disable it(RST&CLK)\n");
++              return -1;
++      }
++
++      /* setup ranges */
++      bridge_w32(0xffffffff, RALINK_PCI_MEMBASE);
++      bridge_w32(RALINK_PCI_IO_MAP_BASE, RALINK_PCI_IOBASE);
++
++      pcie_w32(0x7FFF0001, RALINK_PCI0_BAR0SETUP_ADDR);
++      pcie_w32(MEMORY_BASE, RALINK_PCI0_IMBASEBAR0_ADDR);
++      pcie_w32(0x06040001, RALINK_PCI0_CLASS);
++
++      /* enable interrupts */
++      pcie_m32(0, BIT(20), RALINK_PCI_PCIMSK_ADDR);
++
++      /* voodoo from the SDK driver */
++      pci_config_read(NULL, 0, 4, 4, &val);
++      pci_config_write(NULL, 0, 4, 4, val | 0x7);
++
++      pci_load_of_ranges(&mt7620_controller, pdev->dev.of_node);
++      register_pci_controller(&mt7620_controller);
++
++      return 0;
++}
++
++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++      u16 cmd;
++      u32 val;
++      int irq = 0;
++
++      if ((dev->bus->number == 0) && (slot == 0)) {
++              pcie_w32(0x7FFF0001, RALINK_PCI0_BAR0SETUP_ADDR); //open 7FFF:2G; ENABLE
++              pci_config_write(dev->bus, 0, PCI_BASE_ADDRESS_0, 4, MEMORY_BASE);
++              pci_config_read(dev->bus, 0, PCI_BASE_ADDRESS_0, 4, &val);
++      } else if ((dev->bus->number == 1) && (slot == 0x0)) {
++              irq = RALINK_INT_PCIE0;
++      } else {
++              dev_err(&dev->dev, "no irq found - bus=0x%x, slot = 0x%x\n", dev->bus->number, slot);
++              return 0;
++      }
++      dev_err(&dev->dev, "card - bus=0x%x, slot = 0x%x irq=%d\n", dev->bus->number, slot, irq);
++
++      pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14);  //configure cache line size 0x14
++      pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF);  //configure latency timer 0x10
++      pci_read_config_word(dev, PCI_COMMAND, &cmd);
++
++      // FIXME
++      cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
++      pci_write_config_word(dev, PCI_COMMAND, cmd);
++      pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
++      //pci_write_config_byte(dev, PCI_INTERRUPT_PIN, dev->irq);
++
++      return irq;
++}
++
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++      return 0;
++}
++
++static const struct of_device_id mt7620_pci_ids[] = {
++      { .compatible = "mediatek,mt7620-pci" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, mt7620_pci_ids);
++
++static struct platform_driver mt7620_pci_driver = {
++      .probe = mt7620_pci_probe,
++      .driver = {
++              .name = "mt7620-pci",
++              .owner = THIS_MODULE,
++              .of_match_table = of_match_ptr(mt7620_pci_ids),
++      },
++};
++
++static int __init mt7620_pci_init(void)
++{
++      return platform_driver_register(&mt7620_pci_driver);
++}
++
++arch_initcall(mt7620_pci_init);
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -43,6 +43,7 @@ choice
+       config SOC_MT7620
+               bool "MT7620/8"
++              select HW_HAS_PCI
+       config SOC_MT7621
+               bool "MT7621"
diff --git a/target/linux/ramips/patches-4.4/0010-arch-mips-ralink-add-spi1-clocks.patch b/target/linux/ramips/patches-4.4/0010-arch-mips-ralink-add-spi1-clocks.patch
new file mode 100644 (file)
index 0000000..1c3db6b
--- /dev/null
@@ -0,0 +1,44 @@
+From 39ce22c870f4503bed5e451acfcab21eba3b6239 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:49:07 +0100
+Subject: [PATCH 10/53] arch: mips: ralink: add spi1 clocks
+
+based on f3bc64d6d1f21c1b92d75f233a37b75d77af6963
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/mt7620.c |    1 +
+ arch/mips/ralink/rt305x.c |    1 +
+ arch/mips/ralink/rt3883.c |    1 +
+ 3 files changed, 3 insertions(+)
+
+--- a/arch/mips/ralink/mt7620.c
++++ b/arch/mips/ralink/mt7620.c
+@@ -436,6 +436,7 @@ void __init ralink_clk_init(void)
+       ralink_clk_add("10000100.timer", periph_rate);
+       ralink_clk_add("10000120.watchdog", periph_rate);
+       ralink_clk_add("10000b00.spi", sys_rate);
++      ralink_clk_add("10000b40.spi", sys_rate);
+       ralink_clk_add("10000c00.uartlite", periph_rate);
+       ralink_clk_add("10180000.wmac", xtal_rate);
+--- a/arch/mips/ralink/rt305x.c
++++ b/arch/mips/ralink/rt305x.c
+@@ -201,6 +201,7 @@ void __init ralink_clk_init(void)
+       ralink_clk_add("cpu", cpu_rate);
+       ralink_clk_add("sys", sys_rate);
+       ralink_clk_add("10000b00.spi", sys_rate);
++      ralink_clk_add("10000b40.spi", sys_rate);
+       ralink_clk_add("10000100.timer", wdt_rate);
+       ralink_clk_add("10000120.watchdog", wdt_rate);
+       ralink_clk_add("10000500.uart", uart_rate);
+--- a/arch/mips/ralink/rt3883.c
++++ b/arch/mips/ralink/rt3883.c
+@@ -109,6 +109,7 @@ void __init ralink_clk_init(void)
+       ralink_clk_add("10000120.watchdog", sys_rate);
+       ralink_clk_add("10000500.uart", 40000000);
+       ralink_clk_add("10000b00.spi", sys_rate);
++      ralink_clk_add("10000b40.spi", sys_rate);
+       ralink_clk_add("10000c00.uartlite", 40000000);
+       ralink_clk_add("10100000.ethernet", sys_rate);
+       ralink_clk_add("10180000.wmac", 40000000);
diff --git a/target/linux/ramips/patches-4.4/0013-owrt-hack-fix-mt7688-cache-issue.patch b/target/linux/ramips/patches-4.4/0013-owrt-hack-fix-mt7688-cache-issue.patch
new file mode 100644 (file)
index 0000000..b094b88
--- /dev/null
@@ -0,0 +1,28 @@
+From 5ede027f6c4a57ed25da872420508b7f1168b36b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:15:32 +0100
+Subject: [PATCH 13/53] owrt: hack: fix mt7688 cache issue
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/kernel/setup.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/kernel/setup.c
++++ b/arch/mips/kernel/setup.c
+@@ -696,7 +696,6 @@ static void __init arch_mem_init(char **
+                               crashk_res.end - crashk_res.start + 1,
+                               BOOTMEM_DEFAULT);
+ #endif
+-      device_tree_init();
+       sparse_init();
+       plat_swiotlb_setup();
+       paging_init();
+@@ -806,6 +805,7 @@ void __init setup_arch(char **cmdline_p)
+       prefill_possible_map();
+       cpu_cache_init();
++      device_tree_init();
+ }
+ unsigned long kernelsp[NR_CPUS];
diff --git a/target/linux/ramips/patches-4.4/0014-arch-mips-cleanup-cevt-rt3352.patch b/target/linux/ramips/patches-4.4/0014-arch-mips-cleanup-cevt-rt3352.patch
new file mode 100644 (file)
index 0000000..50b3dc8
--- /dev/null
@@ -0,0 +1,165 @@
+From e6ed424c36458aff8738fb1fbb0141196678058a Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:17:23 +0100
+Subject: [PATCH 14/53] arch: mips: cleanup cevt-rt3352
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/cevt-rt3352.c |   85 ++++++++++++++++++++++++++--------------
+ 1 file changed, 56 insertions(+), 29 deletions(-)
+
+--- a/arch/mips/ralink/cevt-rt3352.c
++++ b/arch/mips/ralink/cevt-rt3352.c
+@@ -52,7 +52,7 @@ static inline void mt7620_freq_scaling(s
+       sdev->freq_scale = status;
+-      pr_info("%s: %s autosleep mode\n", systick.dev.name,
++      pr_info("%s: %s autosleep mode\n", sdev->dev.name,
+                       (status) ? ("enable") : ("disable"));
+       if (status)
+               rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
+@@ -60,18 +60,33 @@ static inline void mt7620_freq_scaling(s
+               rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
+ }
++static inline unsigned int read_count(struct systick_device *sdev)
++{
++      return ioread32(sdev->membase + SYSTICK_COUNT);
++}
++
++static inline unsigned int read_compare(struct systick_device *sdev)
++{
++      return ioread32(sdev->membase + SYSTICK_COMPARE);
++}
++
++static inline void write_compare(struct systick_device *sdev, unsigned int val)
++{
++      iowrite32(val, sdev->membase + SYSTICK_COMPARE);
++}
++
+ static int systick_next_event(unsigned long delta,
+                               struct clock_event_device *evt)
+ {
+       struct systick_device *sdev;
+-      u32 count;
++      int res;
+       sdev = container_of(evt, struct systick_device, dev);
+-      count = ioread32(sdev->membase + SYSTICK_COUNT);
+-      count = (count + delta) % SYSTICK_FREQ;
+-      iowrite32(count, sdev->membase + SYSTICK_COMPARE);
++      delta += read_count(sdev);
++      write_compare(sdev, delta);
++      res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0;
+-      return 0;
++      return res;
+ }
+ static void systick_event_handler(struct clock_event_device *dev)
+@@ -81,20 +96,25 @@ static void systick_event_handler(struct
+ static irqreturn_t systick_interrupt(int irq, void *dev_id)
+ {
+-      struct clock_event_device *dev = (struct clock_event_device *) dev_id;
++      int ret = 0;
++      struct clock_event_device *cdev;
++      struct systick_device *sdev;
+-      dev->event_handler(dev);
++      if (read_c0_cause() & STATUSF_IP7) {
++              cdev = (struct clock_event_device *) dev_id;
++              sdev = container_of(cdev, struct systick_device, dev);
++
++              /* Clear Count/Compare Interrupt */
++              write_compare(sdev, read_compare(sdev));
++              cdev->event_handler(cdev);
++              ret = 1;
++      }
+-      return IRQ_HANDLED;
++      return IRQ_RETVAL(ret);
+ }
+ static struct systick_device systick = {
+       .dev = {
+-              /*
+-               * cevt-r4k uses 300, make sure systick
+-               * gets used if available
+-               */
+-              .rating                 = 310,
+               .features               = CLOCK_EVT_FEAT_ONESHOT,
+               .set_next_event         = systick_next_event,
+               .set_state_shutdown     = systick_shutdown,
+@@ -116,9 +136,9 @@ static int systick_shutdown(struct clock
+       sdev = container_of(evt, struct systick_device, dev);
+       if (sdev->irq_requested)
+-              free_irq(systick.dev.irq, &systick_irqaction);
++              remove_irq(systick.dev.irq, &systick_irqaction);
+       sdev->irq_requested = 0;
+-      iowrite32(0, systick.membase + SYSTICK_CONFIG);
++      iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
+       if (systick_freq_scaling)
+               systick_freq_scaling(sdev, 0);
+@@ -145,38 +165,45 @@ static int systick_set_oneshot(struct cl
+ }
+ static const struct of_device_id systick_match[] = {
+-      { .compatible = "ralink,mt7620-systick", .data = mt7620_freq_scaling},
++      { .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling},
+       {},
+ };
+ static void __init ralink_systick_init(struct device_node *np)
+ {
+       const struct of_device_id *match;
++      int rating = 200;
+       systick.membase = of_iomap(np, 0);
+       if (!systick.membase)
+               return;
+       match = of_match_node(systick_match, np);
+-      if (match)
++      if (match) {
+               systick_freq_scaling = match->data;
++              /*
++               * cevt-r4k uses 300, make sure systick
++               * gets used if available
++               */
++              rating = 310;
++      }
+-      systick_irqaction.name = np->name;
+-      systick.dev.name = np->name;
+-      clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
+-      systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
+-      systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
++      /* enable counter than register clock source */
++      iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
++      clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
++                      SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up);
++
++      /* register clock event */
+       systick.dev.irq = irq_of_parse_and_map(np, 0);
+       if (!systick.dev.irq) {
+               pr_err("%s: request_irq failed", np->name);
+               return;
+       }
+-
+-      clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
+-                      SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up);
+-
+-      clockevents_register_device(&systick.dev);
+-
++      systick_irqaction.name = np->name;
++      systick.dev.name = np->name;
++      systick.dev.rating = rating;
++      systick.dev.cpumask = cpumask_of(0);
++      clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff);
+       pr_info("%s: running - mult: %d, shift: %d\n",
+                       np->name, systick.dev.mult, systick.dev.shift);
+ }
diff --git a/target/linux/ramips/patches-4.4/0015-arch-mips-do-not-select-illegal-access-driver-by-def.patch b/target/linux/ramips/patches-4.4/0015-arch-mips-do-not-select-illegal-access-driver-by-def.patch
new file mode 100644 (file)
index 0000000..6f5a6f4
--- /dev/null
@@ -0,0 +1,25 @@
+From 9e6ce539092a1dd605a20bf73c655a9de58d8641 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:18:05 +0100
+Subject: [PATCH 15/53] arch: mips: do not select illegal access driver by
+ default
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/Kconfig |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -13,9 +13,9 @@ config CLKEVT_RT3352
+       select CEVT_SYSTICK_QUIRK
+ config RALINK_ILL_ACC
+-      bool
++      bool "illegal access irq"
+       depends on SOC_RT305X
+-      default y
++      default n
+ config IRQ_INTC
+       bool
diff --git a/target/linux/ramips/patches-4.4/0019-arch-mips-ralink-add-mt7621-cpu-feature-overrides.patch b/target/linux/ramips/patches-4.4/0019-arch-mips-ralink-add-mt7621-cpu-feature-overrides.patch
new file mode 100644 (file)
index 0000000..d2da23a
--- /dev/null
@@ -0,0 +1,79 @@
+From 43372c2be9fcf68bc40c322039c75893ce4e982c Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:20:47 +0100
+Subject: [PATCH 19/53] arch: mips: ralink: add mt7621 cpu-feature-overrides
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ .../asm/mach-ralink/mt7621/cpu-feature-overrides.h |   65 ++++++++++++++++++++
+ 1 file changed, 65 insertions(+)
+ create mode 100644 arch/mips/include/asm/mach-ralink/mt7621/cpu-feature-overrides.h
+
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ralink/mt7621/cpu-feature-overrides.h
+@@ -0,0 +1,65 @@
++/*
++ * Ralink MT7621 specific CPU feature overrides
++ *
++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This file was derived from: include/asm-mips/cpu-features.h
++ *    Copyright (C) 2003, 2004 Ralf Baechle
++ *    Copyright (C) 2004 Maciej W. Rozycki
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++#ifndef _MT7621_CPU_FEATURE_OVERRIDES_H
++#define _MT7621_CPU_FEATURE_OVERRIDES_H
++
++#define cpu_has_tlb           1
++#define cpu_has_4kex          1
++#define cpu_has_3k_cache      0
++#define cpu_has_4k_cache      1
++#define cpu_has_tx39_cache    0
++#define cpu_has_sb1_cache     0
++#define cpu_has_fpu           0
++#define cpu_has_32fpr         0
++#define cpu_has_counter               1
++#define cpu_has_watch         1
++#define cpu_has_divec         1
++
++#define cpu_has_prefetch      1
++#define cpu_has_ejtag         1
++#define cpu_has_llsc          1
++
++#define cpu_has_mips16                1
++#define cpu_has_mdmx          0
++#define cpu_has_mips3d                0
++#define cpu_has_smartmips     0
++
++#define cpu_has_mips32r1      1
++#define cpu_has_mips32r2      1
++#define cpu_has_mips64r1      0
++#define cpu_has_mips64r2      0
++
++#define cpu_has_dsp           1
++#define cpu_has_dsp2          0
++#define cpu_has_mipsmt                1
++
++#define cpu_has_64bits                0
++#define cpu_has_64bit_zero_reg        0
++#define cpu_has_64bit_gp_regs 0
++#define cpu_has_64bit_addresses       0
++
++#define cpu_dcache_line_size()        32
++#define cpu_icache_line_size()        32
++
++#define cpu_has_dc_aliases    0
++#define cpu_has_vtag_icache   0
++
++#define cpu_has_rixi          0
++#define cpu_has_tlbinv                0
++#define cpu_has_userlocal     1
++
++#endif /* _MT7621_CPU_FEATURE_OVERRIDES_H */
diff --git a/target/linux/ramips/patches-4.4/0022-arch-mips-ralink-proper-vendor-id-srtring.patch b/target/linux/ramips/patches-4.4/0022-arch-mips-ralink-proper-vendor-id-srtring.patch
new file mode 100644 (file)
index 0000000..adadf2a
--- /dev/null
@@ -0,0 +1,21 @@
+From 2e5d90398aacde3e46dfd87e6f716b00a0ffcd83 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:30:11 +0100
+Subject: [PATCH 22/53] arch: mips: ralink: proper vendor id srtring
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/ralink/mt7620.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/mips/ralink/mt7620.c
++++ b/arch/mips/ralink/mt7620.c
+@@ -553,7 +553,7 @@ void prom_soc_init(struct ralink_soc_inf
+       }
+       snprintf(soc_info->sys_type, RAMIPS_SYS_TYPE_LEN,
+-              "Ralink %s ver:%u eco:%u",
++              "MediaTek %s ver:%u eco:%u",
+               name,
+               (rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK,
+               (rev & CHIP_REV_ECO_MASK));
diff --git a/target/linux/ramips/patches-4.4/0024-GPIO-add-named-gpio-exports.patch b/target/linux/ramips/patches-4.4/0024-GPIO-add-named-gpio-exports.patch
new file mode 100644 (file)
index 0000000..cfdab76
--- /dev/null
@@ -0,0 +1,166 @@
+From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 12 Aug 2014 20:49:27 +0200
+Subject: [PATCH 24/53] GPIO: add named gpio exports
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/gpio/gpiolib-of.c     |   68 +++++++++++++++++++++++++++++++++++++++++
+ drivers/gpio/gpiolib-sysfs.c  |   10 +++++-
+ include/asm-generic/gpio.h    |    6 ++++
+ include/linux/gpio/consumer.h |    8 +++++
+ 4 files changed, 91 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpiolib-of.c
++++ b/drivers/gpio/gpiolib-of.c
+@@ -23,6 +23,8 @@
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/slab.h>
+ #include <linux/gpio/machine.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
+ #include "gpiolib.h"
+@@ -450,3 +452,69 @@ void of_gpiochip_remove(struct gpio_chip
+       gpiochip_remove_pin_ranges(chip);
+       of_node_put(chip->of_node);
+ }
++
++static struct of_device_id gpio_export_ids[] = {
++      { .compatible = "gpio-export" },
++      { /* sentinel */ }
++};
++
++static int __init of_gpio_export_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct device_node *cnp;
++      u32 val;
++      int nb = 0;
++
++      for_each_child_of_node(np, cnp) {
++              const char *name = NULL;
++              int gpio;
++              bool dmc;
++              int max_gpio = 1;
++              int i;
++
++              of_property_read_string(cnp, "gpio-export,name", &name);
++
++              if (!name)
++                      max_gpio = of_gpio_count(cnp);
++
++              for (i = 0; i < max_gpio; i++) {
++                      unsigned flags = 0;
++                      enum of_gpio_flags of_flags;
++
++                      gpio = of_get_gpio_flags(cnp, i, &of_flags);
++
++                      if (of_flags == OF_GPIO_ACTIVE_LOW)
++                              flags |= GPIOF_ACTIVE_LOW;
++
++                      if (!of_property_read_u32(cnp, "gpio-export,output", &val))
++                              flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
++                      else
++                              flags |= GPIOF_IN;
++
++                      if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
++                              continue;
++
++                      dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
++                      gpio_export_with_name(gpio, dmc, name);
++                      nb++;
++              }
++      }
++
++      dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
++
++      return 0;
++}
++
++static struct platform_driver gpio_export_driver = {
++      .driver         = {
++              .name           = "gpio-export",
++              .owner  = THIS_MODULE,
++              .of_match_table = of_match_ptr(gpio_export_ids),
++      },
++};
++
++static int __init of_gpio_export_init(void)
++{
++      return platform_driver_probe(&gpio_export_driver, of_gpio_export_probe);
++}
++device_initcall(of_gpio_export_init);
+--- a/drivers/gpio/gpiolib-sysfs.c
++++ b/drivers/gpio/gpiolib-sysfs.c
+@@ -544,7 +544,7 @@ static struct class gpio_class = {
+  *
+  * Returns zero on success, else an error.
+  */
+-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
+ {
+       struct gpio_chip        *chip;
+       struct gpiod_data       *data;
+@@ -604,6 +604,8 @@ int gpiod_export(struct gpio_desc *desc,
+       offset = gpio_chip_hwgpio(desc);
+       if (chip->names && chip->names[offset])
+               ioname = chip->names[offset];
++      if (name)
++              ioname = name;
+       dev = device_create_with_groups(&gpio_class, chip->dev,
+                                       MKDEV(0, 0), data, gpio_groups,
+@@ -625,6 +627,12 @@ err_unlock:
+       gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+       return status;
+ }
++EXPORT_SYMBOL_GPL(__gpiod_export);
++
++int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++{
++      return __gpiod_export(desc, direction_may_change, NULL);
++}
+ EXPORT_SYMBOL_GPL(gpiod_export);
+ static int match_export(struct device *dev, const void *desc)
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -122,6 +122,12 @@ static inline int gpio_export(unsigned g
+       return gpiod_export(gpio_to_desc(gpio), direction_may_change);
+ }
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
++static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
++{
++      return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
++}
++
+ static inline int gpio_export_link(struct device *dev, const char *name,
+                                  unsigned gpio)
+ {
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -427,6 +427,7 @@ static inline struct gpio_desc *devm_get
+ #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
++int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+ int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
+ int gpiod_export_link(struct device *dev, const char *name,
+                     struct gpio_desc *desc);
+@@ -434,6 +435,13 @@ void gpiod_unexport(struct gpio_desc *de
+ #else  /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
++static inline int _gpiod_export(struct gpio_desc *desc,
++                             bool direction_may_change,
++                             const char *name)
++{
++      return -ENOSYS;
++}
++
+ static inline int gpiod_export(struct gpio_desc *desc,
+                              bool direction_may_change)
+ {
diff --git a/target/linux/ramips/patches-4.4/0025-pinctrl-ralink-add-pinctrl-driver.patch b/target/linux/ramips/patches-4.4/0025-pinctrl-ralink-add-pinctrl-driver.patch
new file mode 100644 (file)
index 0000000..315d956
--- /dev/null
@@ -0,0 +1,524 @@
+From 7adbe9a88c33c6e362a10b109d963b5500a21f00 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:34:05 +0100
+Subject: [PATCH 25/53] pinctrl: ralink: add pinctrl driver
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/Kconfig                |    2 +
+ drivers/pinctrl/Kconfig          |    5 +
+ drivers/pinctrl/Makefile         |    1 +
+ drivers/pinctrl/pinctrl-rt2880.c |  474 ++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 482 insertions(+)
+ create mode 100644 drivers/pinctrl/pinctrl-rt2880.c
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -585,6 +585,8 @@ config RALINK
+       select CLKDEV_LOOKUP
+       select ARCH_HAS_RESET_CONTROLLER
+       select RESET_CONTROLLER
++      select PINCTRL
++      select PINCTRL_RT2880
+ config SGI_IP22
+       bool "SGI IP22 (Indy/Indigo2)"
+--- a/drivers/pinctrl/Kconfig
++++ b/drivers/pinctrl/Kconfig
+@@ -114,6 +114,11 @@ config PINCTRL_LPC18XX
+       help
+         Pinctrl driver for NXP LPC18xx/43xx System Control Unit (SCU).
++config PINCTRL_RT2880
++      bool
++      depends on RALINK
++      select PINMUX
++
+ config PINCTRL_FALCON
+       bool
+       depends on SOC_FALCON
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_PINCTRL_MESON)  += meson/
+ obj-$(CONFIG_PINCTRL_PALMAS)  += pinctrl-palmas.o
+ obj-$(CONFIG_PINCTRL_PISTACHIO)       += pinctrl-pistachio.o
+ obj-$(CONFIG_PINCTRL_ROCKCHIP)        += pinctrl-rockchip.o
++obj-$(CONFIG_PINCTRL_RT2880)  += pinctrl-rt2880.o
+ obj-$(CONFIG_PINCTRL_SINGLE)  += pinctrl-single.o
+ obj-$(CONFIG_PINCTRL_SIRF)    += sirf/
+ obj-$(CONFIG_PINCTRL_TEGRA)   += pinctrl-tegra.o
+--- /dev/null
++++ b/drivers/pinctrl/pinctrl-rt2880.c
+@@ -0,0 +1,472 @@
++/*
++ *  linux/drivers/pinctrl/pinctrl-rt2880.c
++ *
++ *  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
++ *  publishhed by the Free Software Foundation.
++ *
++ *  Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/pinctrl/pinconf.h>
++#include <linux/pinctrl/pinmux.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/pinctrl/machine.h>
++
++#include <asm/mach-ralink/ralink_regs.h>
++#include <asm/mach-ralink/pinmux.h>
++#include <asm/mach-ralink/mt7620.h>
++
++#include "core.h"
++
++#define SYSC_REG_GPIO_MODE    0x60
++#define SYSC_REG_GPIO_MODE2   0x64
++
++struct rt2880_priv {
++      struct device *dev;
++
++      struct pinctrl_pin_desc *pads;
++      struct pinctrl_desc *desc;
++
++      struct rt2880_pmx_func **func;
++      int func_count;
++
++      struct rt2880_pmx_group *groups;
++      const char **group_names;
++      int group_count;
++
++      uint8_t *gpio;
++      int max_pins;
++};
++
++static int rt2880_get_group_count(struct pinctrl_dev *pctrldev)
++{
++      struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
++
++      return p->group_count;
++}
++
++static const char *rt2880_get_group_name(struct pinctrl_dev *pctrldev,
++                                       unsigned group)
++{
++      struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
++
++      if (group >= p->group_count)
++              return NULL;
++
++      return p->group_names[group];
++}
++
++static int rt2880_get_group_pins(struct pinctrl_dev *pctrldev,
++                               unsigned group,
++                               const unsigned **pins,
++                               unsigned *num_pins)
++{
++      struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
++
++      if (group >= p->group_count)
++              return -EINVAL;
++
++      *pins = p->groups[group].func[0].pins;
++      *num_pins = p->groups[group].func[0].pin_count;
++
++      return 0;
++}
++
++static void rt2880_pinctrl_dt_free_map(struct pinctrl_dev *pctrldev,
++                                  struct pinctrl_map *map, unsigned num_maps)
++{
++      int i;
++
++      for (i = 0; i < num_maps; i++)
++              if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN ||
++                  map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
++                      kfree(map[i].data.configs.configs);
++      kfree(map);
++}
++
++static void rt2880_pinctrl_pin_dbg_show(struct pinctrl_dev *pctrldev,
++                                      struct seq_file *s,
++                                      unsigned offset)
++{
++      seq_printf(s, "ralink pio");
++}
++
++static void rt2880_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctrldev,
++                              struct device_node *np,
++                              struct pinctrl_map **map)
++{
++        const char *function;
++      int func = of_property_read_string(np, "ralink,function", &function);
++      int grps = of_property_count_strings(np, "ralink,group");
++      int i;
++
++      if (func || !grps)
++              return;
++
++      for (i = 0; i < grps; i++) {
++              const char *group;
++
++              of_property_read_string_index(np, "ralink,group", i, &group);
++
++              (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
++              (*map)->name = function;
++              (*map)->data.mux.group = group;
++              (*map)->data.mux.function = function;
++              (*map)++;
++      }
++}
++
++static int rt2880_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrldev,
++                              struct device_node *np_config,
++                              struct pinctrl_map **map,
++                              unsigned *num_maps)
++{
++      int max_maps = 0;
++      struct pinctrl_map *tmp;
++      struct device_node *np;
++
++      for_each_child_of_node(np_config, np) {
++              int ret = of_property_count_strings(np, "ralink,group");
++
++              if (ret >= 0)
++                      max_maps += ret;
++      }
++
++      if (!max_maps)
++              return max_maps;
++
++      *map = kzalloc(max_maps * sizeof(struct pinctrl_map), GFP_KERNEL);
++      if (!*map)
++              return -ENOMEM;
++
++      tmp = *map;
++
++      for_each_child_of_node(np_config, np)
++              rt2880_pinctrl_dt_subnode_to_map(pctrldev, np, &tmp);
++      *num_maps = max_maps;
++
++      return 0;
++}
++
++static const struct pinctrl_ops rt2880_pctrl_ops = {
++      .get_groups_count       = rt2880_get_group_count,
++      .get_group_name         = rt2880_get_group_name,
++      .get_group_pins         = rt2880_get_group_pins,
++      .pin_dbg_show           = rt2880_pinctrl_pin_dbg_show,
++      .dt_node_to_map         = rt2880_pinctrl_dt_node_to_map,
++      .dt_free_map            = rt2880_pinctrl_dt_free_map,
++};
++
++static int rt2880_pmx_func_count(struct pinctrl_dev *pctrldev)
++{
++      struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
++
++      return p->func_count;
++}
++
++static const char *rt2880_pmx_func_name(struct pinctrl_dev *pctrldev,
++                                       unsigned func)
++{
++      struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
++
++      return p->func[func]->name;
++}
++
++static int rt2880_pmx_group_get_groups(struct pinctrl_dev *pctrldev,
++                              unsigned func,
++                              const char * const **groups,
++                              unsigned * const num_groups)
++{
++      struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
++
++      if (p->func[func]->group_count == 1)
++              *groups = &p->group_names[p->func[func]->groups[0]];
++      else
++              *groups = p->group_names;
++
++      *num_groups = p->func[func]->group_count;
++
++      return 0;
++}
++
++static int rt2880_pmx_group_enable(struct pinctrl_dev *pctrldev,
++                              unsigned func,
++                              unsigned group)
++{
++      struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
++        u32 mode = 0;
++      u32 reg = SYSC_REG_GPIO_MODE;
++      int i;
++      int shift;
++
++      /* dont allow double use */
++      if (p->groups[group].enabled) {
++              dev_err(p->dev, "%s is already enabled\n", p->groups[group].name);
++              return -EBUSY;
++      }
++
++      p->groups[group].enabled = 1;
++      p->func[func]->enabled = 1;
++
++      shift = p->groups[group].shift;
++      if (shift >= 32) {
++              shift -= 32;
++              reg = SYSC_REG_GPIO_MODE2;
++      }
++      mode = rt_sysc_r32(reg);
++      mode &= ~(p->groups[group].mask << shift);
++
++      /* mark the pins as gpio */
++      for (i = 0; i < p->groups[group].func[0].pin_count; i++)
++              p->gpio[p->groups[group].func[0].pins[i]] = 1;
++
++      /* function 0 is gpio and needs special handling */
++      if (func == 0) {
++              mode |= p->groups[group].gpio << shift;
++      } else {
++              for (i = 0; i < p->func[func]->pin_count; i++)
++                      p->gpio[p->func[func]->pins[i]] = 0;
++              mode |= p->func[func]->value << shift;
++      }
++      rt_sysc_w32(mode, reg);
++
++      return 0;
++}
++
++static int rt2880_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev,
++                              struct pinctrl_gpio_range *range,
++                              unsigned pin)
++{
++      struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev);
++
++      if (!p->gpio[pin]) {
++              dev_err(p->dev, "pin %d is not set to gpio mux\n", pin);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++static const struct pinmux_ops rt2880_pmx_group_ops = {
++      .get_functions_count    = rt2880_pmx_func_count,
++      .get_function_name      = rt2880_pmx_func_name,
++      .get_function_groups    = rt2880_pmx_group_get_groups,
++      .set_mux                = rt2880_pmx_group_enable,
++      .gpio_request_enable    = rt2880_pmx_group_gpio_request_enable,
++};
++
++static struct pinctrl_desc rt2880_pctrl_desc = {
++      .owner          = THIS_MODULE,
++      .name           = "rt2880-pinmux",
++      .pctlops        = &rt2880_pctrl_ops,
++      .pmxops         = &rt2880_pmx_group_ops,
++};
++
++static struct rt2880_pmx_func gpio_func = {
++      .name = "gpio",
++};
++
++static int rt2880_pinmux_index(struct rt2880_priv *p)
++{
++      struct rt2880_pmx_func **f;
++      struct rt2880_pmx_group *mux = p->groups;
++      int i, j, c = 0;
++
++      /* count the mux functions */
++      while (mux->name) {
++              p->group_count++;
++              mux++;
++      }
++
++      /* allocate the group names array needed by the gpio function */
++      p->group_names = devm_kzalloc(p->dev, sizeof(char *) * p->group_count, GFP_KERNEL);
++      if (!p->group_names)
++              return -1;
++
++      for (i = 0; i < p->group_count; i++) {
++              p->group_names[i] = p->groups[i].name;
++              p->func_count += p->groups[i].func_count;
++      }
++
++      /* we have a dummy function[0] for gpio */
++      p->func_count++;
++
++      /* allocate our function and group mapping index buffers */
++      f = p->func = devm_kzalloc(p->dev, sizeof(struct rt2880_pmx_func) * p->func_count, GFP_KERNEL);
++      gpio_func.groups = devm_kzalloc(p->dev, sizeof(int) * p->group_count, GFP_KERNEL);
++      if (!f || !gpio_func.groups)
++              return -1;
++
++      /* add a backpointer to the function so it knows its group */
++      gpio_func.group_count = p->group_count;
++      for (i = 0; i < gpio_func.group_count; i++)
++              gpio_func.groups[i] = i;
++
++      f[c] = &gpio_func;
++      c++;
++
++      /* add remaining functions */
++      for (i = 0; i < p->group_count; i++) {
++              for (j = 0; j < p->groups[i].func_count; j++) {
++                      f[c] = &p->groups[i].func[j];
++                      f[c]->groups = devm_kzalloc(p->dev, sizeof(int), GFP_KERNEL);
++                      f[c]->groups[0] = i;
++                      f[c]->group_count = 1;
++                      c++;
++              }
++      }
++      return 0;
++}
++
++static int rt2880_pinmux_pins(struct rt2880_priv *p)
++{
++      int i, j;
++
++      /* loop over the functions and initialize the pins array. also work out the highest pin used */
++      for (i = 0; i < p->func_count; i++) {
++              int pin;
++
++              if (!p->func[i]->pin_count)
++                      continue;
++
++              p->func[i]->pins = devm_kzalloc(p->dev, sizeof(int) * p->func[i]->pin_count, GFP_KERNEL);
++              for (j = 0; j < p->func[i]->pin_count; j++)
++                      p->func[i]->pins[j] = p->func[i]->pin_first + j;
++
++              pin = p->func[i]->pin_first + p->func[i]->pin_count;
++              if (pin > p->max_pins)
++                      p->max_pins = pin;
++      }
++
++      /* the buffer that tells us which pins are gpio */
++      p->gpio = devm_kzalloc(p->dev,sizeof(uint8_t) * p->max_pins,
++              GFP_KERNEL);
++      /* the pads needed to tell pinctrl about our pins */
++      p->pads = devm_kzalloc(p->dev,
++              sizeof(struct pinctrl_pin_desc) * p->max_pins,
++              GFP_KERNEL);
++      if (!p->pads || !p->gpio ) {
++              dev_err(p->dev, "Failed to allocate gpio data\n");
++              return -ENOMEM;
++      }
++
++      memset(p->gpio, 1, sizeof(uint8_t) * p->max_pins);
++      for (i = 0; i < p->func_count; i++) {
++              if (!p->func[i]->pin_count)
++                      continue;
++
++              for (j = 0; j < p->func[i]->pin_count; j++)
++                      p->gpio[p->func[i]->pins[j]] = 0;
++      }
++
++      /* pin 0 is always a gpio */
++      p->gpio[0] = 1;
++
++      /* set the pads */
++      for (i = 0; i < p->max_pins; i++) {
++              /* strlen("ioXY") + 1 = 5 */
++              char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL);
++
++              if (!name) {
++                      dev_err(p->dev, "Failed to allocate pad name\n");
++                      return -ENOMEM;
++              }
++              snprintf(name, 5, "io%d", i);
++              p->pads[i].number = i;
++              p->pads[i].name = name;
++      }
++      p->desc->pins = p->pads;
++      p->desc->npins = p->max_pins;
++
++      return 0;
++}
++
++static int rt2880_pinmux_probe(struct platform_device *pdev)
++{
++      struct rt2880_priv *p;
++      struct pinctrl_dev *dev;
++      struct device_node *np;
++
++      if (!rt2880_pinmux_data)
++              return -ENOSYS;
++
++      /* setup the private data */
++      p = devm_kzalloc(&pdev->dev, sizeof(struct rt2880_priv), GFP_KERNEL);
++      if (!p)
++              return -ENOMEM;
++
++      p->dev = &pdev->dev;
++      p->desc = &rt2880_pctrl_desc;
++      p->groups = rt2880_pinmux_data;
++      platform_set_drvdata(pdev, p);
++
++      /* init the device */
++      if (rt2880_pinmux_index(p)) {
++              dev_err(&pdev->dev, "failed to load index\n");
++              return -EINVAL;
++      }
++      if (rt2880_pinmux_pins(p)) {
++              dev_err(&pdev->dev, "failed to load pins\n");
++              return -EINVAL;
++      }
++      dev = pinctrl_register(p->desc, &pdev->dev, p);
++      if (IS_ERR(dev))
++              return PTR_ERR(dev);
++
++      /* finalize by adding gpio ranges for enables gpio controllers */
++      for_each_compatible_node(np, NULL, "ralink,rt2880-gpio") {
++              const __be32 *ngpio, *gpiobase;
++              struct pinctrl_gpio_range *range;
++              char *name;
++
++              if (!of_device_is_available(np))
++                      continue;
++
++              ngpio = of_get_property(np, "ralink,num-gpios", NULL);
++              gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
++              if (!ngpio || !gpiobase) {
++                      dev_err(&pdev->dev, "failed to load chip info\n");
++                      return -EINVAL;
++              }
++
++              range = devm_kzalloc(p->dev, sizeof(struct pinctrl_gpio_range) + 4, GFP_KERNEL);
++              range->name = name = (char *) &range[1];
++              sprintf(name, "pio");
++              range->npins = __be32_to_cpu(*ngpio);
++              range->base = __be32_to_cpu(*gpiobase);
++              range->pin_base = range->base;
++              pinctrl_add_gpio_range(dev, range);
++      }
++
++      return 0;
++}
++
++static const struct of_device_id rt2880_pinmux_match[] = {
++      { .compatible = "ralink,rt2880-pinmux" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, rt2880_pinmux_match);
++
++static struct platform_driver rt2880_pinmux_driver = {
++      .probe = rt2880_pinmux_probe,
++      .driver = {
++              .name = "rt2880-pinmux",
++              .owner = THIS_MODULE,
++              .of_match_table = rt2880_pinmux_match,
++      },
++};
++
++int __init rt2880_pinmux_init(void)
++{
++      return platform_driver_register(&rt2880_pinmux_driver);
++}
++
++core_initcall_sync(rt2880_pinmux_init);
diff --git a/target/linux/ramips/patches-4.4/0026-DT-Add-documentation-for-gpio-ralink.patch b/target/linux/ramips/patches-4.4/0026-DT-Add-documentation-for-gpio-ralink.patch
new file mode 100644 (file)
index 0000000..7d5f98f
--- /dev/null
@@ -0,0 +1,59 @@
+From d410e5478c622c01fcf31427533df5f433df9146 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 28 Jul 2013 19:45:30 +0200
+Subject: [PATCH 26/53] DT: Add documentation for gpio-ralink
+
+Describe gpio-ralink binding.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+Cc: devicetree@vger.kernel.org
+Cc: linux-gpio@vger.kernel.org
+---
+ .../devicetree/bindings/gpio/gpio-ralink.txt       |   40 ++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/gpio/gpio-ralink.txt
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
+@@ -0,0 +1,40 @@
++Ralink SoC GPIO controller bindings
++
++Required properties:
++- compatible:
++  - "ralink,rt2880-gpio" for Ralink controllers
++- #gpio-cells : Should be two.
++  - first cell is the pin number
++  - second cell is used to specify optional parameters (unused)
++- gpio-controller : Marks the device node as a GPIO controller
++- reg : Physical base address and length of the controller's registers
++- interrupt-parent: phandle to the INTC device node
++- interrupts : Specify the INTC interrupt number
++- ralink,num-gpios : Specify the number of GPIOs
++- ralink,register-map : The register layout depends on the GPIO bank and actual
++              SoC type. Register offsets need to be in this order.
++              [ INT, EDGE, RENA, FENA, DATA, DIR, POL, SET, RESET, TOGGLE ]
++
++Optional properties:
++- ralink,gpio-base : Specify the GPIO chips base number
++
++Example:
++
++      gpio0: gpio@600 {
++              compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio";
++
++              #gpio-cells = <2>;
++              gpio-controller;
++
++              reg = <0x600 0x34>;
++
++              interrupt-parent = <&intc>;
++              interrupts = <6>;
++
++              ralink,gpio-base = <0>;
++              ralink,num-gpios = <24>;
++              ralink,register-map = [ 00 04 08 0c
++                              20 24 28 2c
++                              30 34 ];
++
++      };
diff --git a/target/linux/ramips/patches-4.4/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch b/target/linux/ramips/patches-4.4/0027-GPIO-MIPS-ralink-add-gpio-driver-for-ralink-SoC.patch
new file mode 100644 (file)
index 0000000..1a7ddec
--- /dev/null
@@ -0,0 +1,430 @@
+From 69fdd2c4f937796b934e89c33acde9d082e27bfd Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 4 Aug 2014 20:36:29 +0200
+Subject: [PATCH 27/53] GPIO: MIPS: ralink: add gpio driver for ralink SoC
+
+Add gpio driver for Ralink SoC. This driver makes the gpio core on
+RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: linux-mips@linux-mips.org
+Cc: linux-gpio@vger.kernel.org
+---
+ arch/mips/include/asm/mach-ralink/gpio.h |   24 ++
+ drivers/gpio/Kconfig                     |    6 +
+ drivers/gpio/Makefile                    |    1 +
+ drivers/gpio/gpio-ralink.c               |  355 ++++++++++++++++++++++++++++++
+ 4 files changed, 386 insertions(+)
+ create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h
+ create mode 100644 drivers/gpio/gpio-ralink.c
+
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ralink/gpio.h
+@@ -0,0 +1,24 @@
++/*
++ *  Ralink SoC GPIO API support
++ *
++ *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
++ *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ *
++ */
++
++#ifndef __ASM_MACH_RALINK_GPIO_H
++#define __ASM_MACH_RALINK_GPIO_H
++
++#define ARCH_NR_GPIOS 128
++#include <asm-generic/gpio.h>
++
++#define gpio_get_value        __gpio_get_value
++#define gpio_set_value        __gpio_set_value
++#define gpio_cansleep __gpio_cansleep
++#define gpio_to_irq   __gpio_to_irq
++
++#endif /* __ASM_MACH_RALINK_GPIO_H */
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -351,6 +351,12 @@ config GPIO_SAMSUNG
+         Legacy GPIO support. Use only for platforms without support for
+         pinctrl.
++config GPIO_RALINK
++      bool "Ralink GPIO Support"
++      depends on RALINK
++      help
++        Say yes here to support the Ralink SoC GPIO device
++
+ config GPIO_SPEAR_SPICS
+       bool "ST SPEAr13xx SPI Chip Select as GPIO support"
+       depends on PLAT_SPEAR
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -76,6 +76,7 @@ obj-$(CONFIG_GPIO_PCF857X)   += gpio-pcf85
+ obj-$(CONFIG_GPIO_PCH)                += gpio-pch.o
+ obj-$(CONFIG_GPIO_PL061)      += gpio-pl061.o
+ obj-$(CONFIG_GPIO_PXA)                += gpio-pxa.o
++obj-$(CONFIG_GPIO_RALINK)     += gpio-ralink.o
+ obj-$(CONFIG_GPIO_RC5T583)    += gpio-rc5t583.o
+ obj-$(CONFIG_GPIO_RDC321X)    += gpio-rdc321x.o
+ obj-$(CONFIG_GPIO_RCAR)               += gpio-rcar.o
+--- /dev/null
++++ b/drivers/gpio/gpio-ralink.c
+@@ -0,0 +1,355 @@
++/*
++ * 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.
++ *
++ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <linux/of_irq.h>
++#include <linux/irqdomain.h>
++#include <linux/interrupt.h>
++
++enum ralink_gpio_reg {
++      GPIO_REG_INT = 0,
++      GPIO_REG_EDGE,
++      GPIO_REG_RENA,
++      GPIO_REG_FENA,
++      GPIO_REG_DATA,
++      GPIO_REG_DIR,
++      GPIO_REG_POL,
++      GPIO_REG_SET,
++      GPIO_REG_RESET,
++      GPIO_REG_TOGGLE,
++      GPIO_REG_MAX
++};
++
++struct ralink_gpio_chip {
++      struct gpio_chip chip;
++      u8 regs[GPIO_REG_MAX];
++
++      spinlock_t lock;
++      void __iomem *membase;
++      struct irq_domain *domain;
++      int irq;
++
++      u32 rising;
++      u32 falling;
++};
++
++#define MAP_MAX       4
++static struct irq_domain *irq_map[MAP_MAX];
++static int irq_map_count;
++static atomic_t irq_refcount = ATOMIC_INIT(0);
++
++static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip)
++{
++      struct ralink_gpio_chip *rg;
++
++      rg = container_of(chip, struct ralink_gpio_chip, chip);
++
++      return rg;
++}
++
++static inline void rt_gpio_w32(struct ralink_gpio_chip *rg, u8 reg, u32 val)
++{
++      iowrite32(val, rg->membase + rg->regs[reg]);
++}
++
++static inline u32 rt_gpio_r32(struct ralink_gpio_chip *rg, u8 reg)
++{
++      return ioread32(rg->membase + rg->regs[reg]);
++}
++
++static void ralink_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++      rt_gpio_w32(rg, (value) ? GPIO_REG_SET : GPIO_REG_RESET, BIT(offset));
++}
++
++static int ralink_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++      return !!(rt_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
++}
++
++static int ralink_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++      unsigned long flags;
++      u32 t;
++
++      spin_lock_irqsave(&rg->lock, flags);
++      t = rt_gpio_r32(rg, GPIO_REG_DIR);
++      t &= ~BIT(offset);
++      rt_gpio_w32(rg, GPIO_REG_DIR, t);
++      spin_unlock_irqrestore(&rg->lock, flags);
++
++      return 0;
++}
++
++static int ralink_gpio_direction_output(struct gpio_chip *chip,
++                                      unsigned offset, int value)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++      unsigned long flags;
++      u32 t;
++
++      spin_lock_irqsave(&rg->lock, flags);
++      ralink_gpio_set(chip, offset, value);
++      t = rt_gpio_r32(rg, GPIO_REG_DIR);
++      t |= BIT(offset);
++      rt_gpio_w32(rg, GPIO_REG_DIR, t);
++      spin_unlock_irqrestore(&rg->lock, flags);
++
++      return 0;
++}
++
++static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
++{
++      struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
++
++      if (rg->irq < 1)
++              return -1;
++
++      return irq_create_mapping(rg->domain, pin);
++}
++
++static void ralink_gpio_irq_handler(struct irq_desc *desc)
++{
++      int i;
++
++      for (i = 0; i < irq_map_count; i++) {
++              struct irq_domain *domain = irq_map[i];
++              struct ralink_gpio_chip *rg;
++              unsigned long pending;
++              int bit;
++
++              rg = (struct ralink_gpio_chip *) domain->host_data;
++              pending = rt_gpio_r32(rg, GPIO_REG_INT);
++
++              for_each_set_bit(bit, &pending, rg->chip.ngpio) {
++                      u32 map = irq_find_mapping(domain, bit);
++                      generic_handle_irq(map);
++                      rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit));
++              }
++      }
++}
++
++static void ralink_gpio_irq_unmask(struct irq_data *d)
++{
++      struct ralink_gpio_chip *rg;
++      unsigned long flags;
++      u32 rise, fall;
++
++      rg = (struct ralink_gpio_chip *) d->domain->host_data;
++      rise = rt_gpio_r32(rg, GPIO_REG_RENA);
++      fall = rt_gpio_r32(rg, GPIO_REG_FENA);
++
++      spin_lock_irqsave(&rg->lock, flags);
++      rt_gpio_w32(rg, GPIO_REG_RENA, rise | (BIT(d->hwirq) & rg->rising));
++      rt_gpio_w32(rg, GPIO_REG_FENA, fall | (BIT(d->hwirq) & rg->falling));
++      spin_unlock_irqrestore(&rg->lock, flags);
++}
++
++static void ralink_gpio_irq_mask(struct irq_data *d)
++{
++      struct ralink_gpio_chip *rg;
++      unsigned long flags;
++      u32 rise, fall;
++
++      rg = (struct ralink_gpio_chip *) d->domain->host_data;
++      rise = rt_gpio_r32(rg, GPIO_REG_RENA);
++      fall = rt_gpio_r32(rg, GPIO_REG_FENA);
++
++      spin_lock_irqsave(&rg->lock, flags);
++      rt_gpio_w32(rg, GPIO_REG_FENA, fall & ~BIT(d->hwirq));
++      rt_gpio_w32(rg, GPIO_REG_RENA, rise & ~BIT(d->hwirq));
++      spin_unlock_irqrestore(&rg->lock, flags);
++}
++
++static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type)
++{
++      struct ralink_gpio_chip *rg;
++      u32 mask = BIT(d->hwirq);
++
++      rg = (struct ralink_gpio_chip *) d->domain->host_data;
++
++      if (type == IRQ_TYPE_PROBE) {
++              if ((rg->rising | rg->falling) & mask)
++                      return 0;
++
++              type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
++      }
++
++      if (type & IRQ_TYPE_EDGE_RISING)
++              rg->rising |= mask;
++      else
++              rg->rising &= ~mask;
++
++      if (type & IRQ_TYPE_EDGE_FALLING)
++              rg->falling |= mask;
++      else
++              rg->falling &= ~mask;
++
++      return 0;
++}
++
++static struct irq_chip ralink_gpio_irq_chip = {
++      .name           = "GPIO",
++      .irq_unmask     = ralink_gpio_irq_unmask,
++      .irq_mask       = ralink_gpio_irq_mask,
++      .irq_mask_ack   = ralink_gpio_irq_mask,
++      .irq_set_type   = ralink_gpio_irq_type,
++};
++
++static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
++{
++      irq_set_chip_and_handler(irq, &ralink_gpio_irq_chip, handle_level_irq);
++      irq_set_handler_data(irq, d);
++
++      return 0;
++}
++
++static const struct irq_domain_ops irq_domain_ops = {
++      .xlate = irq_domain_xlate_onecell,
++      .map = gpio_map,
++};
++
++static void ralink_gpio_irq_init(struct device_node *np,
++                               struct ralink_gpio_chip *rg)
++{
++      if (irq_map_count >= MAP_MAX)
++              return;
++
++      rg->irq = irq_of_parse_and_map(np, 0);
++      if (!rg->irq)
++              return;
++
++      rg->domain = irq_domain_add_linear(np, rg->chip.ngpio,
++                                         &irq_domain_ops, rg);
++      if (!rg->domain) {
++              dev_err(rg->chip.dev, "irq_domain_add_linear failed\n");
++              return;
++      }
++
++      irq_map[irq_map_count++] = rg->domain;
++
++      rt_gpio_w32(rg, GPIO_REG_RENA, 0x0);
++      rt_gpio_w32(rg, GPIO_REG_FENA, 0x0);
++
++      if (!atomic_read(&irq_refcount))
++              irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler);
++      atomic_inc(&irq_refcount);
++
++      dev_info(rg->chip.dev, "registering %d irq handlers\n", rg->chip.ngpio);
++}
++
++static int ralink_gpio_request(struct gpio_chip *chip, unsigned offset)
++{
++      int gpio = chip->base + offset;
++
++      return pinctrl_request_gpio(gpio);
++}
++
++static void ralink_gpio_free(struct gpio_chip *chip, unsigned offset)
++{
++      int gpio = chip->base + offset;
++
++      pinctrl_free_gpio(gpio);
++}
++
++static int ralink_gpio_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      struct ralink_gpio_chip *rg;
++      const __be32 *ngpio, *gpiobase;
++
++      if (!res) {
++              dev_err(&pdev->dev, "failed to find resource\n");
++              return -ENOMEM;
++      }
++
++      rg = devm_kzalloc(&pdev->dev,
++                      sizeof(struct ralink_gpio_chip), GFP_KERNEL);
++      if (!rg)
++              return -ENOMEM;
++
++      rg->membase = devm_ioremap_resource(&pdev->dev, res);
++      if (!rg->membase) {
++              dev_err(&pdev->dev, "cannot remap I/O memory region\n");
++              return -ENOMEM;
++      }
++
++      if (of_property_read_u8_array(np, "ralink,register-map",
++                      rg->regs, GPIO_REG_MAX)) {
++              dev_err(&pdev->dev, "failed to read register definition\n");
++              return -EINVAL;
++      }
++
++      ngpio = of_get_property(np, "ralink,num-gpios", NULL);
++      if (!ngpio) {
++              dev_err(&pdev->dev, "failed to read number of pins\n");
++              return -EINVAL;
++      }
++
++      gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
++      if (gpiobase)
++              rg->chip.base = be32_to_cpu(*gpiobase);
++      else
++              rg->chip.base = -1;
++
++      spin_lock_init(&rg->lock);
++
++      rg->chip.dev = &pdev->dev;
++      rg->chip.label = dev_name(&pdev->dev);
++      rg->chip.of_node = np;
++      rg->chip.ngpio = be32_to_cpu(*ngpio);
++      rg->chip.direction_input = ralink_gpio_direction_input;
++      rg->chip.direction_output = ralink_gpio_direction_output;
++      rg->chip.get = ralink_gpio_get;
++      rg->chip.set = ralink_gpio_set;
++      rg->chip.request = ralink_gpio_request;
++      rg->chip.to_irq = ralink_gpio_to_irq;
++      rg->chip.free = ralink_gpio_free;
++
++      /* set polarity to low for all lines */
++      rt_gpio_w32(rg, GPIO_REG_POL, 0);
++
++      dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
++
++      ralink_gpio_irq_init(np, rg);
++
++      return gpiochip_add(&rg->chip);
++}
++
++static const struct of_device_id ralink_gpio_match[] = {
++      { .compatible = "ralink,rt2880-gpio" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, ralink_gpio_match);
++
++static struct platform_driver ralink_gpio_driver = {
++      .probe = ralink_gpio_probe,
++      .driver = {
++              .name = "rt2880_gpio",
++              .owner = THIS_MODULE,
++              .of_match_table = ralink_gpio_match,
++      },
++};
++
++static int __init ralink_gpio_init(void)
++{
++      return platform_driver_register(&ralink_gpio_driver);
++}
++
++subsys_initcall(ralink_gpio_init);
diff --git a/target/linux/ramips/patches-4.4/0028-GPIO-ralink-add-mt7621-gpio-controller.patch b/target/linux/ramips/patches-4.4/0028-GPIO-ralink-add-mt7621-gpio-controller.patch
new file mode 100644 (file)
index 0000000..e407805
--- /dev/null
@@ -0,0 +1,405 @@
+From 61ac7d9b4228de8c332900902c2b93189b042eab Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 11:00:32 +0100
+Subject: [PATCH 28/53] GPIO: ralink: add mt7621 gpio controller
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/Kconfig          |    3 +
+ drivers/gpio/Kconfig       |    6 +
+ drivers/gpio/Makefile      |    1 +
+ drivers/gpio/gpio-mt7621.c |  354 ++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 364 insertions(+)
+ create mode 100644 drivers/gpio/gpio-mt7621.c
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -587,6 +587,9 @@ config RALINK
+       select RESET_CONTROLLER
+       select PINCTRL
+       select PINCTRL_RT2880
++      select ARCH_HAS_RESET_CONTROLLER
++      select RESET_CONTROLLER
++      select ARCH_REQUIRE_GPIOLIB
+ config SGI_IP22
+       bool "SGI IP22 (Indy/Indigo2)"
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -260,6 +260,12 @@ config GPIO_MB86S7X
+       help
+         Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs.
++config GPIO_MT7621
++      bool "Mediatek GPIO Support"
++      depends on SOC_MT7620 || SOC_MT7621
++      help
++        Say yes here to support the Mediatek SoC GPIO device
++
+ config GPIO_MM_LANTIQ
+       bool "Lantiq Memory mapped GPIOs"
+       depends on LANTIQ && SOC_XWAY
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -120,3 +120,4 @@ obj-$(CONFIG_GPIO_XTENSA)  += gpio-xtensa
+ obj-$(CONFIG_GPIO_ZEVIO)      += gpio-zevio.o
+ obj-$(CONFIG_GPIO_ZYNQ)               += gpio-zynq.o
+ obj-$(CONFIG_GPIO_ZX)         += gpio-zx.o
++obj-$(CONFIG_GPIO_MT7621)     += gpio-mt7621.o
+--- /dev/null
++++ b/drivers/gpio/gpio-mt7621.c
+@@ -0,0 +1,354 @@
++/*
++ * 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.
++ *
++ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/gpio.h>
++#include <linux/module.h>
++#include <linux/of_irq.h>
++#include <linux/spinlock.h>
++#include <linux/irqdomain.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++
++#define MTK_MAX_BANK          3
++#define MTK_BANK_WIDTH                32
++
++enum mediatek_gpio_reg {
++      GPIO_REG_CTRL = 0,
++      GPIO_REG_POL,
++      GPIO_REG_DATA,
++      GPIO_REG_DSET,
++      GPIO_REG_DCLR,
++      GPIO_REG_REDGE,
++      GPIO_REG_FEDGE,
++      GPIO_REG_HLVL,
++      GPIO_REG_LLVL,
++      GPIO_REG_STAT,
++      GPIO_REG_EDGE,
++};
++
++static void __iomem *mediatek_gpio_membase;
++static int mediatek_gpio_irq;
++static struct irq_domain *mediatek_gpio_irq_domain;
++static atomic_t irq_refcount = ATOMIC_INIT(0);
++
++struct mtk_gc {
++      struct gpio_chip chip;
++      spinlock_t lock;
++      int bank;
++      u32 rising;
++      u32 falling;
++} *gc_map[MTK_MAX_BANK];
++
++static inline struct mtk_gc
++*to_mediatek_gpio(struct gpio_chip *chip)
++{
++      struct mtk_gc *mgc;
++
++      mgc = container_of(chip, struct mtk_gc, chip);
++
++      return mgc;
++}
++
++static inline void
++mtk_gpio_w32(struct mtk_gc *rg, u8 reg, u32 val)
++{
++      iowrite32(val, mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4));
++}
++
++static inline u32
++mtk_gpio_r32(struct mtk_gc *rg, u8 reg)
++{
++      return ioread32(mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4));
++}
++
++static void
++mediatek_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++      struct mtk_gc *rg = to_mediatek_gpio(chip);
++
++      mtk_gpio_w32(rg, (value) ? GPIO_REG_DSET : GPIO_REG_DCLR, BIT(offset));
++}
++
++static int
++mediatek_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++      struct mtk_gc *rg = to_mediatek_gpio(chip);
++
++      return !!(mtk_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
++}
++
++static int
++mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++      struct mtk_gc *rg = to_mediatek_gpio(chip);
++      unsigned long flags;
++      u32 t;
++
++      spin_lock_irqsave(&rg->lock, flags);
++      t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
++      t &= ~BIT(offset);
++      mtk_gpio_w32(rg, GPIO_REG_CTRL, t);
++      spin_unlock_irqrestore(&rg->lock, flags);
++
++      return 0;
++}
++
++static int
++mediatek_gpio_direction_output(struct gpio_chip *chip,
++                                      unsigned offset, int value)
++{
++      struct mtk_gc *rg = to_mediatek_gpio(chip);
++      unsigned long flags;
++      u32 t;
++
++      spin_lock_irqsave(&rg->lock, flags);
++      t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
++      t |= BIT(offset);
++      mtk_gpio_w32(rg, GPIO_REG_CTRL, t);
++      mediatek_gpio_set(chip, offset, value);
++      spin_unlock_irqrestore(&rg->lock, flags);
++
++      return 0;
++}
++
++static int
++mediatek_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
++{
++      struct mtk_gc *rg = to_mediatek_gpio(chip);
++      unsigned long flags;
++      u32 t;
++
++      spin_lock_irqsave(&rg->lock, flags);
++      t = mtk_gpio_r32(rg, GPIO_REG_CTRL);
++      spin_unlock_irqrestore(&rg->lock, flags);
++
++      if (t & BIT(offset))
++              return 0;
++
++      return 1;
++}
++
++static int
++mediatek_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
++{
++      struct mtk_gc *rg = to_mediatek_gpio(chip);
++
++      return irq_create_mapping(mediatek_gpio_irq_domain, pin + (rg->bank * MTK_BANK_WIDTH));
++}
++
++static int
++mediatek_gpio_bank_probe(struct platform_device *pdev, struct device_node *bank)
++{
++      const __be32 *id = of_get_property(bank, "reg", NULL);
++      struct mtk_gc *rg = devm_kzalloc(&pdev->dev,
++                              sizeof(struct mtk_gc), GFP_KERNEL);
++
++      if (!rg || !id || be32_to_cpu(*id) > MTK_MAX_BANK)
++              return -ENOMEM;
++
++      gc_map[be32_to_cpu(*id)] = rg;
++
++      memset(rg, 0, sizeof(struct mtk_gc));
++
++      spin_lock_init(&rg->lock);
++
++      rg->chip.dev = &pdev->dev;
++      rg->chip.label = dev_name(&pdev->dev);
++      rg->chip.of_node = bank;
++      rg->chip.base = MTK_BANK_WIDTH * be32_to_cpu(*id);
++      rg->chip.ngpio = MTK_BANK_WIDTH;
++      rg->chip.direction_input = mediatek_gpio_direction_input;
++      rg->chip.direction_output = mediatek_gpio_direction_output;
++      rg->chip.get_direction = mediatek_gpio_get_direction;
++      rg->chip.get = mediatek_gpio_get;
++      rg->chip.set = mediatek_gpio_set;
++      if (mediatek_gpio_irq_domain)
++              rg->chip.to_irq = mediatek_gpio_to_irq;
++      rg->bank = be32_to_cpu(*id);
++
++      /* set polarity to low for all gpios */
++      mtk_gpio_w32(rg, GPIO_REG_POL, 0);
++
++      dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
++
++      return gpiochip_add(&rg->chip);
++}
++
++static void
++mediatek_gpio_irq_handler(struct irq_desc *desc)
++{
++      int i;
++
++      for (i = 0; i < MTK_MAX_BANK; i++) {
++              struct mtk_gc *rg = gc_map[i];
++              unsigned long pending;
++              int bit;
++
++              if (!rg)
++                      continue;
++
++              pending = mtk_gpio_r32(rg, GPIO_REG_STAT);
++
++              for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) {
++                      u32 map = irq_find_mapping(mediatek_gpio_irq_domain, (MTK_BANK_WIDTH * i) + bit);
++
++                      generic_handle_irq(map);
++                      mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit));
++              }
++      }
++}
++
++static void
++mediatek_gpio_irq_unmask(struct irq_data *d)
++{
++      int pin = d->hwirq;
++      int bank = pin / 32;
++      struct mtk_gc *rg = gc_map[bank];
++      unsigned long flags;
++      u32 rise, fall;
++
++      if (!rg)
++              return;
++
++      rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
++      fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
++
++      spin_lock_irqsave(&rg->lock, flags);
++      mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(d->hwirq) & rg->rising));
++      mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(d->hwirq) & rg->falling));
++      spin_unlock_irqrestore(&rg->lock, flags);
++}
++
++static void
++mediatek_gpio_irq_mask(struct irq_data *d)
++{
++      int pin = d->hwirq;
++      int bank = pin / 32;
++      struct mtk_gc *rg = gc_map[bank];
++      unsigned long flags;
++      u32 rise, fall;
++
++      if (!rg)
++              return;
++
++      rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
++      fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
++
++      spin_lock_irqsave(&rg->lock, flags);
++      mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(d->hwirq));
++      mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(d->hwirq));
++      spin_unlock_irqrestore(&rg->lock, flags);
++}
++
++static int
++mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
++{
++      int pin = d->hwirq;
++      int bank = pin / 32;
++      struct mtk_gc *rg = gc_map[bank];
++      u32 mask = BIT(d->hwirq);
++
++      if (!rg)
++              return -1;
++
++      if (type == IRQ_TYPE_PROBE) {
++              if ((rg->rising | rg->falling) & mask)
++                      return 0;
++
++              type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
++      }
++
++      if (type & IRQ_TYPE_EDGE_RISING)
++              rg->rising |= mask;
++      else
++              rg->rising &= ~mask;
++
++      if (type & IRQ_TYPE_EDGE_FALLING)
++              rg->falling |= mask;
++      else
++              rg->falling &= ~mask;
++
++      return 0;
++}
++
++static struct irq_chip mediatek_gpio_irq_chip = {
++      .name           = "GPIO",
++      .irq_unmask     = mediatek_gpio_irq_unmask,
++      .irq_mask       = mediatek_gpio_irq_mask,
++      .irq_mask_ack   = mediatek_gpio_irq_mask,
++      .irq_set_type   = mediatek_gpio_irq_type,
++};
++
++static int
++mediatek_gpio_gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
++{
++      irq_set_chip_and_handler(irq, &mediatek_gpio_irq_chip, handle_level_irq);
++      irq_set_handler_data(irq, d);
++
++      return 0;
++}
++
++static const struct irq_domain_ops irq_domain_ops = {
++      .xlate = irq_domain_xlate_onecell,
++      .map = mediatek_gpio_gpio_map,
++};
++
++static int
++mediatek_gpio_probe(struct platform_device *pdev)
++{
++      struct device_node *bank, *np = pdev->dev.of_node;
++      struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      mediatek_gpio_membase = devm_ioremap_resource(&pdev->dev, res);
++      if (IS_ERR(mediatek_gpio_membase))
++              return PTR_ERR(mediatek_gpio_membase);
++
++      mediatek_gpio_irq = irq_of_parse_and_map(np, 0);
++      if (mediatek_gpio_irq) {
++              mediatek_gpio_irq_domain = irq_domain_add_linear(np,
++                      MTK_MAX_BANK * MTK_BANK_WIDTH,
++                      &irq_domain_ops, NULL);
++              if (!mediatek_gpio_irq_domain)
++                      dev_err(&pdev->dev, "irq_domain_add_linear failed\n");
++      }
++
++      for_each_child_of_node(np, bank)
++              if (of_device_is_compatible(bank, "mtk,mt7621-gpio-bank"))
++                      mediatek_gpio_bank_probe(pdev, bank);
++
++      if (mediatek_gpio_irq_domain)
++              irq_set_chained_handler(mediatek_gpio_irq, mediatek_gpio_irq_handler);
++
++      return 0;
++}
++
++static const struct of_device_id mediatek_gpio_match[] = {
++      { .compatible = "mtk,mt7621-gpio" },
++      {},
++};
++MODULE_DEVICE_TABLE(of, mediatek_gpio_match);
++
++static struct platform_driver mediatek_gpio_driver = {
++      .probe = mediatek_gpio_probe,
++      .driver = {
++              .name = "mt7621_gpio",
++              .owner = THIS_MODULE,
++              .of_match_table = mediatek_gpio_match,
++      },
++};
++
++static int __init
++mediatek_gpio_init(void)
++{
++      return platform_driver_register(&mediatek_gpio_driver);
++}
++
++subsys_initcall(mediatek_gpio_init);
diff --git a/target/linux/ramips/patches-4.4/0029-phy-usb-add-ralink-phy.patch b/target/linux/ramips/patches-4.4/0029-phy-usb-add-ralink-phy.patch
new file mode 100644 (file)
index 0000000..4068e9a
--- /dev/null
@@ -0,0 +1,293 @@
+From b00b5eafa7e8d059bd0ce844e66f648916953270 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 3 Jan 2016 19:11:22 +0100
+Subject: [PATCH 2/3] phy: ralink-usb: add driver for Mediatek/Ralink
+
+Add a driver to setup the USB phy on Mediatek/Ralink SoCs.
+The driver is trivial and only sets up power and host mode.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ .../devicetree/bindings/phy/ralink-usb-phy.txt     |   17 ++
+ drivers/phy/Kconfig                                |    8 +
+ drivers/phy/Makefile                               |    1 +
+ drivers/phy/phy-ralink-usb.c                       |  171 ++++++++++++++++++++
+ 4 files changed, 197 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/phy/ralink-usb-phy.txt
+ create mode 100644 drivers/phy/phy-ralink-usb.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/phy/ralink-usb-phy.txt
+@@ -0,0 +1,17 @@
++Mediatek/Ralink USB PHY
++
++Required properties:
++ - compatible: ralink,rt3352-usbphy or mediatek,mt7620-usbphy
++ - #phy-cells: should be 0
++ - resets: the two reset controllers for host and device
++ - reset-names: the names of the 2 reset controllers
++
++Example:
++
++usbphy: phy {
++      compatible = "mediatek,mt7620-usbphy";
++      #phy-cells = <0>;
++
++      resets = <&rstctrl 22 &rstctrl 25>;
++      reset-names = "host", "device";
++};
+--- a/drivers/phy/Kconfig
++++ b/drivers/phy/Kconfig
+@@ -341,6 +341,14 @@ config PHY_XGENE
+       help
+         This option enables support for APM X-Gene SoC multi-purpose PHY.
++config PHY_RALINK_USB
++      tristate "Ralink USB PHY driver"
++      select GENERIC_PHY
++      depends on RALINK
++      help
++        This option enables support for the Ralink USB PHY found inside
++        RT3352 and MT7620.
++
+ config PHY_STIH407_USB
+       tristate "STMicroelectronics USB2 picoPHY driver for STiH407 family"
+       depends on RESET_CONTROLLER
+--- a/drivers/phy/Makefile
++++ b/drivers/phy/Makefile
+@@ -48,3 +48,4 @@ obj-$(CONFIG_PHY_TUSB1210)           += phy-tusb1
+ obj-$(CONFIG_PHY_BRCMSTB_SATA)                += phy-brcmstb-sata.o
+ obj-$(CONFIG_PHY_PISTACHIO_USB)               += phy-pistachio-usb.o
+ obj-$(CONFIG_PHY_CYGNUS_PCIE)         += phy-bcm-cygnus-pcie.o
++obj-$(CONFIG_PHY_RALINK_USB)          += phy-ralink-usb.o
+--- /dev/null
++++ b/drivers/phy/phy-ralink-usb.c
+@@ -0,0 +1,228 @@
++/*
++ * Allwinner ralink USB phy driver
++ *
++ * Copyright (C) 2016 John Crispin <blogic@openwrt.org>
++ *
++ * Based on code from
++ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/reset.h>
++#include <linux/of_platform.h>
++
++#include <asm/mach-ralink/ralink_regs.h>
++
++#define RT_SYSC_REG_SYSCFG1           0x014
++#define RT_SYSC_REG_CLKCFG1           0x030
++#define RT_SYSC_REG_USB_PHY_CFG               0x05c
++
++#define OFS_U2_PHY_AC0                  0x00
++#define OFS_U2_PHY_AC1                  0x04
++#define OFS_U2_PHY_AC2                  0x08
++#define OFS_U2_PHY_ACR0                 0x10
++#define OFS_U2_PHY_ACR1                 0x14
++#define OFS_U2_PHY_ACR2                 0x18
++#define OFS_U2_PHY_ACR3                 0x1C
++#define OFS_U2_PHY_ACR4                 0x20
++#define OFS_U2_PHY_AMON0                0x24
++#define OFS_U2_PHY_DCR0                 0x60
++#define OFS_U2_PHY_DCR1                 0x64
++#define OFS_U2_PHY_DTM0                 0x68
++#define OFS_U2_PHY_DTM1                 0x6C
++
++#define RT_RSTCTRL_UDEV                       BIT(25)
++#define RT_RSTCTRL_UHST                       BIT(22)
++#define RT_SYSCFG1_USB0_HOST_MODE     BIT(10)
++
++#define MT7620_CLKCFG1_UPHY0_CLK_EN   BIT(25)
++#define MT7620_CLKCFG1_UPHY1_CLK_EN   BIT(22)
++#define RT_CLKCFG1_UPHY1_CLK_EN               BIT(20)
++#define RT_CLKCFG1_UPHY0_CLK_EN               BIT(18)
++
++#define USB_PHY_UTMI_8B60M            BIT(1)
++#define UDEV_WAKEUP                   BIT(0)
++
++struct ralink_usb_phy {
++      struct reset_control    *rstdev;
++      struct reset_control    *rsthost;
++      u32                     clk;
++      struct phy              *phy;
++      void __iomem            *base;
++};
++
++static void u2_phy_w32(struct ralink_usb_phy *phy, u32 val, u32 reg)
++{
++      iowrite32(val, phy->base + reg);
++}
++
++static u32 u2_phy_r32(struct ralink_usb_phy *phy, u32 reg)
++{
++      return ioread32(phy->base + reg);
++}
++
++static void
++u2_phy_init(struct ralink_usb_phy *phy)
++{
++      u2_phy_r32(phy, OFS_U2_PHY_AC2);
++      u2_phy_r32(phy, OFS_U2_PHY_ACR0);
++      u2_phy_r32(phy, OFS_U2_PHY_DCR0);
++
++      u2_phy_w32(phy, 0x00ffff02, OFS_U2_PHY_DCR0);
++      u2_phy_r32(phy, OFS_U2_PHY_DCR0);
++      u2_phy_w32(phy, 0x00555502, OFS_U2_PHY_DCR0);
++      u2_phy_r32(phy, OFS_U2_PHY_DCR0);
++      u2_phy_w32(phy, 0x00aaaa02, OFS_U2_PHY_DCR0);
++      u2_phy_r32(phy, OFS_U2_PHY_DCR0);
++      u2_phy_w32(phy, 0x00000402, OFS_U2_PHY_DCR0);
++      u2_phy_r32(phy, OFS_U2_PHY_DCR0);
++      u2_phy_w32(phy, 0x0048086a, OFS_U2_PHY_AC0);
++      u2_phy_w32(phy, 0x4400001c, OFS_U2_PHY_AC1);
++      u2_phy_w32(phy, 0xc0200000, OFS_U2_PHY_ACR3);
++      u2_phy_w32(phy, 0x02000000, OFS_U2_PHY_DTM0);
++}
++
++static int ralink_usb_phy_power_on(struct phy *_phy)
++{
++      struct ralink_usb_phy *phy = phy_get_drvdata(_phy);
++      u32 t;
++
++      /* enable the phy */
++      rt_sysc_m32(0, phy->clk, RT_SYSC_REG_CLKCFG1);
++
++      /* setup host mode */
++      rt_sysc_m32(0, RT_SYSCFG1_USB0_HOST_MODE, RT_SYSC_REG_SYSCFG1);
++
++      /* deassert the reset lines */
++      reset_control_deassert(phy->rsthost);
++      reset_control_deassert(phy->rstdev);
++
++      /*
++       * The SDK kernel had a delay of 100ms. however on device
++       * testing showed that 10ms is enough
++       */
++      mdelay(10);
++
++      if (!IS_ERR(phy->base))
++              u2_phy_init(phy);
++
++      /* print some status info */
++      t = rt_sysc_r32(RT_SYSC_REG_USB_PHY_CFG);
++      dev_info(&phy->phy->dev, "remote usb device wakeup %s\n",
++              (t & UDEV_WAKEUP) ? ("enabled") : ("disabled"));
++      if (t & USB_PHY_UTMI_8B60M)
++              dev_info(&phy->phy->dev, "UTMI 8bit 60MHz\n");
++      else
++              dev_info(&phy->phy->dev, "UTMI 16bit 30MHz\n");
++
++      return 0;
++}
++
++static int ralink_usb_phy_power_off(struct phy *_phy)
++{
++      struct ralink_usb_phy *phy = phy_get_drvdata(_phy);
++
++      /* assert the reset lines */
++      reset_control_assert(phy->rstdev);
++      reset_control_assert(phy->rsthost);
++
++      /* disable the phy */
++      rt_sysc_m32(phy->clk, 0, RT_SYSC_REG_CLKCFG1);
++
++      return 0;
++}
++
++static struct phy_ops ralink_usb_phy_ops = {
++      .power_on       = ralink_usb_phy_power_on,
++      .power_off      = ralink_usb_phy_power_off,
++      .owner          = THIS_MODULE,
++};
++
++static const struct of_device_id ralink_usb_phy_of_match[] = {
++      {
++              .compatible = "ralink,rt3352-usbphy",
++              .data = (void *) (RT_CLKCFG1_UPHY1_CLK_EN |
++                                RT_CLKCFG1_UPHY0_CLK_EN)
++      },
++      {
++              .compatible = "mediatek,mt7620-usbphy",
++              .data = (void *) (MT7620_CLKCFG1_UPHY1_CLK_EN |
++                                MT7620_CLKCFG1_UPHY0_CLK_EN) },
++      { },
++};
++MODULE_DEVICE_TABLE(of, ralink_usb_phy_of_match);
++
++static int ralink_usb_phy_probe(struct platform_device *pdev)
++{
++      struct resource *res;
++      struct device *dev = &pdev->dev;
++      struct phy_provider *phy_provider;
++      const struct of_device_id *match;
++      struct ralink_usb_phy *phy;
++
++      phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
++      if (!phy)
++              return -ENOMEM;
++
++      match = of_match_device(ralink_usb_phy_of_match, &pdev->dev);
++      if (!match)
++              return -ENODEV;
++
++      phy->clk = (int) match->data;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      phy->base = devm_ioremap_resource(&pdev->dev, res);
++
++      phy->rsthost = devm_reset_control_get(&pdev->dev, "host");
++      if (IS_ERR(phy->rsthost)) {
++              dev_err(dev, "host reset is missing\n");
++              return PTR_ERR(phy->rsthost);
++      }
++
++      phy->rstdev = devm_reset_control_get(&pdev->dev, "device");
++      if (IS_ERR(phy->rstdev)) {
++              dev_err(dev, "device reset is missing\n");
++              return PTR_ERR(phy->rstdev);
++      }
++
++      phy->phy = devm_phy_create(dev, NULL, &ralink_usb_phy_ops);
++      if (IS_ERR(phy->phy)) {
++              dev_err(dev, "failed to create PHY\n");
++              return PTR_ERR(phy->phy);
++      }
++      phy_set_drvdata(phy->phy, phy);
++
++      phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
++
++      return PTR_ERR_OR_ZERO(phy_provider);
++}
++
++static struct platform_driver ralink_usb_phy_driver = {
++      .probe  = ralink_usb_phy_probe,
++      .driver = {
++              .of_match_table = ralink_usb_phy_of_match,
++              .name  = "ralink-usb-phy",
++      }
++};
++module_platform_driver(ralink_usb_phy_driver);
++
++MODULE_DESCRIPTION("Ralink USB phy driver");
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ramips/patches-4.4/0031-uvc-add-iPassion-iP2970-support.patch b/target/linux/ramips/patches-4.4/0031-uvc-add-iPassion-iP2970-support.patch
new file mode 100644 (file)
index 0000000..0279568
--- /dev/null
@@ -0,0 +1,246 @@
+From 975e76214cd2516eb6cfff4c3eec581872645e88 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 19 Sep 2013 01:50:59 +0200
+Subject: [PATCH 31/53] uvc: add iPassion iP2970 support
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/media/usb/uvc/uvc_driver.c |   12 +++
+ drivers/media/usb/uvc/uvc_status.c |    2 +
+ drivers/media/usb/uvc/uvc_video.c  |  147 ++++++++++++++++++++++++++++++++++++
+ drivers/media/usb/uvc/uvcvideo.h   |    5 +-
+ 4 files changed, 165 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/usb/uvc/uvc_driver.c
++++ b/drivers/media/usb/uvc/uvc_driver.c
+@@ -2539,6 +2539,18 @@ static struct usb_device_id uvc_ids[] =
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_FORCE_Y8 },
++      /* iPassion iP2970 */
++      { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
++                              | USB_DEVICE_ID_MATCH_INT_INFO,
++       .idVendor              = 0x1B3B,
++       .idProduct             = 0x2970,
++       .bInterfaceClass       = USB_CLASS_VIDEO,
++       .bInterfaceSubClass    = 1,
++       .bInterfaceProtocol    = 0,
++       .driver_info           = UVC_QUIRK_PROBE_MINMAX
++                              | UVC_QUIRK_STREAM_NO_FID
++                              | UVC_QUIRK_MOTION
++                              | UVC_QUIRK_SINGLE_ISO },
+       /* Generic USB Video Class */
+       { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+       {}
+--- a/drivers/media/usb/uvc/uvc_status.c
++++ b/drivers/media/usb/uvc/uvc_status.c
+@@ -139,6 +139,7 @@ static void uvc_status_complete(struct u
+               switch (dev->status[0] & 0x0f) {
+               case UVC_STATUS_TYPE_CONTROL:
+                       uvc_event_control(dev, dev->status, len);
++                      dev->motion = 1;
+                       break;
+               case UVC_STATUS_TYPE_STREAMING:
+@@ -182,6 +183,7 @@ int uvc_status_init(struct uvc_device *d
+       }
+       pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
++      dev->motion = 0;
+       /* For high-speed interrupt endpoints, the bInterval value is used as
+        * an exponent of two. Some developers forgot about it.
+--- a/drivers/media/usb/uvc/uvc_video.c
++++ b/drivers/media/usb/uvc/uvc_video.c
+@@ -21,6 +21,11 @@
+ #include <linux/wait.h>
+ #include <linux/atomic.h>
+ #include <asm/unaligned.h>
++#include <linux/skbuff.h>
++#include <linux/kobject.h>
++#include <linux/netlink.h>
++#include <linux/kobject.h>
++#include <linux/workqueue.h>
+ #include <media/v4l2-common.h>
+@@ -1092,9 +1097,149 @@ static void uvc_video_decode_data(struct
+       }
+ }
++struct bh_priv {
++      unsigned long   seen;
++};
++
++struct bh_event {
++      const char              *name;
++      struct sk_buff          *skb;
++      struct work_struct      work;
++};
++
++#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, "webcam", ##args )
++#define BH_DBG(fmt, args...) do {} while (0)
++#define BH_SKB_SIZE     2048
++
++extern u64 uevent_next_seqnum(void);
++static int seen = 0;
++
++static int bh_event_add_var(struct bh_event *event, int argv,
++              const char *format, ...)
++{
++      static char buf[128];
++      char *s;
++      va_list args;
++      int len;
++
++      if (argv)
++              return 0;
++
++      va_start(args, format);
++      len = vsnprintf(buf, sizeof(buf), format, args);
++      va_end(args);
++
++      if (len >= sizeof(buf)) {
++              BH_ERR("buffer size too small\n");
++              WARN_ON(1);
++              return -ENOMEM;
++      }
++
++      s = skb_put(event->skb, len + 1);
++      strcpy(s, buf);
++
++      BH_DBG("added variable '%s'\n", s);
++
++      return 0;
++}
++
++static int motion_hotplug_fill_event(struct bh_event *event)
++{
++      int s = jiffies;
++      int ret;
++
++      if (!seen)
++              seen = jiffies;
++
++      ret = bh_event_add_var(event, 0, "HOME=%s", "/");
++      if (ret)
++              return ret;
++
++      ret = bh_event_add_var(event, 0, "PATH=%s",
++              "/sbin:/bin:/usr/sbin:/usr/bin");
++      if (ret)
++              return ret;
++
++      ret = bh_event_add_var(event, 0, "SUBSYSTEM=usb");
++      if (ret)
++              return ret;
++
++      ret = bh_event_add_var(event, 0, "ACTION=motion");
++      if (ret)
++              return ret;
++
++      ret = bh_event_add_var(event, 0, "SEEN=%d", s - seen);
++      if (ret)
++              return ret;
++      seen = s;
++
++      ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
++
++      return ret;
++}
++
++static void motion_hotplug_work(struct work_struct *work)
++{
++      struct bh_event *event = container_of(work, struct bh_event, work);
++      int ret = 0;
++
++      event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
++      if (!event->skb)
++              goto out_free_event;
++
++      ret = bh_event_add_var(event, 0, "%s@", "add");
++      if (ret)
++              goto out_free_skb;
++
++      ret = motion_hotplug_fill_event(event);
++      if (ret)
++              goto out_free_skb;
++
++      NETLINK_CB(event->skb).dst_group = 1;
++      broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
++
++out_free_skb:
++      if (ret) {
++              BH_ERR("work error %d\n", ret);
++              kfree_skb(event->skb);
++      }
++out_free_event:
++      kfree(event);
++}
++
++static int motion_hotplug_create_event(void)
++{
++      struct bh_event *event;
++
++      event = kzalloc(sizeof(*event), GFP_KERNEL);
++      if (!event)
++              return -ENOMEM;
++
++      event->name = "motion";
++
++      INIT_WORK(&event->work, (void *)(void *)motion_hotplug_work);
++      schedule_work(&event->work);
++
++      return 0;
++}
++
++#define MOTION_FLAG_OFFSET    4
+ static void uvc_video_decode_end(struct uvc_streaming *stream,
+               struct uvc_buffer *buf, const __u8 *data, int len)
+ {
++      if ((stream->dev->quirks & UVC_QUIRK_MOTION) &&
++                      (data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) {
++              u8 *mem;
++              buf->state = UVC_BUF_STATE_READY;
++              mem = (u8 *) (buf->mem + MOTION_FLAG_OFFSET);
++              if ( stream->dev->motion ) {
++                      stream->dev->motion = 0;
++                      motion_hotplug_create_event();
++              } else {
++                      *mem &= 0x7f;
++              }
++      }
++
+       /* Mark the buffer as done if the EOF marker is set. */
+       if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
+               uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
+@@ -1507,6 +1652,8 @@ static int uvc_init_video_isoc(struct uv
+       if (npackets == 0)
+               return -ENOMEM;
++      if (stream->dev->quirks & UVC_QUIRK_SINGLE_ISO)
++              npackets = 1;
+       size = npackets * psize;
+       for (i = 0; i < UVC_URBS; ++i) {
+--- a/drivers/media/usb/uvc/uvcvideo.h
++++ b/drivers/media/usb/uvc/uvcvideo.h
+@@ -152,7 +152,9 @@
+ #define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
+ #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT       0x00000400
+ #define UVC_QUIRK_FORCE_Y8            0x00000800
+-
++#define UVC_QUIRK_MOTION              0x00001000
++#define UVC_QUIRK_SINGLE_ISO          0x00002000
++ 
+ /* Format flags */
+ #define UVC_FMT_FLAG_COMPRESSED               0x00000001
+ #define UVC_FMT_FLAG_STREAM           0x00000002
+@@ -550,6 +552,7 @@ struct uvc_device {
+       __u8 *status;
+       struct input_dev *input;
+       char input_phys[64];
++      int motion;
+ };
+ enum uvc_handle_state {
diff --git a/target/linux/ramips/patches-4.4/0032-USB-dwc2-add-device_reset.patch b/target/linux/ramips/patches-4.4/0032-USB-dwc2-add-device_reset.patch
new file mode 100644 (file)
index 0000000..e77e02f
--- /dev/null
@@ -0,0 +1,29 @@
+From a758e0870c6d1e4b0272f6e7f9efa9face5534bb Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:49:07 +0100
+Subject: [PATCH 32/53] USB: dwc2: add device_reset()
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/usb/dwc2/hcd.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/usb/dwc2/hcd.c
++++ b/drivers/usb/dwc2/hcd.c
+@@ -47,6 +47,7 @@
+ #include <linux/io.h>
+ #include <linux/slab.h>
+ #include <linux/usb.h>
++#include <linux/reset.h>
+ #include <linux/usb/hcd.h>
+ #include <linux/usb/ch11.h>
+@@ -3002,6 +3003,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hso
+       retval = -ENOMEM;
++      device_reset(hsotg->dev);
++
+       hcfg = dwc2_readl(hsotg->regs + HCFG);
+       dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
diff --git a/target/linux/ramips/patches-4.4/0033-xhci-mediatek-support-MTK-xHCI-host-controller.patch b/target/linux/ramips/patches-4.4/0033-xhci-mediatek-support-MTK-xHCI-host-controller.patch
new file mode 100644 (file)
index 0000000..a00d2d7
--- /dev/null
@@ -0,0 +1,1517 @@
+From: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Date: Tue, 24 Nov 2015 13:09:55 +0200
+Subject: [PATCH] xhci: mediatek: support MTK xHCI host controller
+
+There some vendor quirks for MTK xhci host controller:
+1. It defines some extra SW scheduling parameters for HW
+  to minimize the scheduling effort for synchronous and
+  interrupt endpoints. The parameters are put into reseved
+  DWs of slot context and endpoint context.
+2. Its IMODI unit for Interrupter Moderation register is
+  8 times as much as that defined in xHCI spec.
+3. Its TDS in  Normal TRB defines a number of packets that
+  remains to be transferred for a TD after processing all
+  Max packets in all previous TRBs.
+
+Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
+Tested-by: Daniel Thompson <daniel.thompson@linaro.org>
+Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ create mode 100644 drivers/usb/host/xhci-mtk-sch.c
+ create mode 100644 drivers/usb/host/xhci-mtk.c
+ create mode 100644 drivers/usb/host/xhci-mtk.h
+
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -41,6 +41,15 @@ config USB_XHCI_PLATFORM
+         If unsure, say N.
++config USB_XHCI_MTK
++      tristate "xHCI support for Mediatek MT65xx"
++      select MFD_SYSCON
++      depends on ARCH_MEDIATEK || COMPILE_TEST
++      ---help---
++        Say 'Y' to enable the support for the xHCI host controller
++        found in Mediatek MT65xx SoCs.
++        If unsure, say N.
++
+ config USB_XHCI_MVEBU
+       tristate "xHCI support for Marvell Armada 375/38x"
+       select USB_XHCI_PLATFORM
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -13,6 +13,9 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
+ xhci-hcd-y := xhci.o xhci-mem.o
+ xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
+ xhci-hcd-y += xhci-trace.o
++ifneq ($(CONFIG_USB_XHCI_MTK), )
++      xhci-hcd-y += xhci-mtk-sch.o
++endif
+ xhci-plat-hcd-y := xhci-plat.o
+ ifneq ($(CONFIG_USB_XHCI_MVEBU), )
+@@ -64,6 +67,7 @@ obj-$(CONFIG_USB_FHCI_HCD)   += fhci.o
+ obj-$(CONFIG_USB_XHCI_HCD)    += xhci-hcd.o
+ obj-$(CONFIG_USB_XHCI_PCI)    += xhci-pci.o
+ obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
++obj-$(CONFIG_USB_XHCI_MTK)    += xhci-mtk.o
+ obj-$(CONFIG_USB_SL811_HCD)   += sl811-hcd.o
+ obj-$(CONFIG_USB_SL811_CS)    += sl811_cs.o
+ obj-$(CONFIG_USB_U132_HCD)    += u132-hcd.o
+--- /dev/null
++++ b/drivers/usb/host/xhci-mtk-sch.c
+@@ -0,0 +1,415 @@
++/*
++ * Copyright (c) 2015 MediaTek Inc.
++ * Author:
++ *  Zhigang.Wei <zhigang.wei@mediatek.com>
++ *  Chunfeng.Yun <chunfeng.yun@mediatek.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++
++#include "xhci.h"
++#include "xhci-mtk.h"
++
++#define SS_BW_BOUNDARY        51000
++/* table 5-5. High-speed Isoc Transaction Limits in usb_20 spec */
++#define HS_BW_BOUNDARY        6144
++/* usb2 spec section11.18.1: at most 188 FS bytes per microframe */
++#define FS_PAYLOAD_MAX 188
++
++/* mtk scheduler bitmasks */
++#define EP_BPKTS(p)   ((p) & 0x3f)
++#define EP_BCSCOUNT(p)        (((p) & 0x7) << 8)
++#define EP_BBM(p)     ((p) << 11)
++#define EP_BOFFSET(p) ((p) & 0x3fff)
++#define EP_BREPEAT(p) (((p) & 0x7fff) << 16)
++
++static int is_fs_or_ls(enum usb_device_speed speed)
++{
++      return speed == USB_SPEED_FULL || speed == USB_SPEED_LOW;
++}
++
++/*
++* get the index of bandwidth domains array which @ep belongs to.
++*
++* the bandwidth domain array is saved to @sch_array of struct xhci_hcd_mtk,
++* each HS root port is treated as a single bandwidth domain,
++* but each SS root port is treated as two bandwidth domains, one for IN eps,
++* one for OUT eps.
++* @real_port value is defined as follow according to xHCI spec:
++* 1 for SSport0, ..., N+1 for SSportN, N+2 for HSport0, N+3 for HSport1, etc
++* so the bandwidth domain array is organized as follow for simplification:
++* SSport0-OUT, SSport0-IN, ..., SSportX-OUT, SSportX-IN, HSport0, ..., HSportY
++*/
++static int get_bw_index(struct xhci_hcd *xhci, struct usb_device *udev,
++      struct usb_host_endpoint *ep)
++{
++      struct xhci_virt_device *virt_dev;
++      int bw_index;
++
++      virt_dev = xhci->devs[udev->slot_id];
++
++      if (udev->speed == USB_SPEED_SUPER) {
++              if (usb_endpoint_dir_out(&ep->desc))
++                      bw_index = (virt_dev->real_port - 1) * 2;
++              else
++                      bw_index = (virt_dev->real_port - 1) * 2 + 1;
++      } else {
++              /* add one more for each SS port */
++              bw_index = virt_dev->real_port + xhci->num_usb3_ports - 1;
++      }
++
++      return bw_index;
++}
++
++static void setup_sch_info(struct usb_device *udev,
++              struct xhci_ep_ctx *ep_ctx, struct mu3h_sch_ep_info *sch_ep)
++{
++      u32 ep_type;
++      u32 ep_interval;
++      u32 max_packet_size;
++      u32 max_burst;
++      u32 mult;
++      u32 esit_pkts;
++
++      ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
++      ep_interval = CTX_TO_EP_INTERVAL(le32_to_cpu(ep_ctx->ep_info));
++      max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
++      max_burst = CTX_TO_MAX_BURST(le32_to_cpu(ep_ctx->ep_info2));
++      mult = CTX_TO_EP_MULT(le32_to_cpu(ep_ctx->ep_info));
++
++      sch_ep->esit = 1 << ep_interval;
++      sch_ep->offset = 0;
++      sch_ep->burst_mode = 0;
++
++      if (udev->speed == USB_SPEED_HIGH) {
++              sch_ep->cs_count = 0;
++
++              /*
++               * usb_20 spec section5.9
++               * a single microframe is enough for HS synchromous endpoints
++               * in a interval
++               */
++              sch_ep->num_budget_microframes = 1;
++              sch_ep->repeat = 0;
++
++              /*
++               * xHCI spec section6.2.3.4
++               * @max_burst is the number of additional transactions
++               * opportunities per microframe
++               */
++              sch_ep->pkts = max_burst + 1;
++              sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts;
++      } else if (udev->speed == USB_SPEED_SUPER) {
++              /* usb3_r1 spec section4.4.7 & 4.4.8 */
++              sch_ep->cs_count = 0;
++              esit_pkts = (mult + 1) * (max_burst + 1);
++              if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
++                      sch_ep->pkts = esit_pkts;
++                      sch_ep->num_budget_microframes = 1;
++                      sch_ep->repeat = 0;
++              }
++
++              if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) {
++                      if (esit_pkts <= sch_ep->esit)
++                              sch_ep->pkts = 1;
++                      else
++                              sch_ep->pkts = roundup_pow_of_two(esit_pkts)
++                                      / sch_ep->esit;
++
++                      sch_ep->num_budget_microframes =
++                              DIV_ROUND_UP(esit_pkts, sch_ep->pkts);
++
++                      if (sch_ep->num_budget_microframes > 1)
++                              sch_ep->repeat = 1;
++                      else
++                              sch_ep->repeat = 0;
++              }
++              sch_ep->bw_cost_per_microframe = max_packet_size * sch_ep->pkts;
++      } else if (is_fs_or_ls(udev->speed)) {
++
++              /*
++               * usb_20 spec section11.18.4
++               * assume worst cases
++               */
++              sch_ep->repeat = 0;
++              sch_ep->pkts = 1; /* at most one packet for each microframe */
++              if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
++                      sch_ep->cs_count = 3; /* at most need 3 CS*/
++                      /* one for SS and one for budgeted transaction */
++                      sch_ep->num_budget_microframes = sch_ep->cs_count + 2;
++                      sch_ep->bw_cost_per_microframe = max_packet_size;
++              }
++              if (ep_type == ISOC_OUT_EP) {
++
++                      /*
++                       * the best case FS budget assumes that 188 FS bytes
++                       * occur in each microframe
++                       */
++                      sch_ep->num_budget_microframes = DIV_ROUND_UP(
++                              max_packet_size, FS_PAYLOAD_MAX);
++                      sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX;
++                      sch_ep->cs_count = sch_ep->num_budget_microframes;
++              }
++              if (ep_type == ISOC_IN_EP) {
++                      /* at most need additional two CS. */
++                      sch_ep->cs_count = DIV_ROUND_UP(
++                              max_packet_size, FS_PAYLOAD_MAX) + 2;
++                      sch_ep->num_budget_microframes = sch_ep->cs_count + 2;
++                      sch_ep->bw_cost_per_microframe = FS_PAYLOAD_MAX;
++              }
++      }
++}
++
++/* Get maximum bandwidth when we schedule at offset slot. */
++static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw,
++      struct mu3h_sch_ep_info *sch_ep, u32 offset)
++{
++      u32 num_esit;
++      u32 max_bw = 0;
++      int i;
++      int j;
++
++      num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
++      for (i = 0; i < num_esit; i++) {
++              u32 base = offset + i * sch_ep->esit;
++
++              for (j = 0; j < sch_ep->num_budget_microframes; j++) {
++                      if (sch_bw->bus_bw[base + j] > max_bw)
++                              max_bw = sch_bw->bus_bw[base + j];
++              }
++      }
++      return max_bw;
++}
++
++static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
++      struct mu3h_sch_ep_info *sch_ep, int bw_cost)
++{
++      u32 num_esit;
++      u32 base;
++      int i;
++      int j;
++
++      num_esit = XHCI_MTK_MAX_ESIT / sch_ep->esit;
++      for (i = 0; i < num_esit; i++) {
++              base = sch_ep->offset + i * sch_ep->esit;
++              for (j = 0; j < sch_ep->num_budget_microframes; j++)
++                      sch_bw->bus_bw[base + j] += bw_cost;
++      }
++}
++
++static int check_sch_bw(struct usb_device *udev,
++      struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep)
++{
++      u32 offset;
++      u32 esit;
++      u32 num_budget_microframes;
++      u32 min_bw;
++      u32 min_index;
++      u32 worst_bw;
++      u32 bw_boundary;
++
++      if (sch_ep->esit > XHCI_MTK_MAX_ESIT)
++              sch_ep->esit = XHCI_MTK_MAX_ESIT;
++
++      esit = sch_ep->esit;
++      num_budget_microframes = sch_ep->num_budget_microframes;
++
++      /*
++       * Search through all possible schedule microframes.
++       * and find a microframe where its worst bandwidth is minimum.
++       */
++      min_bw = ~0;
++      min_index = 0;
++      for (offset = 0; offset < esit; offset++) {
++              if ((offset + num_budget_microframes) > sch_ep->esit)
++                      break;
++
++              /*
++               * usb_20 spec section11.18:
++               * must never schedule Start-Split in Y6
++               */
++              if (is_fs_or_ls(udev->speed) && (offset % 8 == 6))
++                      continue;
++
++              worst_bw = get_max_bw(sch_bw, sch_ep, offset);
++              if (min_bw > worst_bw) {
++                      min_bw = worst_bw;
++                      min_index = offset;
++              }
++              if (min_bw == 0)
++                      break;
++      }
++      sch_ep->offset = min_index;
++
++      bw_boundary = (udev->speed == USB_SPEED_SUPER)
++                              ? SS_BW_BOUNDARY : HS_BW_BOUNDARY;
++
++      /* check bandwidth */
++      if (min_bw + sch_ep->bw_cost_per_microframe > bw_boundary)
++              return -ERANGE;
++
++      /* update bus bandwidth info */
++      update_bus_bw(sch_bw, sch_ep, sch_ep->bw_cost_per_microframe);
++
++      return 0;
++}
++
++static bool need_bw_sch(struct usb_host_endpoint *ep,
++      enum usb_device_speed speed, int has_tt)
++{
++      /* only for periodic endpoints */
++      if (usb_endpoint_xfer_control(&ep->desc)
++              || usb_endpoint_xfer_bulk(&ep->desc))
++              return false;
++
++      /*
++       * for LS & FS periodic endpoints which its device don't attach
++       * to TT are also ignored, root-hub will schedule them directly
++       */
++      if (is_fs_or_ls(speed) && !has_tt)
++              return false;
++
++      return true;
++}
++
++int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk)
++{
++      struct mu3h_sch_bw_info *sch_array;
++      int num_usb_bus;
++      int i;
++
++      /* ss IN and OUT are separated */
++      num_usb_bus = mtk->num_u3_ports * 2 + mtk->num_u2_ports;
++
++      sch_array = kcalloc(num_usb_bus, sizeof(*sch_array), GFP_KERNEL);
++      if (sch_array == NULL)
++              return -ENOMEM;
++
++      for (i = 0; i < num_usb_bus; i++)
++              INIT_LIST_HEAD(&sch_array[i].bw_ep_list);
++
++      mtk->sch_array = sch_array;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(xhci_mtk_sch_init);
++
++void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk)
++{
++      kfree(mtk->sch_array);
++}
++EXPORT_SYMBOL_GPL(xhci_mtk_sch_exit);
++
++int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
++              struct usb_host_endpoint *ep)
++{
++      struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
++      struct xhci_hcd *xhci;
++      struct xhci_ep_ctx *ep_ctx;
++      struct xhci_slot_ctx *slot_ctx;
++      struct xhci_virt_device *virt_dev;
++      struct mu3h_sch_bw_info *sch_bw;
++      struct mu3h_sch_ep_info *sch_ep;
++      struct mu3h_sch_bw_info *sch_array;
++      unsigned int ep_index;
++      int bw_index;
++      int ret = 0;
++
++      xhci = hcd_to_xhci(hcd);
++      virt_dev = xhci->devs[udev->slot_id];
++      ep_index = xhci_get_endpoint_index(&ep->desc);
++      slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
++      ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
++      sch_array = mtk->sch_array;
++
++      xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n",
++              __func__, usb_endpoint_type(&ep->desc), udev->speed,
++              GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)),
++              usb_endpoint_dir_in(&ep->desc), ep);
++
++      if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT))
++              return 0;
++
++      bw_index = get_bw_index(xhci, udev, ep);
++      sch_bw = &sch_array[bw_index];
++
++      sch_ep = kzalloc(sizeof(struct mu3h_sch_ep_info), GFP_NOIO);
++      if (!sch_ep)
++              return -ENOMEM;
++
++      setup_sch_info(udev, ep_ctx, sch_ep);
++
++      ret = check_sch_bw(udev, sch_bw, sch_ep);
++      if (ret) {
++              xhci_err(xhci, "Not enough bandwidth!\n");
++              kfree(sch_ep);
++              return -ENOSPC;
++      }
++
++      list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list);
++      sch_ep->ep = ep;
++
++      ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts)
++              | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode));
++      ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset)
++              | EP_BREPEAT(sch_ep->repeat));
++
++      xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n",
++                      sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode,
++                      sch_ep->offset, sch_ep->repeat);
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk);
++
++void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
++              struct usb_host_endpoint *ep)
++{
++      struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
++      struct xhci_hcd *xhci;
++      struct xhci_slot_ctx *slot_ctx;
++      struct xhci_virt_device *virt_dev;
++      struct mu3h_sch_bw_info *sch_array;
++      struct mu3h_sch_bw_info *sch_bw;
++      struct mu3h_sch_ep_info *sch_ep;
++      int bw_index;
++
++      xhci = hcd_to_xhci(hcd);
++      virt_dev = xhci->devs[udev->slot_id];
++      slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
++      sch_array = mtk->sch_array;
++
++      xhci_dbg(xhci, "%s() type:%d, speed:%d, mpks:%d, dir:%d, ep:%p\n",
++              __func__, usb_endpoint_type(&ep->desc), udev->speed,
++              GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)),
++              usb_endpoint_dir_in(&ep->desc), ep);
++
++      if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT))
++              return;
++
++      bw_index = get_bw_index(xhci, udev, ep);
++      sch_bw = &sch_array[bw_index];
++
++      list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) {
++              if (sch_ep->ep == ep) {
++                      update_bus_bw(sch_bw, sch_ep,
++                              -sch_ep->bw_cost_per_microframe);
++                      list_del(&sch_ep->endpoint);
++                      kfree(sch_ep);
++                      break;
++              }
++      }
++}
++EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk);
+--- /dev/null
++++ b/drivers/usb/host/xhci-mtk.c
+@@ -0,0 +1,763 @@
++/*
++ * MediaTek xHCI Host Controller Driver
++ *
++ * Copyright (c) 2015 MediaTek Inc.
++ * Author:
++ *  Chunfeng Yun <chunfeng.yun@mediatek.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <linux/iopoll.h>
++#include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/regmap.h>
++#include <linux/regulator/consumer.h>
++
++#include "xhci.h"
++#include "xhci-mtk.h"
++
++/* ip_pw_ctrl0 register */
++#define CTRL0_IP_SW_RST       BIT(0)
++
++/* ip_pw_ctrl1 register */
++#define CTRL1_IP_HOST_PDN     BIT(0)
++
++/* ip_pw_ctrl2 register */
++#define CTRL2_IP_DEV_PDN      BIT(0)
++
++/* ip_pw_sts1 register */
++#define STS1_IP_SLEEP_STS     BIT(30)
++#define STS1_XHCI_RST         BIT(11)
++#define STS1_SYS125_RST       BIT(10)
++#define STS1_REF_RST          BIT(8)
++#define STS1_SYSPLL_STABLE    BIT(0)
++
++/* ip_xhci_cap register */
++#define CAP_U3_PORT_NUM(p)    ((p) & 0xff)
++#define CAP_U2_PORT_NUM(p)    (((p) >> 8) & 0xff)
++
++/* u3_ctrl_p register */
++#define CTRL_U3_PORT_HOST_SEL BIT(2)
++#define CTRL_U3_PORT_PDN      BIT(1)
++#define CTRL_U3_PORT_DIS      BIT(0)
++
++/* u2_ctrl_p register */
++#define CTRL_U2_PORT_HOST_SEL BIT(2)
++#define CTRL_U2_PORT_PDN      BIT(1)
++#define CTRL_U2_PORT_DIS      BIT(0)
++
++/* u2_phy_pll register */
++#define CTRL_U2_FORCE_PLL_STB BIT(28)
++
++#define PERI_WK_CTRL0         0x400
++#define UWK_CTR0_0P_LS_PE     BIT(8)  /* posedge */
++#define UWK_CTR0_0P_LS_NE     BIT(7)  /* negedge for 0p linestate*/
++#define UWK_CTL1_1P_LS_C(x)   (((x) & 0xf) << 1)
++#define UWK_CTL1_1P_LS_E      BIT(0)
++
++#define PERI_WK_CTRL1         0x404
++#define UWK_CTL1_IS_C(x)      (((x) & 0xf) << 26)
++#define UWK_CTL1_IS_E         BIT(25)
++#define UWK_CTL1_0P_LS_C(x)   (((x) & 0xf) << 21)
++#define UWK_CTL1_0P_LS_E      BIT(20)
++#define UWK_CTL1_IDDIG_C(x)   (((x) & 0xf) << 11)  /* cycle debounce */
++#define UWK_CTL1_IDDIG_E      BIT(10) /* enable debounce */
++#define UWK_CTL1_IDDIG_P      BIT(9)  /* polarity */
++#define UWK_CTL1_0P_LS_P      BIT(7)
++#define UWK_CTL1_IS_P         BIT(6)  /* polarity for ip sleep */
++
++enum ssusb_wakeup_src {
++      SSUSB_WK_IP_SLEEP = 1,
++      SSUSB_WK_LINE_STATE = 2,
++};
++
++static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
++{
++      struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
++      u32 value, check_val;
++      int ret;
++      int i;
++
++      /* power on host ip */
++      value = readl(&ippc->ip_pw_ctr1);
++      value &= ~CTRL1_IP_HOST_PDN;
++      writel(value, &ippc->ip_pw_ctr1);
++
++      /* power on and enable all u3 ports */
++      for (i = 0; i < mtk->num_u3_ports; i++) {
++              value = readl(&ippc->u3_ctrl_p[i]);
++              value &= ~(CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS);
++              value |= CTRL_U3_PORT_HOST_SEL;
++              writel(value, &ippc->u3_ctrl_p[i]);
++      }
++
++      /* power on and enable all u2 ports */
++      for (i = 0; i < mtk->num_u2_ports; i++) {
++              value = readl(&ippc->u2_ctrl_p[i]);
++              value &= ~(CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS);
++              value |= CTRL_U2_PORT_HOST_SEL;
++              writel(value, &ippc->u2_ctrl_p[i]);
++      }
++
++      /*
++       * wait for clocks to be stable, and clock domains reset to
++       * be inactive after power on and enable ports
++       */
++      check_val = STS1_SYSPLL_STABLE | STS1_REF_RST |
++                      STS1_SYS125_RST | STS1_XHCI_RST;
++
++      ret = readl_poll_timeout(&ippc->ip_pw_sts1, value,
++                        (check_val == (value & check_val)), 100, 20000);
++      if (ret) {
++              dev_err(mtk->dev, "clocks are not stable (0x%x)\n", value);
++              return ret;
++      }
++
++      return 0;
++}
++
++static int xhci_mtk_host_disable(struct xhci_hcd_mtk *mtk)
++{
++      struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
++      u32 value;
++      int ret;
++      int i;
++
++      /* power down all u3 ports */
++      for (i = 0; i < mtk->num_u3_ports; i++) {
++              value = readl(&ippc->u3_ctrl_p[i]);
++              value |= CTRL_U3_PORT_PDN;
++              writel(value, &ippc->u3_ctrl_p[i]);
++      }
++
++      /* power down all u2 ports */
++      for (i = 0; i < mtk->num_u2_ports; i++) {
++              value = readl(&ippc->u2_ctrl_p[i]);
++              value |= CTRL_U2_PORT_PDN;
++              writel(value, &ippc->u2_ctrl_p[i]);
++      }
++
++      /* power down host ip */
++      value = readl(&ippc->ip_pw_ctr1);
++      value |= CTRL1_IP_HOST_PDN;
++      writel(value, &ippc->ip_pw_ctr1);
++
++      /* wait for host ip to sleep */
++      ret = readl_poll_timeout(&ippc->ip_pw_sts1, value,
++                        (value & STS1_IP_SLEEP_STS), 100, 100000);
++      if (ret) {
++              dev_err(mtk->dev, "ip sleep failed!!!\n");
++              return ret;
++      }
++      return 0;
++}
++
++static int xhci_mtk_ssusb_config(struct xhci_hcd_mtk *mtk)
++{
++      struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
++      u32 value;
++
++      /* reset whole ip */
++      value = readl(&ippc->ip_pw_ctr0);
++      value |= CTRL0_IP_SW_RST;
++      writel(value, &ippc->ip_pw_ctr0);
++      udelay(1);
++      value = readl(&ippc->ip_pw_ctr0);
++      value &= ~CTRL0_IP_SW_RST;
++      writel(value, &ippc->ip_pw_ctr0);
++
++      /*
++       * device ip is default power-on in fact
++       * power down device ip, otherwise ip-sleep will fail
++       */
++      value = readl(&ippc->ip_pw_ctr2);
++      value |= CTRL2_IP_DEV_PDN;
++      writel(value, &ippc->ip_pw_ctr2);
++
++      value = readl(&ippc->ip_xhci_cap);
++      mtk->num_u3_ports = CAP_U3_PORT_NUM(value);
++      mtk->num_u2_ports = CAP_U2_PORT_NUM(value);
++      dev_dbg(mtk->dev, "%s u2p:%d, u3p:%d\n", __func__,
++                      mtk->num_u2_ports, mtk->num_u3_ports);
++
++      return xhci_mtk_host_enable(mtk);
++}
++
++static int xhci_mtk_clks_enable(struct xhci_hcd_mtk *mtk)
++{
++      int ret;
++
++      ret = clk_prepare_enable(mtk->sys_clk);
++      if (ret) {
++              dev_err(mtk->dev, "failed to enable sys_clk\n");
++              goto sys_clk_err;
++      }
++
++      if (mtk->wakeup_src) {
++              ret = clk_prepare_enable(mtk->wk_deb_p0);
++              if (ret) {
++                      dev_err(mtk->dev, "failed to enable wk_deb_p0\n");
++                      goto usb_p0_err;
++              }
++
++              ret = clk_prepare_enable(mtk->wk_deb_p1);
++              if (ret) {
++                      dev_err(mtk->dev, "failed to enable wk_deb_p1\n");
++                      goto usb_p1_err;
++              }
++      }
++      return 0;
++
++usb_p1_err:
++      clk_disable_unprepare(mtk->wk_deb_p0);
++usb_p0_err:
++      clk_disable_unprepare(mtk->sys_clk);
++sys_clk_err:
++      return -EINVAL;
++}
++
++static void xhci_mtk_clks_disable(struct xhci_hcd_mtk *mtk)
++{
++      if (mtk->wakeup_src) {
++              clk_disable_unprepare(mtk->wk_deb_p1);
++              clk_disable_unprepare(mtk->wk_deb_p0);
++      }
++      clk_disable_unprepare(mtk->sys_clk);
++}
++
++/* only clocks can be turn off for ip-sleep wakeup mode */
++static void usb_wakeup_ip_sleep_en(struct xhci_hcd_mtk *mtk)
++{
++      u32 tmp;
++      struct regmap *pericfg = mtk->pericfg;
++
++      regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
++      tmp &= ~UWK_CTL1_IS_P;
++      tmp &= ~(UWK_CTL1_IS_C(0xf));
++      tmp |= UWK_CTL1_IS_C(0x8);
++      regmap_write(pericfg, PERI_WK_CTRL1, tmp);
++      regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_IS_E);
++
++      regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
++      dev_dbg(mtk->dev, "%s(): WK_CTRL1[P6,E25,C26:29]=%#x\n",
++              __func__, tmp);
++}
++
++static void usb_wakeup_ip_sleep_dis(struct xhci_hcd_mtk *mtk)
++{
++      u32 tmp;
++
++      regmap_read(mtk->pericfg, PERI_WK_CTRL1, &tmp);
++      tmp &= ~UWK_CTL1_IS_E;
++      regmap_write(mtk->pericfg, PERI_WK_CTRL1, tmp);
++}
++
++/*
++* for line-state wakeup mode, phy's power should not power-down
++* and only support cable plug in/out
++*/
++static void usb_wakeup_line_state_en(struct xhci_hcd_mtk *mtk)
++{
++      u32 tmp;
++      struct regmap *pericfg = mtk->pericfg;
++
++      /* line-state of u2-port0 */
++      regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
++      tmp &= ~UWK_CTL1_0P_LS_P;
++      tmp &= ~(UWK_CTL1_0P_LS_C(0xf));
++      tmp |= UWK_CTL1_0P_LS_C(0x8);
++      regmap_write(pericfg, PERI_WK_CTRL1, tmp);
++      regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
++      regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_0P_LS_E);
++
++      /* line-state of u2-port1 */
++      regmap_read(pericfg, PERI_WK_CTRL0, &tmp);
++      tmp &= ~(UWK_CTL1_1P_LS_C(0xf));
++      tmp |= UWK_CTL1_1P_LS_C(0x8);
++      regmap_write(pericfg, PERI_WK_CTRL0, tmp);
++      regmap_write(pericfg, PERI_WK_CTRL0, tmp | UWK_CTL1_1P_LS_E);
++}
++
++static void usb_wakeup_line_state_dis(struct xhci_hcd_mtk *mtk)
++{
++      u32 tmp;
++      struct regmap *pericfg = mtk->pericfg;
++
++      /* line-state of u2-port0 */
++      regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
++      tmp &= ~UWK_CTL1_0P_LS_E;
++      regmap_write(pericfg, PERI_WK_CTRL1, tmp);
++
++      /* line-state of u2-port1 */
++      regmap_read(pericfg, PERI_WK_CTRL0, &tmp);
++      tmp &= ~UWK_CTL1_1P_LS_E;
++      regmap_write(pericfg, PERI_WK_CTRL0, tmp);
++}
++
++static void usb_wakeup_enable(struct xhci_hcd_mtk *mtk)
++{
++      if (mtk->wakeup_src == SSUSB_WK_IP_SLEEP)
++              usb_wakeup_ip_sleep_en(mtk);
++      else if (mtk->wakeup_src == SSUSB_WK_LINE_STATE)
++              usb_wakeup_line_state_en(mtk);
++}
++
++static void usb_wakeup_disable(struct xhci_hcd_mtk *mtk)
++{
++      if (mtk->wakeup_src == SSUSB_WK_IP_SLEEP)
++              usb_wakeup_ip_sleep_dis(mtk);
++      else if (mtk->wakeup_src == SSUSB_WK_LINE_STATE)
++              usb_wakeup_line_state_dis(mtk);
++}
++
++static int usb_wakeup_of_property_parse(struct xhci_hcd_mtk *mtk,
++                              struct device_node *dn)
++{
++      struct device *dev = mtk->dev;
++
++      /*
++      * wakeup function is optional, so it is not an error if this property
++      * does not exist, and in such case, no need to get relative
++      * properties anymore.
++      */
++      of_property_read_u32(dn, "mediatek,wakeup-src", &mtk->wakeup_src);
++      if (!mtk->wakeup_src)
++              return 0;
++
++      mtk->wk_deb_p0 = devm_clk_get(dev, "wakeup_deb_p0");
++      if (IS_ERR(mtk->wk_deb_p0)) {
++              dev_err(dev, "fail to get wakeup_deb_p0\n");
++              return PTR_ERR(mtk->wk_deb_p0);
++      }
++
++      mtk->wk_deb_p1 = devm_clk_get(dev, "wakeup_deb_p1");
++      if (IS_ERR(mtk->wk_deb_p1)) {
++              dev_err(dev, "fail to get wakeup_deb_p1\n");
++              return PTR_ERR(mtk->wk_deb_p1);
++      }
++
++      mtk->pericfg = syscon_regmap_lookup_by_phandle(dn,
++                                              "mediatek,syscon-wakeup");
++      if (IS_ERR(mtk->pericfg)) {
++              dev_err(dev, "fail to get pericfg regs\n");
++              return PTR_ERR(mtk->pericfg);
++      }
++
++      return 0;
++}
++
++static int xhci_mtk_setup(struct usb_hcd *hcd);
++static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = {
++      .extra_priv_size = sizeof(struct xhci_hcd),
++      .reset = xhci_mtk_setup,
++};
++
++static struct hc_driver __read_mostly xhci_mtk_hc_driver;
++
++static int xhci_mtk_phy_init(struct xhci_hcd_mtk *mtk)
++{
++      int i;
++      int ret;
++
++      for (i = 0; i < mtk->num_phys; i++) {
++              ret = phy_init(mtk->phys[i]);
++              if (ret)
++                      goto exit_phy;
++      }
++      return 0;
++
++exit_phy:
++      for (; i > 0; i--)
++              phy_exit(mtk->phys[i - 1]);
++
++      return ret;
++}
++
++static int xhci_mtk_phy_exit(struct xhci_hcd_mtk *mtk)
++{
++      int i;
++
++      for (i = 0; i < mtk->num_phys; i++)
++              phy_exit(mtk->phys[i]);
++
++      return 0;
++}
++
++static int xhci_mtk_phy_power_on(struct xhci_hcd_mtk *mtk)
++{
++      int i;
++      int ret;
++
++      for (i = 0; i < mtk->num_phys; i++) {
++              ret = phy_power_on(mtk->phys[i]);
++              if (ret)
++                      goto power_off_phy;
++      }
++      return 0;
++
++power_off_phy:
++      for (; i > 0; i--)
++              phy_power_off(mtk->phys[i - 1]);
++
++      return ret;
++}
++
++static void xhci_mtk_phy_power_off(struct xhci_hcd_mtk *mtk)
++{
++      unsigned int i;
++
++      for (i = 0; i < mtk->num_phys; i++)
++              phy_power_off(mtk->phys[i]);
++}
++
++static int xhci_mtk_ldos_enable(struct xhci_hcd_mtk *mtk)
++{
++      int ret;
++
++      ret = regulator_enable(mtk->vbus);
++      if (ret) {
++              dev_err(mtk->dev, "failed to enable vbus\n");
++              return ret;
++      }
++
++      ret = regulator_enable(mtk->vusb33);
++      if (ret) {
++              dev_err(mtk->dev, "failed to enable vusb33\n");
++              regulator_disable(mtk->vbus);
++              return ret;
++      }
++      return 0;
++}
++
++static void xhci_mtk_ldos_disable(struct xhci_hcd_mtk *mtk)
++{
++      regulator_disable(mtk->vbus);
++      regulator_disable(mtk->vusb33);
++}
++
++static void xhci_mtk_quirks(struct device *dev, struct xhci_hcd *xhci)
++{
++      struct usb_hcd *hcd = xhci_to_hcd(xhci);
++      struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
++
++      /*
++       * As of now platform drivers don't provide MSI support so we ensure
++       * here that the generic code does not try to make a pci_dev from our
++       * dev struct in order to setup MSI
++       */
++      xhci->quirks |= XHCI_PLAT;
++      xhci->quirks |= XHCI_MTK_HOST;
++      /*
++       * MTK host controller gives a spurious successful event after a
++       * short transfer. Ignore it.
++       */
++      xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
++      if (mtk->lpm_support)
++              xhci->quirks |= XHCI_LPM_SUPPORT;
++}
++
++/* called during probe() after chip reset completes */
++static int xhci_mtk_setup(struct usb_hcd *hcd)
++{
++      struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
++      int ret;
++
++      if (usb_hcd_is_primary_hcd(hcd)) {
++              ret = xhci_mtk_ssusb_config(mtk);
++              if (ret)
++                      return ret;
++              ret = xhci_mtk_sch_init(mtk);
++              if (ret)
++                      return ret;
++      }
++
++      return xhci_gen_setup(hcd, xhci_mtk_quirks);
++}
++
++static int xhci_mtk_probe(struct platform_device *pdev)
++{
++      struct device *dev = &pdev->dev;
++      struct device_node *node = dev->of_node;
++      struct xhci_hcd_mtk *mtk;
++      const struct hc_driver *driver;
++      struct xhci_hcd *xhci;
++      struct resource *res;
++      struct usb_hcd *hcd;
++      struct phy *phy;
++      int phy_num;
++      int ret = -ENODEV;
++      int irq;
++
++      if (usb_disabled())
++              return -ENODEV;
++
++      driver = &xhci_mtk_hc_driver;
++      mtk = devm_kzalloc(dev, sizeof(*mtk), GFP_KERNEL);
++      if (!mtk)
++              return -ENOMEM;
++
++      mtk->dev = dev;
++      mtk->vbus = devm_regulator_get(dev, "vbus");
++      if (IS_ERR(mtk->vbus)) {
++              dev_err(dev, "fail to get vbus\n");
++              return PTR_ERR(mtk->vbus);
++      }
++
++      mtk->vusb33 = devm_regulator_get(dev, "vusb33");
++      if (IS_ERR(mtk->vusb33)) {
++              dev_err(dev, "fail to get vusb33\n");
++              return PTR_ERR(mtk->vusb33);
++      }
++
++      mtk->sys_clk = devm_clk_get(dev, "sys_ck");
++      if (IS_ERR(mtk->sys_clk)) {
++              dev_err(dev, "fail to get sys_ck\n");
++              return PTR_ERR(mtk->sys_clk);
++      }
++
++      mtk->lpm_support = of_property_read_bool(node, "usb3-lpm-capable");
++
++      ret = usb_wakeup_of_property_parse(mtk, node);
++      if (ret)
++              return ret;
++
++      mtk->num_phys = of_count_phandle_with_args(node,
++                      "phys", "#phy-cells");
++      if (mtk->num_phys > 0) {
++              mtk->phys = devm_kcalloc(dev, mtk->num_phys,
++                                      sizeof(*mtk->phys), GFP_KERNEL);
++              if (!mtk->phys)
++                      return -ENOMEM;
++      } else {
++              mtk->num_phys = 0;
++      }
++      pm_runtime_enable(dev);
++      pm_runtime_get_sync(dev);
++      device_enable_async_suspend(dev);
++
++      ret = xhci_mtk_ldos_enable(mtk);
++      if (ret)
++              goto disable_pm;
++
++      ret = xhci_mtk_clks_enable(mtk);
++      if (ret)
++              goto disable_ldos;
++
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0)
++              goto disable_clk;
++
++      /* Initialize dma_mask and coherent_dma_mask to 32-bits */
++      ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
++      if (ret)
++              goto disable_clk;
++
++      if (!dev->dma_mask)
++              dev->dma_mask = &dev->coherent_dma_mask;
++      else
++              dma_set_mask(dev, DMA_BIT_MASK(32));
++
++      hcd = usb_create_hcd(driver, dev, dev_name(dev));
++      if (!hcd) {
++              ret = -ENOMEM;
++              goto disable_clk;
++      }
++
++      /*
++       * USB 2.0 roothub is stored in the platform_device.
++       * Swap it with mtk HCD.
++       */
++      mtk->hcd = platform_get_drvdata(pdev);
++      platform_set_drvdata(pdev, mtk);
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      hcd->regs = devm_ioremap_resource(dev, res);
++      if (IS_ERR(hcd->regs)) {
++              ret = PTR_ERR(hcd->regs);
++              goto put_usb2_hcd;
++      }
++      hcd->rsrc_start = res->start;
++      hcd->rsrc_len = resource_size(res);
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++      mtk->ippc_regs = devm_ioremap_resource(dev, res);
++      if (IS_ERR(mtk->ippc_regs)) {
++              ret = PTR_ERR(mtk->ippc_regs);
++              goto put_usb2_hcd;
++      }
++
++      for (phy_num = 0; phy_num < mtk->num_phys; phy_num++) {
++              phy = devm_of_phy_get_by_index(dev, node, phy_num);
++              if (IS_ERR(phy)) {
++                      ret = PTR_ERR(phy);
++                      goto put_usb2_hcd;
++              }
++              mtk->phys[phy_num] = phy;
++      }
++
++      ret = xhci_mtk_phy_init(mtk);
++      if (ret)
++              goto put_usb2_hcd;
++
++      ret = xhci_mtk_phy_power_on(mtk);
++      if (ret)
++              goto exit_phys;
++
++      device_init_wakeup(dev, true);
++
++      xhci = hcd_to_xhci(hcd);
++      xhci->main_hcd = hcd;
++      xhci->shared_hcd = usb_create_shared_hcd(driver, dev,
++                      dev_name(dev), hcd);
++      if (!xhci->shared_hcd) {
++              ret = -ENOMEM;
++              goto power_off_phys;
++      }
++
++      if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
++              xhci->shared_hcd->can_do_streams = 1;
++
++      ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
++      if (ret)
++              goto put_usb3_hcd;
++
++      ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
++      if (ret)
++              goto dealloc_usb2_hcd;
++
++      return 0;
++
++dealloc_usb2_hcd:
++      usb_remove_hcd(hcd);
++
++put_usb3_hcd:
++      xhci_mtk_sch_exit(mtk);
++      usb_put_hcd(xhci->shared_hcd);
++
++power_off_phys:
++      xhci_mtk_phy_power_off(mtk);
++      device_init_wakeup(dev, false);
++
++exit_phys:
++      xhci_mtk_phy_exit(mtk);
++
++put_usb2_hcd:
++      usb_put_hcd(hcd);
++
++disable_clk:
++      xhci_mtk_clks_disable(mtk);
++
++disable_ldos:
++      xhci_mtk_ldos_disable(mtk);
++
++disable_pm:
++      pm_runtime_put_sync(dev);
++      pm_runtime_disable(dev);
++      return ret;
++}
++
++static int xhci_mtk_remove(struct platform_device *dev)
++{
++      struct xhci_hcd_mtk *mtk = platform_get_drvdata(dev);
++      struct usb_hcd  *hcd = mtk->hcd;
++      struct xhci_hcd *xhci = hcd_to_xhci(hcd);
++
++      usb_remove_hcd(xhci->shared_hcd);
++      xhci_mtk_phy_power_off(mtk);
++      xhci_mtk_phy_exit(mtk);
++      device_init_wakeup(&dev->dev, false);
++
++      usb_remove_hcd(hcd);
++      usb_put_hcd(xhci->shared_hcd);
++      usb_put_hcd(hcd);
++      xhci_mtk_sch_exit(mtk);
++      xhci_mtk_clks_disable(mtk);
++      xhci_mtk_ldos_disable(mtk);
++      pm_runtime_put_sync(&dev->dev);
++      pm_runtime_disable(&dev->dev);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM_SLEEP
++static int xhci_mtk_suspend(struct device *dev)
++{
++      struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
++
++      xhci_mtk_host_disable(mtk);
++      xhci_mtk_phy_power_off(mtk);
++      xhci_mtk_clks_disable(mtk);
++      usb_wakeup_enable(mtk);
++      return 0;
++}
++
++static int xhci_mtk_resume(struct device *dev)
++{
++      struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
++
++      usb_wakeup_disable(mtk);
++      xhci_mtk_clks_enable(mtk);
++      xhci_mtk_phy_power_on(mtk);
++      xhci_mtk_host_enable(mtk);
++      return 0;
++}
++
++static const struct dev_pm_ops xhci_mtk_pm_ops = {
++      SET_SYSTEM_SLEEP_PM_OPS(xhci_mtk_suspend, xhci_mtk_resume)
++};
++#define DEV_PM_OPS    (&xhci_mtk_pm_ops)
++#else
++#define DEV_PM_OPS    NULL
++#endif /* CONFIG_PM */
++
++#ifdef CONFIG_OF
++static const struct of_device_id mtk_xhci_of_match[] = {
++      { .compatible = "mediatek,mt8173-xhci"},
++      { },
++};
++MODULE_DEVICE_TABLE(of, mtk_xhci_of_match);
++#endif
++
++static struct platform_driver mtk_xhci_driver = {
++      .probe  = xhci_mtk_probe,
++      .remove = xhci_mtk_remove,
++      .driver = {
++              .name = "xhci-mtk",
++              .pm = DEV_PM_OPS,
++              .of_match_table = of_match_ptr(mtk_xhci_of_match),
++      },
++};
++MODULE_ALIAS("platform:xhci-mtk");
++
++static int __init xhci_mtk_init(void)
++{
++      xhci_init_driver(&xhci_mtk_hc_driver, &xhci_mtk_overrides);
++      return platform_driver_register(&mtk_xhci_driver);
++}
++module_init(xhci_mtk_init);
++
++static void __exit xhci_mtk_exit(void)
++{
++      platform_driver_unregister(&mtk_xhci_driver);
++}
++module_exit(xhci_mtk_exit);
++
++MODULE_AUTHOR("Chunfeng Yun <chunfeng.yun@mediatek.com>");
++MODULE_DESCRIPTION("MediaTek xHCI Host Controller Driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/drivers/usb/host/xhci-mtk.h
+@@ -0,0 +1,162 @@
++/*
++ * Copyright (c) 2015 MediaTek Inc.
++ * Author:
++ *  Zhigang.Wei <zhigang.wei@mediatek.com>
++ *  Chunfeng.Yun <chunfeng.yun@mediatek.com>
++ *
++ * This software is licensed under the terms of the GNU General Public
++ * License version 2, as published by the Free Software Foundation, and
++ * may be copied, distributed, and modified under those terms.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef _XHCI_MTK_H_
++#define _XHCI_MTK_H_
++
++#include "xhci.h"
++
++/**
++ * To simplify scheduler algorithm, set a upper limit for ESIT,
++ * if a synchromous ep's ESIT is larger than @XHCI_MTK_MAX_ESIT,
++ * round down to the limit value, that means allocating more
++ * bandwidth to it.
++ */
++#define XHCI_MTK_MAX_ESIT     64
++
++/**
++ * struct mu3h_sch_bw_info: schedule information for bandwidth domain
++ *
++ * @bus_bw: array to keep track of bandwidth already used at each uframes
++ * @bw_ep_list: eps in the bandwidth domain
++ *
++ * treat a HS root port as a bandwidth domain, but treat a SS root port as
++ * two bandwidth domains, one for IN eps and another for OUT eps.
++ */
++struct mu3h_sch_bw_info {
++      u32 bus_bw[XHCI_MTK_MAX_ESIT];
++      struct list_head bw_ep_list;
++};
++
++/**
++ * struct mu3h_sch_ep_info: schedule information for endpoint
++ *
++ * @esit: unit is 125us, equal to 2 << Interval field in ep-context
++ * @num_budget_microframes: number of continuous uframes
++ *            (@repeat==1) scheduled within the interval
++ * @bw_cost_per_microframe: bandwidth cost per microframe
++ * @endpoint: linked into bandwidth domain which it belongs to
++ * @ep: address of usb_host_endpoint struct
++ * @offset: which uframe of the interval that transfer should be
++ *            scheduled first time within the interval
++ * @repeat: the time gap between two uframes that transfers are
++ *            scheduled within a interval. in the simple algorithm, only
++ *            assign 0 or 1 to it; 0 means using only one uframe in a
++ *            interval, and 1 means using @num_budget_microframes
++ *            continuous uframes
++ * @pkts: number of packets to be transferred in the scheduled uframes
++ * @cs_count: number of CS that host will trigger
++ * @burst_mode: burst mode for scheduling. 0: normal burst mode,
++ *            distribute the bMaxBurst+1 packets for a single burst
++ *            according to @pkts and @repeat, repeate the burst multiple
++ *            times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets
++ *            according to @pkts and @repeat. normal mode is used by
++ *            default
++ */
++struct mu3h_sch_ep_info {
++      u32 esit;
++      u32 num_budget_microframes;
++      u32 bw_cost_per_microframe;
++      struct list_head endpoint;
++      void *ep;
++      /*
++       * mtk xHCI scheduling information put into reserved DWs
++       * in ep context
++       */
++      u32 offset;
++      u32 repeat;
++      u32 pkts;
++      u32 cs_count;
++      u32 burst_mode;
++};
++
++#define MU3C_U3_PORT_MAX 4
++#define MU3C_U2_PORT_MAX 5
++
++/**
++ * struct mu3c_ippc_regs: MTK ssusb ip port control registers
++ * @ip_pw_ctr0~3: ip power and clock control registers
++ * @ip_pw_sts1~2: ip power and clock status registers
++ * @ip_xhci_cap: ip xHCI capability register
++ * @u3_ctrl_p[x]: ip usb3 port x control register, only low 4bytes are used
++ * @u2_ctrl_p[x]: ip usb2 port x control register, only low 4bytes are used
++ * @u2_phy_pll: usb2 phy pll control register
++ */
++struct mu3c_ippc_regs {
++      __le32 ip_pw_ctr0;
++      __le32 ip_pw_ctr1;
++      __le32 ip_pw_ctr2;
++      __le32 ip_pw_ctr3;
++      __le32 ip_pw_sts1;
++      __le32 ip_pw_sts2;
++      __le32 reserved0[3];
++      __le32 ip_xhci_cap;
++      __le32 reserved1[2];
++      __le64 u3_ctrl_p[MU3C_U3_PORT_MAX];
++      __le64 u2_ctrl_p[MU3C_U2_PORT_MAX];
++      __le32 reserved2;
++      __le32 u2_phy_pll;
++      __le32 reserved3[33]; /* 0x80 ~ 0xff */
++};
++
++struct xhci_hcd_mtk {
++      struct device *dev;
++      struct usb_hcd *hcd;
++      struct mu3h_sch_bw_info *sch_array;
++      struct mu3c_ippc_regs __iomem *ippc_regs;
++      int num_u2_ports;
++      int num_u3_ports;
++      struct regulator *vusb33;
++      struct regulator *vbus;
++      struct clk *sys_clk;    /* sys and mac clock */
++      struct clk *wk_deb_p0;  /* port0's wakeup debounce clock */
++      struct clk *wk_deb_p1;
++      struct regmap *pericfg;
++      struct phy **phys;
++      int num_phys;
++      int wakeup_src;
++      bool lpm_support;
++};
++
++static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)
++{
++      return dev_get_drvdata(hcd->self.controller);
++}
++
++#if IS_ENABLED(CONFIG_USB_XHCI_MTK)
++int xhci_mtk_sch_init(struct xhci_hcd_mtk *mtk);
++void xhci_mtk_sch_exit(struct xhci_hcd_mtk *mtk);
++int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
++              struct usb_host_endpoint *ep);
++void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
++              struct usb_host_endpoint *ep);
++
++#else
++static inline int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd,
++      struct usb_device *udev, struct usb_host_endpoint *ep)
++{
++      return 0;
++}
++
++static inline void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd,
++      struct usb_device *udev, struct usb_host_endpoint *ep)
++{
++}
++
++#endif
++
++#endif                /* _XHCI_MTK_H_ */
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -68,6 +68,7 @@
+ #include <linux/slab.h>
+ #include "xhci.h"
+ #include "xhci-trace.h"
++#include "xhci-mtk.h"
+ /*
+  * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
+@@ -3065,17 +3066,22 @@ static u32 xhci_td_remainder(struct xhci
+ {
+       u32 maxp, total_packet_count;
+-      if (xhci->hci_version < 0x100)
++      /* MTK xHCI is mostly 0.97 but contains some features from 1.0 */
++      if (xhci->hci_version < 0x100 && !(xhci->quirks & XHCI_MTK_HOST))
+               return ((td_total_len - transferred) >> 10);
+-      maxp = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
+-      total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
+-
+       /* One TRB with a zero-length data packet. */
+       if (num_trbs_left == 0 || (transferred == 0 && trb_buff_len == 0) ||
+           trb_buff_len == td_total_len)
+               return 0;
++      /* for MTK xHCI, TD size doesn't include this TRB */
++      if (xhci->quirks & XHCI_MTK_HOST)
++              trb_buff_len = 0;
++
++      maxp = GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
++      total_packet_count = DIV_ROUND_UP(td_total_len, maxp);
++
+       /* Queueing functions don't count the current TRB into transferred */
+       return (total_packet_count - ((transferred + trb_buff_len) / maxp));
+ }
+@@ -3463,7 +3469,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *
+               field |= 0x1;
+       /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
+-      if (xhci->hci_version >= 0x100) {
++      if ((xhci->hci_version >= 0x100) || (xhci->quirks & XHCI_MTK_HOST)) {
+               if (urb->transfer_buffer_length > 0) {
+                       if (setup->bRequestType & USB_DIR_IN)
+                               field |= TRB_TX_TYPE(TRB_DATA_IN);
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -31,6 +31,7 @@
+ #include "xhci.h"
+ #include "xhci-trace.h"
++#include "xhci-mtk.h"
+ #define DRIVER_AUTHOR "Sarah Sharp"
+ #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
+@@ -634,7 +635,11 @@ int xhci_run(struct usb_hcd *hcd)
+                       "// Set the interrupt modulation register");
+       temp = readl(&xhci->ir_set->irq_control);
+       temp &= ~ER_IRQ_INTERVAL_MASK;
+-      temp |= (u32) 160;
++      /*
++       * the increment interval is 8 times as much as that defined
++       * in xHCI spec on MTK's controller
++       */
++      temp |= (u32) ((xhci->quirks & XHCI_MTK_HOST) ? 20 : 160);
+       writel(temp, &xhci->ir_set->irq_control);
+       /* Set the HCD state before we enable the irqs */
+@@ -1700,6 +1705,9 @@ int xhci_drop_endpoint(struct usb_hcd *h
+       xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
++      if (xhci->quirks & XHCI_MTK_HOST)
++              xhci_mtk_drop_ep_quirk(hcd, udev, ep);
++
+       xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
+                       (unsigned int) ep->desc.bEndpointAddress,
+                       udev->slot_id,
+@@ -1795,6 +1803,15 @@ int xhci_add_endpoint(struct usb_hcd *hc
+               return -ENOMEM;
+       }
++      if (xhci->quirks & XHCI_MTK_HOST) {
++              ret = xhci_mtk_add_ep_quirk(hcd, udev, ep);
++              if (ret < 0) {
++                      xhci_free_or_cache_endpoint_ring(xhci,
++                              virt_dev, ep_index);
++                      return ret;
++              }
++      }
++
+       ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
+       new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1630,6 +1630,7 @@ struct xhci_hcd {
+ /* For controllers with a broken beyond repair streams implementation */
+ #define XHCI_BROKEN_STREAMS   (1 << 19)
+ #define XHCI_PME_STUCK_QUIRK  (1 << 20)
++#define XHCI_MTK_HOST         (1 << 21)
+       unsigned int            num_active_eps;
+       unsigned int            limit_active_eps;
+       /* There are two roothubs to keep track of bus suspend info for */
diff --git a/target/linux/ramips/patches-4.4/0034-NET-multi-phy-support.patch b/target/linux/ramips/patches-4.4/0034-NET-multi-phy-support.patch
new file mode 100644 (file)
index 0000000..2c3807d
--- /dev/null
@@ -0,0 +1,53 @@
+From 0b6eb1e68290243d439ee330ea8d0b239a5aec69 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 27 Jul 2014 09:38:50 +0100
+Subject: [PATCH 34/53] NET: multi phy support
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/phy/phy.c |    9 ++++++---
+ include/linux/phy.h   |    1 +
+ 2 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -888,7 +888,8 @@ void phy_state_machine(struct work_struc
+               /* If the link is down, give up on negotiation for now */
+               if (!phydev->link) {
+                       phydev->state = PHY_NOLINK;
+-                      netif_carrier_off(phydev->attached_dev);
++                      if (!phydev->no_auto_carrier_off)
++                              netif_carrier_off(phydev->attached_dev);
+                       phydev->adjust_link(phydev->attached_dev);
+                       break;
+               }
+@@ -971,7 +972,8 @@ void phy_state_machine(struct work_struc
+                       netif_carrier_on(phydev->attached_dev);
+               } else {
+                       phydev->state = PHY_NOLINK;
+-                      netif_carrier_off(phydev->attached_dev);
++                      if (!phydev->no_auto_carrier_off)
++                              netif_carrier_off(phydev->attached_dev);
+               }
+               phydev->adjust_link(phydev->attached_dev);
+@@ -983,7 +985,8 @@ void phy_state_machine(struct work_struc
+       case PHY_HALTED:
+               if (phydev->link) {
+                       phydev->link = 0;
+-                      netif_carrier_off(phydev->attached_dev);
++                      if (!phydev->no_auto_carrier_off)
++                              netif_carrier_off(phydev->attached_dev);
+                       phydev->adjust_link(phydev->attached_dev);
+                       do_suspend = true;
+               }
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -377,6 +377,7 @@ struct phy_device {
+       bool is_pseudo_fixed_link;
+       bool has_fixups;
+       bool suspended;
++      bool no_auto_carrier_off;
+       enum phy_state state;
diff --git a/target/linux/ramips/patches-4.4/0036-mtd-fix-cfi-cmdset-0002-erase-status-check.patch b/target/linux/ramips/patches-4.4/0036-mtd-fix-cfi-cmdset-0002-erase-status-check.patch
new file mode 100644 (file)
index 0000000..b6189fe
--- /dev/null
@@ -0,0 +1,29 @@
+From 8e72a3a1be8f6328bd7ef491332ba541547b6086 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 15 Jul 2013 00:38:51 +0200
+Subject: [PATCH 36/53] mtd: fix cfi cmdset 0002 erase status check
+
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -2291,7 +2291,7 @@ static int __xipram do_erase_chip(struct
+                       chip->erase_suspended = 0;
+               }
+-              if (chip_ready(map, adr))
++              if (chip_good(map, adr, map_word_ff(map)))
+                       break;
+               if (time_after(jiffies, timeo)) {
+@@ -2380,7 +2380,7 @@ static int __xipram do_erase_oneblock(st
+                       chip->erase_suspended = 0;
+               }
+-              if (chip_ready(map, adr)) {
++              if (chip_good(map, adr, map_word_ff(map))) {
+                       xip_enable(map, chip, adr);
+                       break;
+               }
diff --git a/target/linux/ramips/patches-4.4/0037-mtd-cfi-cmdset-0002-force-word-write.patch b/target/linux/ramips/patches-4.4/0037-mtd-cfi-cmdset-0002-force-word-write.patch
new file mode 100644 (file)
index 0000000..8f274bc
--- /dev/null
@@ -0,0 +1,70 @@
+From ee9081b2726a5ca8cde5497afdc5425e21ff8f8b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 15 Jul 2013 00:39:21 +0200
+Subject: [PATCH 37/53] mtd: cfi cmdset 0002 force word write
+
+---
+ drivers/mtd/chips/cfi_cmdset_0002.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/chips/cfi_cmdset_0002.c
++++ b/drivers/mtd/chips/cfi_cmdset_0002.c
+@@ -40,7 +40,7 @@
+ #include <linux/mtd/xip.h>
+ #define AMD_BOOTLOC_BUG
+-#define FORCE_WORD_WRITE 0
++#define FORCE_WORD_WRITE 1
+ #define MAX_WORD_RETRIES 3
+@@ -51,7 +51,9 @@
+ static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+ static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
++#if !FORCE_WORD_WRITE
+ static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
++#endif
+ static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
+ static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
+ static void cfi_amdstd_sync (struct mtd_info *);
+@@ -202,6 +204,7 @@ static void fixup_amd_bootblock(struct m
+ }
+ #endif
++#if !FORCE_WORD_WRITE
+ static void fixup_use_write_buffers(struct mtd_info *mtd)
+ {
+       struct map_info *map = mtd->priv;
+@@ -211,6 +214,7 @@ static void fixup_use_write_buffers(stru
+               mtd->_write = cfi_amdstd_write_buffers;
+       }
+ }
++#endif /* !FORCE_WORD_WRITE */
+ /* Atmel chips don't use the same PRI format as AMD chips */
+ static void fixup_convert_atmel_pri(struct mtd_info *mtd)
+@@ -1789,6 +1793,7 @@ static int cfi_amdstd_write_words(struct
+ /*
+  * FIXME: interleaved mode not tested, and probably not supported!
+  */
++#if !FORCE_WORD_WRITE
+ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
+                                   unsigned long adr, const u_char *buf,
+                                   int len)
+@@ -1917,7 +1922,6 @@ static int __xipram do_write_buffer(stru
+       return ret;
+ }
+-
+ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
+                                   size_t *retlen, const u_char *buf)
+ {
+@@ -1992,6 +1996,7 @@ static int cfi_amdstd_write_buffers(stru
+       return 0;
+ }
++#endif /* !FORCE_WORD_WRITE */
+ /*
+  * Wait for the flash chip to become ready to write data
diff --git a/target/linux/ramips/patches-4.4/0038-mtd-ralink-add-mt7620-nand-driver.patch b/target/linux/ramips/patches-4.4/0038-mtd-ralink-add-mt7620-nand-driver.patch
new file mode 100644 (file)
index 0000000..0bf9043
--- /dev/null
@@ -0,0 +1,2408 @@
+From fb6e1578cd73d7d81f675e75247a676423f32412 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 17 Nov 2013 17:41:46 +0100
+Subject: [PATCH 38/53] mtd: ralink: add mt7620 nand driver
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/mtd/maps/Kconfig       |    4 +
+ drivers/mtd/maps/Makefile      |    2 +
+ drivers/mtd/maps/ralink_nand.c | 2136 ++++++++++++++++++++++++++++++++++++++++
+ drivers/mtd/maps/ralink_nand.h |  232 +++++
+ 4 files changed, 2374 insertions(+)
+ create mode 100644 drivers/mtd/maps/ralink_nand.c
+ create mode 100644 drivers/mtd/maps/ralink_nand.h
+
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -399,4 +399,8 @@ config MTD_LATCH_ADDR
+           If compiled as a module, it will be called latch-addr-flash.
++config MTD_NAND_MT7620
++      tristate "Support for NAND on Mediatek MT7620"
++      depends on RALINK && SOC_MT7620
++
+ endmenu
+--- a/drivers/mtd/maps/Makefile
++++ b/drivers/mtd/maps/Makefile
+@@ -43,3 +43,5 @@ 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_NAND_MT7620) += ralink_nand.o
++
+--- /dev/null
++++ b/drivers/mtd/maps/ralink_nand.c
+@@ -0,0 +1,2136 @@
++#define DEBUG
++#include <linux/device.h>
++#undef DEBUG
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/mtd/partitions.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++
++#include "ralink_nand.h"
++#ifdef RANDOM_GEN_BAD_BLOCK
++#include <linux/random.h>
++#endif
++
++#define LARGE_MTD_BOOT_PART_SIZE       (CFG_BLOCKSIZE<<2)
++#define LARGE_MTD_CONFIG_PART_SIZE     (CFG_BLOCKSIZE<<2)
++#define LARGE_MTD_FACTORY_PART_SIZE    (CFG_BLOCKSIZE<<1)
++
++
++#define BLOCK_ALIGNED(a) ((a) & (CFG_BLOCKSIZE - 1))
++
++#define READ_STATUS_RETRY     1000
++
++struct mtd_info *ranfc_mtd = NULL;
++
++int skipbbt = 0;
++int ranfc_debug = 1;
++static int ranfc_bbt = 1;
++#if defined (WORKAROUND_RX_BUF_OV)
++static int ranfc_verify = 1;
++#endif
++static u32 nand_addrlen;
++
++#if 0
++module_param(ranfc_debug, int, 0644);
++module_param(ranfc_bbt, int, 0644);
++module_param(ranfc_verify, int, 0644);
++#endif
++
++#if 0
++#define ra_dbg(args...) do { if (ranfc_debug) printk(args); } while(0)
++#else
++#define ra_dbg(args...)
++#endif
++
++#define CLEAR_INT_STATUS()    ra_outl(NFC_INT_ST, ra_inl(NFC_INT_ST))
++#define NFC_TRANS_DONE()      (ra_inl(NFC_INT_ST) & INT_ST_ND_DONE)
++
++int is_nand_page_2048 = 0;
++const unsigned int nand_size_map[2][3] = {{25, 30, 30}, {20, 27, 30}};
++
++static int nfc_wait_ready(int snooze_ms);
++
++static const char * const mtk_probe_types[] = { "cmdlinepart", "ofpart", NULL };
++
++/**
++ * reset nand chip
++ */
++static int nfc_chip_reset(void)
++{
++      int status;
++
++      //ra_dbg("%s:\n", __func__);
++
++      // reset nand flash
++      ra_outl(NFC_CMD1, 0x0);
++      ra_outl(NFC_CMD2, 0xff);
++      ra_outl(NFC_ADDR, 0x0);
++      ra_outl(NFC_CONF, 0x0411);
++
++      status = nfc_wait_ready(5);  //erase wait 5us
++      if (status & NAND_STATUS_FAIL) {
++              printk("%s: fail \n", __func__);
++      }
++      
++      return (int)(status & NAND_STATUS_FAIL);
++
++}
++
++
++
++/** 
++ * clear NFC and flash chip.
++ */
++static int nfc_all_reset(void)
++{
++      int retry;
++
++      ra_dbg("%s: \n", __func__);
++
++      // reset controller
++      ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
++      ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
++
++      CLEAR_INT_STATUS();
++
++      retry = READ_STATUS_RETRY;
++      while ((ra_inl(NFC_INT_ST) & 0x02) != 0x02 && retry--);
++      if (retry <= 0) {
++              printk("nfc_all_reset: clean buffer fail \n");
++              return -1;
++      }
++
++      retry = READ_STATUS_RETRY;
++      while ((ra_inl(NFC_STATUS) & 0x1) != 0x0 && retry--) { //fixme, controller is busy ?
++              udelay(1);
++      }
++
++      nfc_chip_reset();
++
++      return 0;
++}
++
++/** NOTICE: only called by nfc_wait_ready().
++ * @return -1, nfc can not get transction done 
++ * @return 0, ok.
++ */
++static int _nfc_read_status(char *status)
++{
++      unsigned long cmd1, conf;
++      int int_st, nfc_st;
++      int retry;
++
++      cmd1 = 0x70;
++      conf = 0x000101 | (1 << 20);
++
++      //fixme, should we check nfc status?
++      CLEAR_INT_STATUS();
++
++      ra_outl(NFC_CMD1, cmd1);        
++      ra_outl(NFC_CONF, conf); 
++
++      /* FIXME, 
++       * 1. since we have no wired ready signal, directly 
++       * calling this function is not gurantee to read right status under ready state.
++       * 2. the other side, we can not determine how long to become ready, this timeout retry is nonsense.
++       * 3. SUGGESTION: call nfc_read_status() from nfc_wait_ready(),
++       * that is aware about caller (in sementics) and has snooze plused nfc ND_DONE.
++       */
++      retry = READ_STATUS_RETRY; 
++      do {
++              nfc_st = ra_inl(NFC_STATUS);
++              int_st = ra_inl(NFC_INT_ST);
++              
++              ndelay(10);
++      } while (!(int_st & INT_ST_RX_BUF_RDY) && retry--);
++
++      if (!(int_st & INT_ST_RX_BUF_RDY)) {
++              printk("nfc_read_status: NFC fail, int_st(%x), retry:%x. nfc:%x, reset nfc and flash. \n", 
++                     int_st, retry, nfc_st);
++              nfc_all_reset();
++              *status = NAND_STATUS_FAIL;
++              return -1;
++      }
++
++      *status = (char)(le32_to_cpu(ra_inl(NFC_DATA)) & 0x0ff);
++      return 0;
++}
++
++/**
++ * @return !0, chip protect.
++ * @return 0, chip not protected.
++ */
++static int nfc_check_wp(void)
++{
++      /* Check the WP bit */
++#if !defined CONFIG_NOT_SUPPORT_WP
++      return !!(ra_inl(NFC_CTRL) & 0x01);
++#else
++      char result = 0;
++      int ret;
++
++      ret = _nfc_read_status(&result);
++      //FIXME, if ret < 0
++
++      return !(result & NAND_STATUS_WP);
++#endif
++}
++
++#if !defined CONFIG_NOT_SUPPORT_RB
++/*
++ * @return !0, chip ready.
++ * @return 0, chip busy.
++ */
++static int nfc_device_ready(void)
++{
++      /* Check the ready  */
++      return !!(ra_inl(NFC_STATUS) & 0x04);
++}
++#endif
++
++
++/**
++ * generic function to get data from flash.
++ * @return data length reading from flash.
++ */
++static int _ra_nand_pull_data(char *buf, int len, int use_gdma)
++{
++#ifdef RW_DATA_BY_BYTE
++      char *p = buf;
++#else
++      __u32 *p = (__u32 *)buf;
++#endif
++      int retry, int_st;
++      unsigned int ret_data;
++      int ret_size;
++
++      // receive data by use_gdma 
++      if (use_gdma) { 
++              //if (_ra_nand_dma_pull((unsigned long)p, len)) {
++              if (1) {
++                      printk("%s: fail \n", __func__);
++                      len = -1; //return error
++              }
++
++              return len;
++      }
++
++      //fixme: retry count size?
++      retry = READ_STATUS_RETRY;
++      // no gdma
++      while (len > 0) {
++              int_st = ra_inl(NFC_INT_ST);
++              if (int_st & INT_ST_RX_BUF_RDY) {
++
++                      ret_data = ra_inl(NFC_DATA);
++                      ra_outl(NFC_INT_ST, INT_ST_RX_BUF_RDY); 
++#ifdef RW_DATA_BY_BYTE
++                      ret_size = sizeof(unsigned int);
++                      ret_size = min(ret_size, len);
++                      len -= ret_size;
++                      while (ret_size-- > 0) {
++                              //nfc is little endian 
++                              *p++ = ret_data & 0x0ff;
++                              ret_data >>= 8; 
++                      }
++#else
++                      ret_size = min(len, 4);
++                      len -= ret_size;
++                      if (ret_size == 4)
++                              *p++ = ret_data;
++                      else {
++                              __u8 *q = (__u8 *)p;
++                              while (ret_size-- > 0) {
++                                      *q++ = ret_data & 0x0ff;
++                                      ret_data >>= 8; 
++                              }
++                              p = (__u32 *)q;
++                      }
++#endif
++                      retry = READ_STATUS_RETRY;
++              }
++              else if (int_st & INT_ST_ND_DONE) {
++                      break;
++              }
++              else {
++                      udelay(1);
++                      if (retry-- < 0) 
++                              break;
++              }
++      }
++
++#ifdef RW_DATA_BY_BYTE
++      return (int)(p - buf);
++#else
++      return ((int)p - (int)buf);
++#endif
++}
++
++/**
++ * generic function to put data into flash.
++ * @return data length writing into flash.
++ */
++static int _ra_nand_push_data(char *buf, int len, int use_gdma)
++{
++#ifdef RW_DATA_BY_BYTE
++      char *p = buf;
++#else
++      __u32 *p = (__u32 *)buf;
++#endif
++      int retry, int_st;
++      unsigned int tx_data = 0;
++      int tx_size, iter = 0;
++
++      // receive data by use_gdma 
++      if (use_gdma) { 
++              //if (_ra_nand_dma_push((unsigned long)p, len))
++              if (1)
++                      len = 0;                
++              printk("%s: fail \n", __func__);
++              return len;
++      }
++
++      // no gdma
++      retry = READ_STATUS_RETRY;
++      while (len > 0) {
++              int_st = ra_inl(NFC_INT_ST);
++              if (int_st & INT_ST_TX_BUF_RDY) {
++#ifdef RW_DATA_BY_BYTE
++                      tx_size = min(len, (int)sizeof(unsigned long));
++                      for (iter = 0; iter < tx_size; iter++) {
++                              tx_data |= (*p++ << (8*iter));
++                      }
++#else
++                      tx_size = min(len, 4);
++                      if (tx_size == 4)
++                              tx_data = (*p++);
++                      else {
++                              __u8 *q = (__u8 *)p;
++                              for (iter = 0; iter < tx_size; iter++)
++                                      tx_data |= (*q++ << (8*iter));
++                              p = (__u32 *)q;
++                      }
++#endif
++                      ra_outl(NFC_INT_ST, INT_ST_TX_BUF_RDY);
++                      ra_outl(NFC_DATA, tx_data);
++                      len -= tx_size;
++                      retry = READ_STATUS_RETRY;
++              }
++              else if (int_st & INT_ST_ND_DONE) {
++                      break;
++              }
++              else {
++                      udelay(1);
++                      if (retry-- < 0) {
++                              ra_dbg("%s p:%p buf:%p \n", __func__, p, buf);
++                              break;
++                      }
++              }
++      }
++
++      
++#ifdef RW_DATA_BY_BYTE
++      return (int)(p - buf);
++#else
++      return ((int)p - (int)buf);
++#endif
++
++}
++
++static int nfc_select_chip(struct ra_nand_chip *ra, int chipnr)
++{
++#if (CONFIG_NUMCHIPS == 1)
++      if (!(chipnr < CONFIG_NUMCHIPS))
++              return -1;
++      return 0;
++#else
++      BUG();
++#endif
++}
++
++/** @return -1: chip_select fail
++ *        0 : both CE and WP==0 are OK
++ *        1 : CE OK and WP==1
++ */
++static int nfc_enable_chip(struct ra_nand_chip *ra, unsigned int offs, int read_only)
++{
++      int chipnr = offs >> ra->chip_shift;
++
++      ra_dbg("%s: offs:%x read_only:%x \n", __func__, offs, read_only);
++
++      chipnr = nfc_select_chip(ra, chipnr);
++      if (chipnr < 0) {
++              printk("%s: chip select error, offs(%x)\n", __func__, offs);
++              return -1;
++      }
++
++      if (!read_only)
++              return nfc_check_wp();
++      
++      return 0;
++}
++
++/** wait nand chip becomeing ready and return queried status.
++ * @param snooze: sleep time in ms unit before polling device ready.
++ * @return status of nand chip
++ * @return NAN_STATUS_FAIL if something unexpected.
++ */
++static int nfc_wait_ready(int snooze_ms)
++{
++      int retry;
++      char status;
++
++      // wait nfc idle,
++      if (snooze_ms == 0)
++              snooze_ms = 1;
++      else
++              schedule_timeout(snooze_ms * HZ / 1000);
++      
++      snooze_ms = retry = snooze_ms *1000000 / 100 ;  // ndelay(100)
++
++      while (!NFC_TRANS_DONE() && retry--) {
++              if (!cond_resched())
++                      ndelay(100);
++      }
++      
++      if (!NFC_TRANS_DONE()) {
++              printk("nfc_wait_ready: no transaction done \n");
++              return NAND_STATUS_FAIL;
++      }
++
++#if !defined (CONFIG_NOT_SUPPORT_RB)
++      //fixme
++      while(!(status = nfc_device_ready()) && retry--) {
++              ndelay(100);
++      }
++
++      if (status == 0) {
++              printk("nfc_wait_ready: no device ready. \n");  
++              return NAND_STATUS_FAIL;
++      }
++
++      _nfc_read_status(&status);
++      return status;
++#else
++
++      while(retry--) {
++              _nfc_read_status(&status);
++              if (status & NAND_STATUS_READY)
++                      break;
++              ndelay(100);
++      }
++      if (retry<0)
++              printk("nfc_wait_ready 2: no device ready, status(%x). \n", status);    
++
++      return status;
++#endif
++}
++
++/**
++ * return 0: erase OK
++ * return -EIO: fail 
++ */
++int nfc_erase_block(struct ra_nand_chip *ra, int row_addr)
++{
++      unsigned long cmd1, cmd2, bus_addr, conf;
++      char status;
++
++      cmd1 = 0x60;
++      cmd2 = 0xd0;
++      bus_addr = row_addr;
++      conf = 0x00511 | ((CFG_ROW_ADDR_CYCLE)<<16);
++
++      // set NFC
++      ra_dbg("%s: cmd1: %lx, cmd2:%lx bus_addr: %lx, conf: %lx \n", 
++             __func__, cmd1, cmd2, bus_addr, conf);
++
++      //fixme, should we check nfc status?
++      CLEAR_INT_STATUS();
++
++      ra_outl(NFC_CMD1, cmd1);        
++      ra_outl(NFC_CMD2, cmd2);
++      ra_outl(NFC_ADDR, bus_addr);
++      ra_outl(NFC_CONF, conf); 
++
++      status = nfc_wait_ready(3);  //erase wait 3ms 
++      if (status & NAND_STATUS_FAIL) {
++              printk("%s: fail \n", __func__);
++              return -EIO;
++      }
++      
++      return 0;
++
++}
++
++static inline int _nfc_read_raw_data(int cmd1, int cmd2, int bus_addr, int bus_addr2, int conf, char *buf, int len, int flags)
++{
++      int ret;
++
++      CLEAR_INT_STATUS();
++      ra_outl(NFC_CMD1, cmd1);        
++      ra_outl(NFC_CMD2, cmd2);
++      ra_outl(NFC_ADDR, bus_addr);
++#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
++    defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)  
++      ra_outl(NFC_ADDR2, bus_addr2);
++#endif        
++      ra_outl(NFC_CONF, conf); 
++
++      ret = _ra_nand_pull_data(buf, len, 0);
++      if (ret != len) {
++              ra_dbg("%s: ret:%x (%x) \n", __func__, ret, len);
++              return NAND_STATUS_FAIL;
++      }
++
++      //FIXME, this section is not necessary
++      ret = nfc_wait_ready(0); //wait ready 
++      /* to prevent the DATA FIFO 's old data from next operation */
++      ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
++      ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
++
++      if (ret & NAND_STATUS_FAIL) {
++              printk("%s: fail \n", __func__);
++              return NAND_STATUS_FAIL;
++      }
++
++      return 0;
++}
++
++static inline int _nfc_write_raw_data(int cmd1, int cmd3, int bus_addr, int bus_addr2, int conf, char *buf, int len, int flags)
++{
++      int ret;
++
++      CLEAR_INT_STATUS();
++      ra_outl(NFC_CMD1, cmd1);        
++      ra_outl(NFC_CMD3, cmd3);        
++      ra_outl(NFC_ADDR, bus_addr);
++#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
++    defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)  
++      ra_outl(NFC_ADDR2, bus_addr2);
++#endif        
++      ra_outl(NFC_CONF, conf); 
++
++      ret = _ra_nand_push_data(buf, len, 0);
++      if (ret != len) {
++              ra_dbg("%s: ret:%x (%x) \n", __func__, ret, len);
++              return NAND_STATUS_FAIL;
++      }
++
++      ret = nfc_wait_ready(1); //write wait 1ms
++      /* to prevent the DATA FIFO 's old data from next operation */
++      ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) | 0x02); //clear data buffer
++      ra_outl(NFC_CTRL, ra_inl(NFC_CTRL) & ~0x02); //clear data buffer
++
++      if (ret & NAND_STATUS_FAIL) {
++              printk("%s: fail \n", __func__);
++              return NAND_STATUS_FAIL;
++      }
++
++      return 0;
++}
++
++/**
++ * @return !0: fail
++ * @return 0: OK
++ */
++int nfc_read_oob(struct ra_nand_chip *ra, int page, unsigned int offs, char *buf, int len, int flags)
++{
++      unsigned int cmd1 = 0, cmd2 = 0, conf = 0;
++      unsigned int bus_addr = 0, bus_addr2 = 0;
++      unsigned int ecc_en;
++      int use_gdma;
++      int status;
++
++      int pages_perblock = 1<<(ra->erase_shift - ra->page_shift);
++      // constrain of nfc read function 
++
++#if defined (WORKAROUND_RX_BUF_OV)
++      BUG_ON (len > 60);      //problem of rx-buffer overrun 
++#endif
++      BUG_ON (offs >> ra->oob_shift); //page boundry
++      BUG_ON ((unsigned int)(((offs + len) >> ra->oob_shift) + page) >
++              ((page + pages_perblock) & ~(pages_perblock-1))); //block boundry
++
++      use_gdma = flags & FLAG_USE_GDMA;
++      ecc_en = flags & FLAG_ECC_EN;
++      bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8) - 1));
++
++      if (is_nand_page_2048) {
++              bus_addr += CFG_PAGESIZE;
++              bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
++              cmd1 = 0x0;
++              cmd2 = 0x30;
++              conf = 0x000511| ((CFG_ADDR_CYCLE)<<16) | (len << 20); 
++      }
++      else {
++              cmd1 = 0x50;
++              conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20); 
++      }
++      if (ecc_en) 
++              conf |= (1<<3); 
++      if (use_gdma)
++              conf |= (1<<2);
++
++      ra_dbg("%s: cmd1:%x, bus_addr:%x, conf:%x, len:%x, flag:%x\n",
++             __func__, cmd1, bus_addr, conf, len, flags);
++
++      status = _nfc_read_raw_data(cmd1, cmd2, bus_addr, bus_addr2, conf, buf, len, flags);
++      if (status & NAND_STATUS_FAIL) {
++              printk("%s: fail\n", __func__);
++              return -EIO;
++      }
++
++      return 0; 
++}
++
++/**
++ * @return !0: fail
++ * @return 0: OK
++ */
++int nfc_write_oob(struct ra_nand_chip *ra, int page, unsigned int offs, char *buf, int len, int flags)
++{
++      unsigned int cmd1 = 0, cmd3=0, conf = 0;
++      unsigned int bus_addr = 0, bus_addr2 = 0;
++      int use_gdma;
++      int status;
++
++      int pages_perblock = 1<<(ra->erase_shift - ra->page_shift);
++      // constrain of nfc read function 
++
++      BUG_ON (offs >> ra->oob_shift); //page boundry
++      BUG_ON ((unsigned int)(((offs + len) >> ra->oob_shift) + page) >
++              ((page + pages_perblock) & ~(pages_perblock-1))); //block boundry 
++
++      use_gdma = flags & FLAG_USE_GDMA;
++      bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8) - 1));
++
++      if (is_nand_page_2048) {
++              cmd1 = 0x80;
++              cmd3 = 0x10;
++              bus_addr += CFG_PAGESIZE;
++              bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
++              conf = 0x001123 | ((CFG_ADDR_CYCLE)<<16) | ((len) << 20);
++      }
++      else {
++              cmd1 = 0x08050;
++              cmd3 = 0x10;
++              conf = 0x001223 | ((CFG_ADDR_CYCLE)<<16) | ((len) << 20); 
++      }
++      if (use_gdma)
++              conf |= (1<<2);
++
++      // set NFC
++      ra_dbg("%s: cmd1: %x, cmd3: %x bus_addr: %x, conf: %x, len:%x\n", 
++             __func__, cmd1, cmd3, bus_addr, conf, len);
++
++      status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, len, flags);
++      if (status & NAND_STATUS_FAIL) {
++              printk("%s: fail \n", __func__);
++              return -EIO;
++      }
++
++      return 0; 
++}
++
++
++int nfc_read_page(struct ra_nand_chip *ra, char *buf, int page, int flags);
++int nfc_write_page(struct ra_nand_chip *ra, char *buf, int page, int flags);
++
++
++#if !defined (WORKAROUND_RX_BUF_OV)   
++static int one_bit_correction(char *ecc, char *expected, int *bytes, int *bits);
++int nfc_ecc_verify(struct ra_nand_chip *ra, char *buf, int page, int mode)
++{
++      int ret, i;
++      char *p, *e;
++      int ecc;
++      
++      //ra_dbg("%s, page:%x mode:%d\n", __func__, page, mode);
++
++      if (mode == FL_WRITING) {
++              int len = CFG_PAGESIZE + CFG_PAGE_OOBSIZE;
++              int conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20); 
++              conf |= (1<<3); //(ecc_en) 
++              //conf |= (1<<2); // (use_gdma)
++
++              p = ra->readback_buffers;
++              ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_ECC_EN); 
++              if (ret == 0) 
++                      goto ecc_check;
++              
++              //FIXME, double comfirm
++              printk("%s: read back fail, try again \n",__func__);
++              ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_ECC_EN); 
++              if (ret != 0) {
++                      printk("\t%s: read back fail agian \n",__func__);
++                      goto bad_block;
++              }
++      }
++      else if (mode == FL_READING) {
++              p = buf;
++      }       
++      else
++              return -2;
++
++ecc_check:
++      p += CFG_PAGESIZE;
++      if (!is_nand_page_2048) {
++              ecc = ra_inl(NFC_ECC); 
++              if (ecc == 0) //clean page.
++                      return 0;
++              e = (char*)&ecc;
++              for (i=0; i<CONFIG_ECC_BYTES; i++) {
++                      int eccpos = CONFIG_ECC_OFFSET + i;
++                      if (*(p + eccpos) != (char)0xff)
++                              break;
++                      if (i == CONFIG_ECC_BYTES - 1) {
++                              printk("skip ecc 0xff at page %x\n", page);
++                              return 0;
++                      }
++              }
++              for (i=0; i<CONFIG_ECC_BYTES; i++) {
++                      int eccpos = CONFIG_ECC_OFFSET + i;
++                      if (*(p + eccpos) != *(e + i)) {
++                              printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, ecc:%x \n",
++                                              __func__, (mode == FL_READING)?"read":"write", page,    
++                                              *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
++                              return -1;
++                      }
++              }
++      }
++#if defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || \
++    defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621)  
++      else {
++              int ecc2, ecc3, ecc4, qsz;
++              char *e2, *e3, *e4;
++              int correction_flag = 0;
++              ecc = ra_inl(NFC_ECC_P1);
++              ecc2 = ra_inl(NFC_ECC_P2);
++              ecc3 = ra_inl(NFC_ECC_P3);
++              ecc4 = ra_inl(NFC_ECC_P4);
++              e = (char*)&ecc;
++              e2 = (char*)&ecc2;
++              e3 = (char*)&ecc3;
++              e4 = (char*)&ecc4;
++              qsz = CFG_PAGE_OOBSIZE / 4;
++              if (ecc == 0 && ecc2 == 0 && ecc3 == 0 && ecc4 == 0)
++                      return 0;
++              for (i=0; i<CONFIG_ECC_BYTES; i++) {
++                      int eccpos = CONFIG_ECC_OFFSET + i;
++                      if (*(p + eccpos) != (char)0xff)
++                              break;
++                      else if (*(p + eccpos + qsz) != (char)0xff)
++                              break;
++                      else if (*(p + eccpos + qsz*2) != (char)0xff)
++                              break;
++                      else if (*(p + eccpos + qsz*3) != (char)0xff)
++                              break;
++                      if (i == CONFIG_ECC_BYTES - 1) {
++                              printk("skip ecc 0xff at page %x\n", page);
++                              return 0;
++                      }
++              }
++              for (i=0; i<CONFIG_ECC_BYTES; i++) {
++                      int eccpos = CONFIG_ECC_OFFSET + i;
++                      if (*(p + eccpos) != *(e + i)) {
++                              printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, ecc:%x \n",
++                                              __func__, (mode == FL_READING)?"read":"write", page,
++                                              *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
++                              correction_flag |= 0x1;
++                      }
++                      if (*(p + eccpos + qsz) != *(e2 + i)) {
++                              printk("%s mode:%s, invalid ecc2, page: %x read:%x %x %x, ecc2:%x \n",
++                                              __func__, (mode == FL_READING)?"read":"write", page,
++                                              *(p+CONFIG_ECC_OFFSET+qsz), *(p+ CONFIG_ECC_OFFSET+1+qsz), *(p+ CONFIG_ECC_OFFSET+2+qsz), ecc2);
++                              correction_flag |= 0x2;
++                      }
++                      if (*(p + eccpos + qsz*2) != *(e3 + i)) {
++                              printk("%s mode:%s, invalid ecc3, page: %x read:%x %x %x, ecc3:%x \n",
++                                              __func__, (mode == FL_READING)?"read":"write", page,
++                                              *(p+CONFIG_ECC_OFFSET+qsz*2), *(p+ CONFIG_ECC_OFFSET+1+qsz*2), *(p+ CONFIG_ECC_OFFSET+2+qsz*2), ecc3);
++                              correction_flag |= 0x4;
++                      }
++                      if (*(p + eccpos + qsz*3) != *(e4 + i)) {
++                              printk("%s mode:%s, invalid ecc4, page: %x read:%x %x %x, ecc4:%x \n",
++                                              __func__, (mode == FL_READING)?"read":"write", page,
++                                              *(p+CONFIG_ECC_OFFSET+qsz*3), *(p+ CONFIG_ECC_OFFSET+1+qsz*3), *(p+ CONFIG_ECC_OFFSET+2+qsz*3), ecc4);
++                              correction_flag |= 0x8;
++                      }
++              }
++
++              if (correction_flag)
++              {
++                      printk("trying to do correction!\n");
++                      if (correction_flag & 0x1)
++                      {
++                              int bytes, bits;
++                              char *pBuf = p - CFG_PAGESIZE;
++                      
++                              if (one_bit_correction(p + CONFIG_ECC_OFFSET, e, &bytes, &bits) == 0)
++                              {
++                                      pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
++                                      printk("1. correct byte %d, bit %d!\n", bytes, bits);
++                              }
++                              else
++                              {
++                                      printk("failed to correct!\n");
++                                      return -1;
++                              }
++                      }
++
++                      if (correction_flag & 0x2)
++                      {
++                              int bytes, bits;
++                              char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE/4;
++                      
++                              if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz), e2, &bytes, &bits) == 0)
++                              {
++                                      pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
++                                      printk("2. correct byte %d, bit %d!\n", bytes, bits);
++                              }
++                              else
++                              {
++                                      printk("failed to correct!\n");
++                                      return -1;
++                              }
++                      }
++                      if (correction_flag & 0x4)
++                      {
++                              int bytes, bits;
++                              char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE/2;
++                      
++                              if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz * 2), e3, &bytes, &bits) == 0)
++                              {
++                                      pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
++                                      printk("3. correct byte %d, bit %d!\n", bytes, bits);
++                              }
++                              else
++                              {
++                                      printk("failed to correct!\n");
++                                      return -1;
++                              }
++                      }
++                      if (correction_flag & 0x8)
++                      {
++                              int bytes, bits;
++                              char *pBuf = (p - CFG_PAGESIZE) + CFG_PAGESIZE*3/4;
++                      
++                              if (one_bit_correction((p + CONFIG_ECC_OFFSET + qsz * 3), e4, &bytes, &bits) == 0)
++                              {
++                                      pBuf[bytes] = pBuf[bytes] ^ (1 << bits);
++                                      printk("4. correct byte %d, bit %d!\n", bytes, bits);
++                              }
++                              else
++                              {
++                                      printk("failed to correct!\n");
++                                      return -1;
++                              }
++                      }
++              }
++
++      }
++#endif        
++      return 0;
++
++bad_block:
++      return -1;
++}
++
++#else
++
++void ranfc_dump(void) 
++{     
++      int i;
++      for (i=0; i<11; i++) {
++              if (i==6) 
++                      continue;
++              printk("%x: %x \n", NFC_BASE + i*4, ra_inl(NFC_BASE + i*4));
++      }
++}
++
++/**
++ * @return 0, ecc OK or corrected.
++ * @return NAND_STATUS_FAIL, ecc fail.   
++ */
++
++int nfc_ecc_verify(struct ra_nand_chip *ra, char *buf, int page, int mode)
++{
++      int ret, i;
++      char *p, *e;
++      int ecc;
++      
++      if (ranfc_verify == 0)
++              return 0;
++
++      ra_dbg("%s, page:%x mode:%d\n", __func__, page, mode);
++
++      if (mode == FL_WRITING) { // read back and memcmp
++              ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_NONE); 
++              if (ret != 0) //double comfirm
++                      ret = nfc_read_page(ra, ra->readback_buffers, page, FLAG_NONE); 
++
++              if (ret != 0) {
++                      printk("%s: mode:%x read back fail \n", __func__, mode);
++                      return -1;
++              }
++              return memcmp(buf, ra->readback_buffers, 1<<ra->page_shift);
++      }
++      
++      if (mode == FL_READING) { 
++#if 0
++              if (ra->sandbox_page == 0)
++                      return 0;
++
++              ret = nfc_write_page(ra, buf, ra->sandbox_page, FLAG_USE_GDMA | FLAG_ECC_EN);
++              if (ret != 0) {
++                      printk("%s, fail write sandbox_page \n", __func__);
++                      return -1;
++              }
++#else
++              /** @note: 
++               * The following command is actually not 'write' command to drive NFC to write flash.
++               * However, it can make NFC to calculate ECC, that will be used to compare with original ones.
++               * --YT
++               */
++              unsigned int conf = 0x001223| (CFG_ADDR_CYCLE<<16) | (0x200 << 20) | (1<<3) | (1<<2); 
++              _nfc_write_raw_data(0xff, 0xff, ra->sandbox_page<<ra->page_shift, conf, buf, 0x200, FLAG_USE_GDMA);
++#endif
++
++              ecc = ra_inl(NFC_ECC); 
++              if (ecc == 0) //clean page.
++                      return 0;
++              e = (char*)&ecc;
++              p = buf + (1<<ra->page_shift);
++              for (i=0; i<CONFIG_ECC_BYTES; i++) {
++                      int eccpos = CONFIG_ECC_OFFSET + i;
++                      if (*(p + eccpos) != *(e + i)) {
++                              printk("%s mode:%s, invalid ecc, page: %x read:%x %x %x, write:%x \n",
++                                     __func__, (mode == FL_READING)?"read":"write", page,     
++                                     *(p+ CONFIG_ECC_OFFSET), *(p+ CONFIG_ECC_OFFSET+1), *(p+ CONFIG_ECC_OFFSET +2), ecc);
++
++                              for (i=0; i<528; i++)
++                                      printk("%-2x \n", *(buf + i));
++                              return -1;
++                      }
++              }
++              return 0;
++      }
++
++      return -1;
++
++}
++
++#endif
++
++
++/**
++ * @return -EIO, writing size is less than a page 
++ * @return 0, OK
++ */
++int nfc_read_page(struct ra_nand_chip *ra, char *buf, int page, int flags)
++{
++      unsigned int cmd1 = 0, cmd2 = 0, conf = 0;
++      unsigned int bus_addr = 0, bus_addr2 = 0;
++      unsigned int ecc_en;
++      int use_gdma;
++      int size, offs;
++      int status = 0;
++
++      use_gdma = flags & FLAG_USE_GDMA;
++      ecc_en = flags & FLAG_ECC_EN;
++
++      page = page & (CFG_CHIPSIZE - 1); // chip boundary
++      size = CFG_PAGESIZE + CFG_PAGE_OOBSIZE; //add oobsize
++      offs = 0;
++
++      while (size > 0) {
++              int len;
++#if defined (WORKAROUND_RX_BUF_OV)
++              len = min(60, size);
++#else
++              len = size;
++#endif                
++              bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)) | (offs & ((1<<CFG_COLUMN_ADDR_CYCLE*8)-1)); 
++              if (is_nand_page_2048) {
++                      bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
++                      cmd1 = 0x0;
++                      cmd2 = 0x30;
++                      conf = 0x000511| ((CFG_ADDR_CYCLE)<<16) | (len << 20); 
++              }
++              else {
++                      if (offs & ~(CFG_PAGESIZE-1))
++                              cmd1 = 0x50;
++                      else if (offs & ~((1<<CFG_COLUMN_ADDR_CYCLE*8)-1))
++                              cmd1 = 0x01;
++                      else
++                              cmd1 = 0;
++
++                      conf = 0x000141| ((CFG_ADDR_CYCLE)<<16) | (len << 20); 
++              }
++#if !defined (WORKAROUND_RX_BUF_OV)
++              if (ecc_en) 
++                      conf |= (1<<3); 
++#endif
++              if (use_gdma)
++                      conf |= (1<<2);
++
++              status = _nfc_read_raw_data(cmd1, cmd2, bus_addr, bus_addr2, conf, buf+offs, len, flags);
++              if (status & NAND_STATUS_FAIL) {
++                      printk("%s: fail \n", __func__);
++                      return -EIO;
++              }
++
++              offs += len;
++              size -= len;
++      }
++
++      // verify and correct ecc
++      if ((flags & (FLAG_VERIFY | FLAG_ECC_EN)) == (FLAG_VERIFY | FLAG_ECC_EN)) {
++              status = nfc_ecc_verify(ra, buf, page, FL_READING);     
++              if (status != 0) {
++                      printk("%s: fail, buf:%x, page:%x, flag:%x\n", 
++                             __func__, (unsigned int)buf, page, flags);
++                      return -EBADMSG;
++              }
++      }
++      else {
++              // fix,e not yet support
++              ra->buffers_page = -1; //cached
++      }
++
++      return 0;
++}
++
++
++/** 
++ * @return -EIO, fail to write
++ * @return 0, OK
++ */
++int nfc_write_page(struct ra_nand_chip *ra, char *buf, int page, int flags)
++{
++      unsigned int cmd1 = 0, cmd3, conf = 0;
++      unsigned int bus_addr = 0, bus_addr2 = 0;
++      unsigned int ecc_en;
++      int use_gdma;
++      int size;
++      char status;
++      uint8_t *oob = buf + (1<<ra->page_shift);
++
++      use_gdma = flags & FLAG_USE_GDMA;
++      ecc_en = flags & FLAG_ECC_EN;
++
++      oob[ra->badblockpos] = 0xff;    //tag as good block.
++      ra->buffers_page = -1; //cached
++
++      page = page & (CFG_CHIPSIZE-1); //chip boundary
++      size = CFG_PAGESIZE + CFG_PAGE_OOBSIZE; //add oobsize
++      bus_addr = (page << (CFG_COLUMN_ADDR_CYCLE*8)); //write_page always write from offset 0.
++
++      if (is_nand_page_2048) {
++      bus_addr2 = page >> (CFG_COLUMN_ADDR_CYCLE*8);
++              cmd1 = 0x80;
++              cmd3 = 0x10;
++              conf = 0x001123| ((CFG_ADDR_CYCLE)<<16) | (size << 20); 
++      }
++      else {
++      cmd1 = 0x8000;
++      cmd3 = 0x10;
++      conf = 0x001223| ((CFG_ADDR_CYCLE)<<16) | (size << 20); 
++}
++      if (ecc_en) 
++              conf |= (1<<3); //enable ecc
++      if (use_gdma)
++              conf |= (1<<2);
++
++      // set NFC
++      ra_dbg("nfc_write_page: cmd1: %x, cmd3: %x bus_addr: %x, conf: %x, len:%x\n", 
++             cmd1, cmd3, bus_addr, conf, size);
++
++      status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, size, flags);
++      if (status & NAND_STATUS_FAIL) {
++              printk("%s: fail \n", __func__);
++              return -EIO;
++      }
++      
++
++      if (flags & FLAG_VERIFY) { // verify and correct ecc
++              status = nfc_ecc_verify(ra, buf, page, FL_WRITING);
++
++#ifdef RANDOM_GEN_BAD_BLOCK
++              if (((random32() & 0x1ff) == 0x0) && (page >= 0x100)) // randomly create bad block
++              {
++                      printk("hmm... create a bad block at page %x\n", (bus_addr >> 16));
++                      status = -1;
++              }
++#endif
++
++              if (status != 0) {
++                      printk("%s: ecc_verify fail: ret:%x \n", __func__, status);
++                      oob[ra->badblockpos] = 0x33; 
++                      page -= page % (CFG_BLOCKSIZE/CFG_PAGESIZE);
++                      printk("create a bad block at page %x\n", page);
++                      if (!is_nand_page_2048)
++                              status = nfc_write_oob(ra, page, ra->badblockpos, oob+ra->badblockpos, 1, flags);
++                      else
++                      {
++                              status = _nfc_write_raw_data(cmd1, cmd3, bus_addr, bus_addr2, conf, buf, size, flags);
++                              nfc_write_oob(ra, page, 0, oob, 16, FLAG_NONE);
++                      }
++                      return -EBADMSG;
++              }
++      }
++
++
++      ra->buffers_page = page; //cached
++      return 0;
++}
++
++
++
++/*************************************************************
++ * nand internal process 
++ *************************************************************/
++
++/**
++ * nand_release_device - [GENERIC] release chip
++ * @mtd:      MTD device structure
++ *
++ * Deselect, release chip lock and wake up anyone waiting on the device
++ */
++static void nand_release_device(struct ra_nand_chip *ra)
++{
++      /* De-select the NAND device */
++      nfc_select_chip(ra, -1);
++
++      /* Release the controller and the chip */
++      ra->state = FL_READY;
++
++      mutex_unlock(ra->controller);
++}
++
++/**
++ * nand_get_device - [GENERIC] Get chip for selected access
++ * @chip:     the nand chip descriptor
++ * @mtd:      MTD device structure
++ * @new_state:        the state which is requested
++ *
++ * Get the device and lock it for exclusive access
++ */
++static int
++nand_get_device(struct ra_nand_chip *ra, int new_state)
++{
++      int ret = 0;
++
++      ret = mutex_lock_interruptible(ra->controller);
++      if (!ret) 
++              ra->state = new_state;
++
++      return ret;
++
++}
++
++
++
++/*************************************************************
++ * nand internal process 
++ *************************************************************/
++
++int nand_bbt_get(struct ra_nand_chip *ra, int block)
++{
++      int byte, bits;
++      bits = block * BBTTAG_BITS;
++
++      byte = bits / 8;
++      bits = bits % 8;
++      
++      return (ra->bbt[byte] >> bits) & BBTTAG_BITS_MASK;
++}
++
++int nand_bbt_set(struct ra_nand_chip *ra, int block, int tag)
++{
++      int byte, bits;
++      bits = block * BBTTAG_BITS;
++
++      byte = bits / 8;
++      bits = bits % 8;
++
++      // If previous tag is bad, dont overwrite it    
++      if (((ra->bbt[byte] >> bits) & BBTTAG_BITS_MASK) == BBT_TAG_BAD)
++      {
++              return BBT_TAG_BAD;
++      }
++
++      ra->bbt[byte] = (ra->bbt[byte] & ~(BBTTAG_BITS_MASK << bits)) | ((tag & BBTTAG_BITS_MASK) << bits);
++              
++      return tag;
++}
++
++/**
++ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
++ * @mtd:      MTD device structure
++ * @ofs:      offset from device start
++ *
++ * Check, if the block is bad. Either by reading the bad block table or
++ * calling of the scan function.
++ */
++int nand_block_checkbad(struct ra_nand_chip *ra, loff_t offs)
++{
++      int page, block;
++      int ret = 4;
++      unsigned int tag;
++      char *str[]= {"UNK", "RES", "BAD", "GOOD"};
++
++      if (ranfc_bbt == 0)
++              return 0;
++
++      {
++              // align with chip
++
++              offs = offs & ((1<<ra->chip_shift) -1);
++
++              page = offs >> ra->page_shift;
++              block = offs >> ra->erase_shift;
++      }
++
++      tag = nand_bbt_get(ra, block);
++
++      if (tag == BBT_TAG_UNKNOWN) {
++              ret = nfc_read_oob(ra, page, ra->badblockpos, (char*)&tag, 1, FLAG_NONE);
++              if (ret == 0)
++                      tag = ((le32_to_cpu(tag) & 0x0ff) == 0x0ff) ? BBT_TAG_GOOD : BBT_TAG_BAD;
++              else
++                      tag = BBT_TAG_BAD;
++
++              nand_bbt_set(ra, block, tag);
++      }
++
++      if (tag != BBT_TAG_GOOD) {
++              printk("%s: offs:%x tag: %s \n", __func__, (unsigned int)offs, str[tag]);
++              return 1;
++      }
++      else 
++              return 0;
++      
++}
++
++
++
++/**
++ * nand_block_markbad -
++ */
++int nand_block_markbad(struct ra_nand_chip *ra, loff_t offs)
++{
++      int page, block;
++      int ret = 4;
++      unsigned int tag;
++      char *ecc;
++
++      // align with chip
++      ra_dbg("%s offs: %x \n", __func__, (int)offs);
++
++      offs = offs & ((1<<ra->chip_shift) -1);
++
++      page = offs >> ra->page_shift;
++      block = offs >> ra->erase_shift;
++
++      tag = nand_bbt_get(ra, block);
++
++      if (tag == BBT_TAG_BAD) {
++              printk("%s: mark repeatedly \n", __func__);
++              return 0;
++      }
++
++      // new tag as bad
++      tag =BBT_TAG_BAD;
++      ret = nfc_read_page(ra, ra->buffers, page, FLAG_NONE);
++      if (ret != 0) {
++              printk("%s: fail to read bad block tag \n", __func__);
++              goto tag_bbt;
++      }
++
++      ecc = &ra->buffers[(1<<ra->page_shift)+ra->badblockpos];
++      if (*ecc == (char)0x0ff) {
++              //tag into flash
++              *ecc = (char)tag;
++              ret = nfc_write_page(ra, ra->buffers, page, FLAG_USE_GDMA);
++              if (ret)
++                      printk("%s: fail to write bad block tag \n", __func__);
++              
++      }       
++
++tag_bbt:
++      //update bbt
++      nand_bbt_set(ra, block, tag);
++
++      return 0;
++}
++
++
++#if defined (WORKAROUND_RX_BUF_OV)
++/**
++ * to find a bad block for ecc verify of read_page
++ */
++unsigned int nand_bbt_find_sandbox(struct ra_nand_chip *ra)
++{
++      loff_t offs = 0;
++      int chipsize = 1 << ra->chip_shift;
++      int blocksize = 1 << ra->erase_shift;
++
++      
++      while (offs < chipsize) {
++              if (nand_block_checkbad(ra, offs)) //scan and verify the unknown tag
++                      break;
++              offs += blocksize;
++      }
++
++      if (offs >= chipsize) {
++              offs = chipsize - blocksize;
++      }
++
++      nand_bbt_set(ra, (unsigned int)offs>>ra->erase_shift, BBT_TAG_RES);      // tag bbt only, instead of update badblockpos of flash.
++      return (offs >> ra->page_shift);
++}
++#endif
++
++
++
++/**
++ * nand_erase_nand - [Internal] erase block(s)
++ * @mtd:      MTD device structure
++ * @instr:    erase instruction
++ * @allowbbt: allow erasing the bbt area
++ *
++ * Erase one ore more blocks
++ */
++int _nand_erase_nand(struct ra_nand_chip *ra, struct erase_info *instr)
++{
++      int page, len, status, ret;
++      unsigned int addr, blocksize = 1<<ra->erase_shift;
++
++      ra_dbg("%s: start:%x, len:%x \n", __func__, 
++             (unsigned int)instr->addr, (unsigned int)instr->len);
++
++//#define BLOCK_ALIGNED(a) ((a) & (blocksize - 1)) // already defined
++
++      if (BLOCK_ALIGNED(instr->addr) || BLOCK_ALIGNED(instr->len)) {
++              ra_dbg("%s: erase block not aligned, addr:%x len:%x\n", __func__, instr->addr, instr->len);
++              return -EINVAL;
++      }
++
++      instr->fail_addr = 0xffffffff;
++
++      len = instr->len;
++      addr = instr->addr;
++      instr->state = MTD_ERASING;
++
++      while (len) {
++
++              page = (int)(addr >> ra->page_shift);
++
++              /* select device and check wp */
++              if (nfc_enable_chip(ra, addr, 0)) {
++                      printk("%s: nand is write protected \n", __func__);
++                      instr->state = MTD_ERASE_FAILED;
++                      goto erase_exit;
++              }
++
++              /* if we have a bad block, we do not erase bad blocks */
++              if (nand_block_checkbad(ra, addr)) {
++                      printk(KERN_WARNING "nand_erase: attempt to erase a "
++                             "bad block at 0x%08x\n", addr);
++                      instr->state = MTD_ERASE_FAILED;
++                      goto erase_exit;
++              }
++
++              /*
++               * Invalidate the page cache, if we erase the block which
++               * contains the current cached page
++               */
++              if (BLOCK_ALIGNED(addr) == BLOCK_ALIGNED(ra->buffers_page << ra->page_shift))
++                      ra->buffers_page = -1;
++
++              status = nfc_erase_block(ra, page);
++              /* See if block erase succeeded */
++              if (status) {
++                      printk("%s: failed erase, page 0x%08x\n", __func__, page);
++                      instr->state = MTD_ERASE_FAILED;
++                      instr->fail_addr = (page << ra->page_shift);
++                      goto erase_exit;
++              }
++
++
++              /* Increment page address and decrement length */
++              len -= blocksize;
++              addr += blocksize;
++
++      }
++      instr->state = MTD_ERASE_DONE;
++
++erase_exit:
++
++      ret = ((instr->state == MTD_ERASE_DONE) ? 0 : -EIO);
++      /* Do call back function */
++      if (!ret)
++              mtd_erase_callback(instr);
++
++      if (ret) {
++              nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
++      }
++
++      /* Return more or less happy */
++      return ret;
++}
++
++static int
++nand_write_oob_buf(struct ra_nand_chip *ra, uint8_t *buf, uint8_t *oob, size_t size,
++                 int mode, int ooboffs)
++{
++      size_t oobsize = 1<<ra->oob_shift;
++      struct nand_oobfree *free;
++      uint32_t woffs = ooboffs;
++      int retsize = 0;
++
++      ra_dbg("%s: size:%x, mode:%x, offs:%x  \n", __func__, size, mode, ooboffs);
++
++      switch(mode) {
++      case MTD_OPS_PLACE_OOB:
++      case MTD_OPS_RAW:
++              if (ooboffs > oobsize)
++                      return -1;
++
++              size = min(size, oobsize - ooboffs);
++              memcpy(buf + ooboffs, oob, size);
++              retsize = size;
++              break;
++
++      case MTD_OPS_AUTO_OOB:
++              if (ooboffs > ra->oob->oobavail)
++                      return -1;
++
++              while (size) {
++                      for(free = ra->oob->oobfree; free->length && size; free++) {
++                              int wlen = free->length - woffs;
++                              int bytes = 0;
++
++                              /* Write request not from offset 0 ? */
++                              if (wlen <= 0) {
++                                      woffs = -wlen;
++                                      continue;
++                              }
++
++                              bytes = min_t(size_t, size, wlen);
++                              memcpy (buf + free->offset + woffs, oob, bytes);
++                              woffs = 0;
++                              oob += bytes;
++                              size -= bytes;
++                              retsize += bytes;
++                      }
++                      buf += oobsize;
++              }
++              break;
++
++      default:
++              BUG();
++      }
++
++      return retsize;
++}
++
++static int nand_read_oob_buf(struct ra_nand_chip *ra, uint8_t *oob, size_t size, 
++                           int mode, int ooboffs) 
++{
++      size_t oobsize = 1<<ra->oob_shift;
++      uint8_t *buf = ra->buffers + (1<<ra->page_shift);
++      int retsize=0;
++
++      ra_dbg("%s: size:%x, mode:%x, offs:%x  \n", __func__, size, mode, ooboffs);
++
++      switch(mode) {
++      case MTD_OPS_PLACE_OOB:
++      case MTD_OPS_RAW:
++              if (ooboffs > oobsize)
++                      return -1;
++
++              size = min(size, oobsize - ooboffs);
++              memcpy(oob, buf + ooboffs, size);
++              return size;
++
++      case MTD_OPS_AUTO_OOB: {
++              struct nand_oobfree *free;
++              uint32_t woffs = ooboffs;
++
++              if (ooboffs > ra->oob->oobavail) 
++                      return -1;
++              
++              size = min(size, ra->oob->oobavail - ooboffs);
++              for(free = ra->oob->oobfree; free->length && size; free++) {
++                      int wlen = free->length - woffs;
++                      int bytes = 0;
++
++                      /* Write request not from offset 0 ? */
++                      if (wlen <= 0) {
++                              woffs = -wlen;
++                              continue;
++                      }
++                      
++                      bytes = min_t(size_t, size, wlen);
++                      memcpy (oob, buf + free->offset + woffs, bytes);
++                      woffs = 0;
++                      oob += bytes;
++                      size -= bytes;
++                      retsize += bytes;
++              }
++              return retsize;
++      }
++      default:
++              BUG();
++      }
++      
++      return -1;
++}
++
++/**
++ * nand_do_write_ops - [Internal] NAND write with ECC
++ * @mtd:      MTD device structure
++ * @to:               offset to write to
++ * @ops:      oob operations description structure
++ *
++ * NAND write with ECC
++ */
++static int nand_do_write_ops(struct ra_nand_chip *ra, loff_t to,
++                           struct mtd_oob_ops *ops)
++{
++      int page;
++      uint32_t datalen = ops->len;
++      uint32_t ooblen = ops->ooblen;
++      uint8_t *oob = ops->oobbuf;
++      uint8_t *data = ops->datbuf;
++      int pagesize = (1<<ra->page_shift);
++      int pagemask = (pagesize -1);
++      int oobsize = 1<<ra->oob_shift;
++      loff_t addr = to;
++      //int i = 0; //for ra_dbg only
++
++      ra_dbg("%s: to:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x oobmode:%x \n", 
++             __func__, (unsigned int)to, data, oob, datalen, ooblen, ops->ooboffs, ops->mode);
++
++      ops->retlen = 0;
++      ops->oobretlen = 0;
++
++
++      /* Invalidate the page cache, when we write to the cached page */
++      ra->buffers_page = -1;
++
++      
++      if (data ==0)
++              datalen = 0;
++      
++      // oob sequential (burst) write
++      if (datalen == 0 && ooblen) {
++              int len = ((ooblen + ops->ooboffs) + (ra->oob->oobavail - 1)) / ra->oob->oobavail * oobsize;
++
++              /* select chip, and check if it is write protected */
++              if (nfc_enable_chip(ra, addr, 0))
++                      return -EIO;
++
++              //FIXME, need sanity check of block boundary
++              page = (int)((to & ((1<<ra->chip_shift)-1)) >> ra->page_shift); //chip boundary
++              memset(ra->buffers, 0x0ff, pagesize);
++              //fixme, should we reserve the original content?
++              if (ops->mode == MTD_OPS_AUTO_OOB) {
++                      nfc_read_oob(ra, page, 0, ra->buffers, len, FLAG_NONE);
++              }
++              //prepare buffers
++              if (ooblen != 8)
++              {
++                      nand_write_oob_buf(ra, ra->buffers, oob, ooblen, ops->mode, ops->ooboffs);
++                      // write out buffer to chip
++                      nfc_write_oob(ra, page, 0, ra->buffers, len, FLAG_USE_GDMA);
++              }
++
++              ops->oobretlen = ooblen;
++              ooblen = 0;
++      }
++
++      // data sequential (burst) write
++      if (datalen && ooblen == 0) {
++              // ranfc can not support write_data_burst, since hw-ecc and fifo constraints..
++      }
++
++      // page write
++      while(datalen || ooblen) {
++              int len;
++              int ret;
++              int offs;
++              int ecc_en = 0;
++
++              ra_dbg("%s (%d): addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n", 
++                     __func__, i++, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
++
++              page = (int)((addr & ((1<<ra->chip_shift)-1)) >> ra->page_shift); //chip boundary
++              
++              /* select chip, and check if it is write protected */
++              if (nfc_enable_chip(ra, addr, 0))
++                      return -EIO;
++
++              // oob write
++              if (ops->mode == MTD_OPS_AUTO_OOB) {
++                      //fixme, this path is not yet varified 
++                      nfc_read_oob(ra, page, 0, ra->buffers + pagesize, oobsize, FLAG_NONE);
++              }
++              if (oob && ooblen > 0) {
++                      len = nand_write_oob_buf(ra, ra->buffers + pagesize, oob, ooblen, ops->mode, ops->ooboffs);
++                      if (len < 0) 
++                              return -EINVAL;
++                      
++                      oob += len;
++                      ops->oobretlen += len;
++                      ooblen -= len;
++              }
++
++              // data write
++              offs = addr & pagemask;
++              len = min_t(size_t, datalen, pagesize - offs);
++              if (data && len > 0) {
++                      memcpy(ra->buffers + offs, data, len);  // we can not sure ops->buf wether is DMA-able.
++
++                      data += len;
++                      datalen -= len;
++                      ops->retlen += len;
++
++                      ecc_en = FLAG_ECC_EN;
++              }
++              ret = nfc_write_page(ra, ra->buffers, page, FLAG_USE_GDMA | FLAG_VERIFY |
++                                   ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0 : ecc_en ));
++              if (ret) {
++                      nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
++                      return ret;
++              }
++
++              nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_GOOD);
++
++              addr = (page+1) << ra->page_shift;
++
++      }
++      return 0;
++}
++
++/**
++ * nand_do_read_ops - [Internal] Read data with ECC
++ *
++ * @mtd:      MTD device structure
++ * @from:     offset to read from
++ * @ops:      oob ops structure
++ *
++ * Internal function. Called with chip held.
++ */
++static int nand_do_read_ops(struct ra_nand_chip *ra, loff_t from,
++                          struct mtd_oob_ops *ops)
++{
++      int page;
++      uint32_t datalen = ops->len;
++      uint32_t ooblen = ops->ooblen;
++      uint8_t *oob = ops->oobbuf;
++      uint8_t *data = ops->datbuf;
++      int pagesize = (1<<ra->page_shift);
++      int pagemask = (pagesize -1);
++      loff_t addr = from;
++      //int i = 0; //for ra_dbg only
++
++      ra_dbg("%s: addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n", 
++             __func__, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
++
++      ops->retlen = 0;
++      ops->oobretlen = 0;
++      if (data == 0)
++              datalen = 0;
++
++
++      while(datalen || ooblen) {
++              int len;
++              int ret;
++              int offs;
++
++              ra_dbg("%s (%d): addr:%x, ops data:%p, oob:%p datalen:%x ooblen:%x, ooboffs:%x \n", 
++                     __func__, i++, (unsigned int)addr, data, oob, datalen, ooblen, ops->ooboffs);
++              /* select chip */
++              if (nfc_enable_chip(ra, addr, 1) < 0)
++                      return -EIO;
++
++              page = (int)((addr & ((1<<ra->chip_shift)-1)) >> ra->page_shift); 
++
++              ret = nfc_read_page(ra, ra->buffers, page, FLAG_VERIFY | 
++                                  ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0: FLAG_ECC_EN ));
++              //FIXME, something strange here, some page needs 2 more tries to guarantee read success.
++              if (ret) {
++                      printk("read again:\n");
++                      ret = nfc_read_page(ra, ra->buffers, page, FLAG_VERIFY | 
++                                          ((ops->mode == MTD_OPS_RAW || ops->mode == MTD_OPS_PLACE_OOB) ? 0: FLAG_ECC_EN ));
++
++                      if (ret) {
++                              printk("read again fail \n");
++                              nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_BAD);
++                              if ((ret != -EUCLEAN) && (ret != -EBADMSG)) {
++                                      return ret;
++                              }
++                              else {
++                                      /* ecc verification fail, but data need to be returned. */
++                              }
++                      }
++                      else {
++                              printk(" read agian susccess \n");
++                      }
++              }
++
++              // oob read
++              if (oob && ooblen > 0) {
++                      len = nand_read_oob_buf(ra, oob, ooblen, ops->mode, ops->ooboffs);
++                      if (len < 0) {
++                              printk("nand_read_oob_buf: fail return %x \n", len);
++                              return -EINVAL;
++                      }
++
++                      oob += len;
++                      ops->oobretlen += len;
++                      ooblen -= len;
++              }
++
++              // data read
++              offs = addr & pagemask;
++              len = min_t(size_t, datalen, pagesize - offs);
++              if (data && len > 0) {
++                      memcpy(data, ra->buffers + offs, len);  // we can not sure ops->buf wether is DMA-able.
++
++                      data += len;
++                      datalen -= len;
++                      ops->retlen += len;
++                      if (ret)
++                              return ret;
++              }
++
++
++              nand_bbt_set(ra, addr >> ra->erase_shift, BBT_TAG_GOOD);
++              // address go further to next page, instead of increasing of length of write. This avoids some special cases wrong.
++              addr = (page+1) << ra->page_shift;
++      }
++      return 0;
++}
++
++static int
++ramtd_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++      struct ra_nand_chip *ra = (struct ra_nand_chip *)mtd->priv;
++      int ret;
++
++      ra_dbg("%s: start:%x, len:%x \n", __func__,
++              (unsigned int)instr->addr, (unsigned int)instr->len);
++
++      nand_get_device(ra, FL_ERASING);
++      ret = _nand_erase_nand((struct ra_nand_chip *)mtd->priv, instr);
++      nand_release_device(ra);
++
++      return ret;
++}
++
++static int
++ramtd_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
++              size_t *retlen, const uint8_t *buf)
++{
++      struct ra_nand_chip *ra = mtd->priv;
++      struct mtd_oob_ops ops;
++      int ret;
++
++      ra_dbg("%s: to 0x%x len=0x%x\n", __func__, to, len);
++
++      if ((to + len) > mtd->size)
++              return -EINVAL;
++
++      if (!len)
++              return 0;
++
++      nand_get_device(ra, FL_WRITING);
++
++      memset(&ops, 0, sizeof(ops));
++      ops.len = len;
++      ops.datbuf = (uint8_t *)buf;
++      ops.oobbuf = NULL;
++      ops.mode =  MTD_OPS_AUTO_OOB;
++
++      ret = nand_do_write_ops(ra, to, &ops);
++
++      *retlen = ops.retlen;
++
++      nand_release_device(ra);
++
++      return ret;
++}
++
++static int
++ramtd_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
++              size_t *retlen, uint8_t *buf)
++{
++
++      struct ra_nand_chip *ra = mtd->priv;
++      int ret;
++      struct mtd_oob_ops ops;
++
++      ra_dbg("%s: mtd:%p from:%x, len:%x, buf:%p \n", __func__, mtd, (unsigned int)from, len, buf);
++
++      /* Do not allow reads past end of device */
++      if ((from + len) > mtd->size)
++              return -EINVAL;
++      if (!len)
++              return 0;
++
++      nand_get_device(ra, FL_READING);
++
++      memset(&ops, 0, sizeof(ops));
++      ops.len = len;
++      ops.datbuf = buf;
++      ops.oobbuf = NULL;
++      ops.mode = MTD_OPS_AUTO_OOB;
++
++      ret = nand_do_read_ops(ra, from, &ops);
++
++      *retlen = ops.retlen;
++
++      nand_release_device(ra);
++
++      return ret;
++
++}
++
++static int
++ramtd_nand_readoob(struct mtd_info *mtd, loff_t from,
++                      struct mtd_oob_ops *ops)
++{
++      struct ra_nand_chip *ra = mtd->priv;
++      int ret;
++
++      ra_dbg("%s: \n", __func__);
++
++      nand_get_device(ra, FL_READING);
++
++      ret = nand_do_read_ops(ra, from, ops);
++
++      nand_release_device(ra);
++
++      return ret;
++}
++
++static int
++ramtd_nand_writeoob(struct mtd_info *mtd, loff_t to,
++                      struct mtd_oob_ops *ops)
++{
++      struct ra_nand_chip *ra = mtd->priv;
++      int ret;
++
++      nand_get_device(ra, FL_READING);
++      ret = nand_do_write_ops(ra, to, ops);
++      nand_release_device(ra);
++
++      return ret;
++}
++
++static int
++ramtd_nand_block_isbad(struct mtd_info *mtd, loff_t offs)
++{
++      if (offs > mtd->size)
++              return -EINVAL;
++
++      return nand_block_checkbad((struct ra_nand_chip *)mtd->priv, offs);
++}
++
++static int
++ramtd_nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++      struct ra_nand_chip *ra = mtd->priv;
++      int ret;
++
++      ra_dbg("%s: \n", __func__);
++      nand_get_device(ra, FL_WRITING);
++      ret = nand_block_markbad(ra, ofs);
++      nand_release_device(ra);
++
++      return ret;
++}
++
++// 1-bit error detection
++static int one_bit_correction(char *ecc1, char *ecc2, int *bytes, int *bits)
++{
++      // check if ecc and expected are all valid
++      char *p, nibble, crumb;
++      int i, xor, iecc1 = 0, iecc2 = 0;
++
++      printk("correction : %x %x %x\n", ecc1[0], ecc1[1], ecc1[2]);
++      printk("correction : %x %x %x\n", ecc2[0], ecc2[1], ecc2[2]);
++
++      p = (char *)ecc1;
++      for (i = 0; i < CONFIG_ECC_BYTES; i++)
++      {
++              nibble = *(p+i) & 0xf;
++              if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
++                      (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
++                      return -1;
++              nibble = ((*(p+i)) >> 4) & 0xf;
++              if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
++                      (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
++                      return -1;
++      }
++
++      p = (char *)ecc2;
++      for (i = 0; i < CONFIG_ECC_BYTES; i++)
++      {
++              nibble = *(p+i) & 0xf;
++              if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
++                      (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
++                      return -1;
++              nibble = ((*(p+i)) >> 4) & 0xf;
++              if ((nibble != 0x0) && (nibble != 0xf) && (nibble != 0x3) && (nibble != 0xc) &&
++                      (nibble != 0x5) && (nibble != 0xa) && (nibble != 0x6) && (nibble != 0x9))
++                      return -1;
++      }
++
++      memcpy(&iecc1, ecc1, 3);
++      memcpy(&iecc2, ecc2, 3);
++
++      xor = iecc1 ^ iecc2;
++      printk("xor = %x (%x %x)\n", xor, iecc1, iecc2);
++
++      *bytes = 0;
++      for (i = 0; i < 9; i++)
++      {
++              crumb = (xor >> (2*i)) & 0x3;
++              if ((crumb == 0x0) || (crumb == 0x3))
++                      return -1;
++              if (crumb == 0x2)
++                      *bytes += (1 << i);
++      }
++
++      *bits = 0;
++      for (i = 0; i < 3; i++)
++      {
++              crumb = (xor >> (18 + 2*i)) & 0x3;
++              if ((crumb == 0x0) || (crumb == 0x3))
++                      return -1;
++              if (crumb == 0x2)
++                      *bits += (1 << i);
++      }
++
++      return 0;
++}
++
++
++
++/************************************************************
++ * the init/exit section.
++ */
++
++static struct nand_ecclayout ra_oob_layout = {
++      .eccbytes = CONFIG_ECC_BYTES,
++      .eccpos = {5, 6, 7},
++      .oobfree = {
++               {.offset = 0, .length = 4},
++               {.offset = 8, .length = 8},
++               {.offset = 0, .length = 0}
++       },
++#define RA_CHIP_OOB_AVAIL (4+8)
++      .oobavail = RA_CHIP_OOB_AVAIL,
++      // 5th byte is bad-block flag.
++};
++
++static int
++mtk_nand_probe(struct platform_device *pdev)
++{
++        struct mtd_part_parser_data ppdata;
++      struct ra_nand_chip *ra;
++      int alloc_size, bbt_size, buffers_size, reg, err;
++      unsigned char chip_mode = 12;
++
++/*    if(ra_check_flash_type()!=BOOT_FROM_NAND) {
++              return 0;
++      }*/
++
++      //FIXME: config 512 or 2048-byte page according to HWCONF
++#if defined (CONFIG_RALINK_RT6855A)
++      reg = ra_inl(RALINK_SYSCTL_BASE+0x8c);
++      chip_mode = ((reg>>28) & 0x3)|(((reg>>22) & 0x3)<<2);
++      if (chip_mode == 1) {
++              printk("! nand 2048\n");
++              ra_or(NFC_CONF1, 1);
++              is_nand_page_2048 = 1;
++              nand_addrlen = 5;
++      }
++      else {
++              printk("! nand 512\n");
++              ra_and(NFC_CONF1, ~1);
++              is_nand_page_2048 = 0;
++              nand_addrlen = 4;
++      }       
++#elif (defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_RT6855))
++      ra_outl(RALINK_SYSCTL_BASE+0x60, ra_inl(RALINK_SYSCTL_BASE+0x60) & ~(0x3<<18));
++      reg = ra_inl(RALINK_SYSCTL_BASE+0x10);
++      chip_mode = (reg & 0x0F);
++      if((chip_mode==1)||(chip_mode==11)) {
++              ra_or(NFC_CONF1, 1);
++              is_nand_page_2048 = 1;
++              nand_addrlen = ((chip_mode!=11) ? 4 : 5);
++              printk("!!! nand page size = 2048, addr len=%d\n", nand_addrlen);
++      }
++      else {
++              ra_and(NFC_CONF1, ~1);
++              is_nand_page_2048 = 0;
++              nand_addrlen = ((chip_mode!=10) ? 3 : 4);
++              printk("!!! nand page size = 512, addr len=%d\n", nand_addrlen);
++      }                       
++#else
++      is_nand_page_2048 = 0;
++      nand_addrlen = 3;
++      printk("!!! nand page size = 512, addr len=%d\n", nand_addrlen);
++#endif                        
++
++#if defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_RT6855) 
++      //config ECC location
++    ra_and(NFC_CONF1, 0xfff000ff);
++      ra_or(NFC_CONF1, ((CONFIG_ECC_OFFSET + 2) << 16) +
++                                              ((CONFIG_ECC_OFFSET + 1) << 12) +
++                                              (CONFIG_ECC_OFFSET << 8));
++#endif
++
++#define ALIGNE_16(a) (((unsigned long)(a)+15) & ~15)
++      buffers_size = ALIGNE_16((1<<CONFIG_PAGE_SIZE_BIT) + (1<<CONFIG_OOBSIZE_PER_PAGE_BIT)); //ra->buffers
++      bbt_size = BBTTAG_BITS * (1<<(CONFIG_CHIP_SIZE_BIT - (CONFIG_PAGE_SIZE_BIT + CONFIG_NUMPAGE_PER_BLOCK_BIT))) / 8; //ra->bbt
++      bbt_size = ALIGNE_16(bbt_size);
++
++      alloc_size = buffers_size + bbt_size;
++      alloc_size += buffers_size; //for ra->readback_buffers
++      alloc_size += sizeof(*ra); 
++      alloc_size += sizeof(*ranfc_mtd);
++
++      //make sure gpio-0 is input
++      ra_outl(RALINK_PIO_BASE+0x24, ra_inl(RALINK_PIO_BASE+0x24) & ~0x01);
++
++      ra = (struct ra_nand_chip *)kzalloc(alloc_size, GFP_KERNEL | GFP_DMA);
++      if (!ra) {
++              printk("%s: mem alloc fail \n", __func__);
++              return -ENOMEM;
++      }
++      memset(ra, 0, alloc_size);
++
++      //dynamic
++      ra->buffers = (char *)((char *)ra + sizeof(*ra));
++      ra->readback_buffers = ra->buffers + buffers_size; 
++      ra->bbt = ra->readback_buffers + buffers_size; 
++      ranfc_mtd = (struct mtd_info *)(ra->bbt + bbt_size);
++
++      //static 
++      ra->numchips            = CONFIG_NUMCHIPS;
++      ra->chip_shift          = CONFIG_CHIP_SIZE_BIT;
++      ra->page_shift          = CONFIG_PAGE_SIZE_BIT;
++      ra->oob_shift           = CONFIG_OOBSIZE_PER_PAGE_BIT;
++      ra->erase_shift         = (CONFIG_PAGE_SIZE_BIT + CONFIG_NUMPAGE_PER_BLOCK_BIT);
++      ra->badblockpos        &nb