aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/lantiq
diff options
context:
space:
mode:
authorJohn Crispin <blogic@openwrt.org>2012-12-15 01:59:45 +0000
committerJohn Crispin <blogic@openwrt.org>2012-12-15 01:59:45 +0000
commit48db0765a608660ca54014e7b579c9de7b423590 (patch)
treeb01c98dfee8ccdd18862f3049d7dfdcca7828c3a /target/linux/lantiq
parent39d02a1398afb88290273276c545a0e9c267f69b (diff)
downloadupstream-48db0765a608660ca54014e7b579c9de7b423590.tar.gz
upstream-48db0765a608660ca54014e7b579c9de7b423590.tar.bz2
upstream-48db0765a608660ca54014e7b579c9de7b423590.zip
[lantiq] add linux-v3.7
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34687 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/lantiq')
-rw-r--r--target/linux/lantiq/Makefile4
-rw-r--r--target/linux/lantiq/ase/config-default10
-rw-r--r--target/linux/lantiq/config-3.7165
-rw-r--r--target/linux/lantiq/falcon/config-default15
-rw-r--r--target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy11g_a1x.binbin0 -> 65536 bytes
-rw-r--r--target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy11g_a2x.binbin0 -> 65536 bytes
-rw-r--r--target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy22f_a1x.binbin0 -> 65536 bytes
-rw-r--r--target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy22f_a2x.binbin0 -> 65536 bytes
-rw-r--r--target/linux/lantiq/image/Makefile4
-rw-r--r--target/linux/lantiq/patches-3.7/0001-MIPS-lantiq-unbreak-devicetree-init.patch41
-rw-r--r--target/linux/lantiq/patches-3.7/0002-MIPS-lantiq-fix-bootselect-bits-on-XRX200-SoC.patch71
-rw-r--r--target/linux/lantiq/patches-3.7/0003-MIPS-lantiq-verbose-init-of-dma-core.patch50
-rw-r--r--target/linux/lantiq/patches-3.7/0004-MIPS-lantiq-adds-xrx200-ethernet-clock-definition.patch29
-rw-r--r--target/linux/lantiq/patches-3.7/0005-MIPS-lantiq-adds-code-for-booting-GPHY.patch89
-rw-r--r--target/linux/lantiq/patches-3.7/0006-MIPS-lantiq-adds-GPHY-firmware-loader.patch144
-rw-r--r--target/linux/lantiq/patches-3.7/0100-MIPS-lantiq-honour-model-property-inside-devicetree-.patch59
-rw-r--r--target/linux/lantiq/patches-3.7/0101-MIPS-lantiq-adds-support-for-SVIP-SoC-Family.patch439
-rw-r--r--target/linux/lantiq/patches-3.7/0102-MIPS-lantiq-add-GPHY-clock-gate-bits.patch52
-rw-r--r--target/linux/lantiq/patches-3.7/0103-MIPS-lantiq-adds-static-clock-for-PP32.patch219
-rw-r--r--target/linux/lantiq/patches-3.7/0104-MIPS-lantiq-adds-4dword-burst-length-for-dma.patch34
-rw-r--r--target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch214
-rw-r--r--target/linux/lantiq/patches-3.7/0106-MIPS-lantiq-adds-minimal-dcdc-driver.patch106
-rw-r--r--target/linux/lantiq/patches-3.7/0107-PINCTRL-lantiq-pinconf-uses-port-instead-of-pin.patch92
-rw-r--r--target/linux/lantiq/patches-3.7/0108-PINCTRL-lantiq-fixes.patch281
-rw-r--r--target/linux/lantiq/patches-3.7/0109-GPIO-MIPS-add-gpio-driver-for-falcon-SoC.patch404
-rw-r--r--target/linux/lantiq/patches-3.7/0110-Document-devicetree-add-OF-documents-for-lantiq-seri.patch39
-rw-r--r--target/linux/lantiq/patches-3.7/0111-MTD-MIPS-lantiq-Add-NAND-support-on-Lantiq-FALCON-So.patch139
-rw-r--r--target/linux/lantiq/patches-3.7/0112-MTD-lantiq-xway-fix-NAND-reset-timeout-handling.patch47
-rw-r--r--target/linux/lantiq/patches-3.7/0113-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch1047
-rw-r--r--target/linux/lantiq/patches-3.7/0114-SPI-MIPS-lantiq-adds-spi-xway.patch1033
-rw-r--r--target/linux/lantiq/patches-3.7/0115-NET-PHY-adds-driver-for-lantiq-PHY11G.patch228
-rw-r--r--target/linux/lantiq/patches-3.7/0116-NET-MIPS-lantiq-update-etop-driver-for-devicetree.patch807
-rw-r--r--target/linux/lantiq/patches-3.7/0117-NET-MIPS-lantiq-adds-xrx200-net.patch1414
-rw-r--r--target/linux/lantiq/patches-3.7/0118-owrt-adds-PHY11G-firmware-blobs.patch2221
-rw-r--r--target/linux/lantiq/patches-3.7/0119-owrt-ATM-adds-lantiq-specific-hacks.patch508
-rw-r--r--target/linux/lantiq/patches-3.7/0120-owrt-generic-dtb-image-hack.patch26
-rw-r--r--target/linux/lantiq/patches-3.7/0121-owrt-lantiq-dtb-image-hack.patch44
-rw-r--r--target/linux/lantiq/patches-3.7/0122-MIPS-lantiq-adds-pcie-driver.patch4786
-rw-r--r--target/linux/lantiq/patches-3.7/0123-USB-fix-roothub-for-IFXHCD.patch34
-rw-r--r--target/linux/lantiq/patches-3.7/0124-pci_fix.patch22
-rw-r--r--target/linux/lantiq/patches-3.7/0300-owrt-mtd-split.patch230
-rw-r--r--target/linux/lantiq/patches-3.7/0301-gptu.path1049
-rw-r--r--target/linux/lantiq/patches-3.7/0302-wifi-eep.patch319
-rw-r--r--target/linux/lantiq/patches-3.7/0303-vmmc.patch79
-rw-r--r--target/linux/lantiq/xway/config-default15
-rw-r--r--target/linux/lantiq/xway/profiles/arv.mk85
-rw-r--r--target/linux/lantiq/xway/profiles/avm.mk10
-rw-r--r--target/linux/lantiq/xway/profiles/lantiq.mk22
-rw-r--r--target/linux/lantiq/xway/profiles/netgear.mk21
-rw-r--r--target/linux/lantiq/xway/target.mk2
50 files changed, 16717 insertions, 32 deletions
diff --git a/target/linux/lantiq/Makefile b/target/linux/lantiq/Makefile
index 1ab6dea1b3..a8e61709ba 100644
--- a/target/linux/lantiq/Makefile
+++ b/target/linux/lantiq/Makefile
@@ -12,8 +12,8 @@ FEATURES:=squashfs jffs2
SUBTARGETS:=danube ar9 vr9 falcon svip_be
LINUX_VERSION:=3.3.8
-#SUBTARGETS=xway ase
-#LINUX_VERSION:=3.6.10
+SUBTARGETS=xway ase falcon
+LINUX_VERSION:=3.7-rc8
CFLAGS=-Os -pipe -mips32r2 -mtune=mips32r2 -fno-caller-saves
diff --git a/target/linux/lantiq/ase/config-default b/target/linux/lantiq/ase/config-default
index 48e9093287..79b559592a 100644
--- a/target/linux/lantiq/ase/config-default
+++ b/target/linux/lantiq/ase/config-default
@@ -1,11 +1,19 @@
+CONFIG_AR8216_PHY=y
CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_POLLDEV=y
# CONFIG_ISDN is not set
+# CONFIG_LANTIQ_PHY is not set
+# CONFIG_M25PXX_USE_FAST_READ is not set
+CONFIG_MTD_M25P80=y
+# CONFIG_RTL8366_SMI is not set
CONFIG_SOC_AMAZON_SE=y
# CONFIG_SOC_XWAY is not set
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_XWAY=y
# CONFIG_USB_ARCH_HAS_EHCI is not set
-# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
# CONFIG_USB_ARCH_HAS_XHCI is not set
CONFIG_USB_SUPPORT=y
diff --git a/target/linux/lantiq/config-3.7 b/target/linux/lantiq/config-3.7
new file mode 100644
index 0000000000..d4591cbea7
--- /dev/null
+++ b/target/linux/lantiq/config-3.7
@@ -0,0 +1,165 @@
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_CEVT_R4K=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R2=y
+CONFIG_CPU_MIPSR2=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CSRC_R4K=y
+CONFIG_CSRC_R4K_LIB=y
+# CONFIG_DEBUG_PINCTRL is not set
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DTC=y
+CONFIG_DT_EASY50712=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_ETHERNET_PACKET_MANGLE=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_MM_LANTIQ=y
+CONFIG_GPIO_STP_XWAY=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=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_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_HAVE_MACH_CLKDEV=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HW_HAS_PCI=y
+CONFIG_HW_RANDOM=y
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQ_CPU=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_LANTIQ=y
+CONFIG_LANTIQ_ETOP=y
+CONFIG_LANTIQ_PHY=y
+CONFIG_LANTIQ_WDT=y
+CONFIG_LANTIQ_XRX200=y
+CONFIG_LEDS_GPIO=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MIPS=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+# CONFIG_MIPS_MACHINE is not set
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+# CONFIG_MIPS_SEAD3 is not set
+# CONFIG_MIPS_VPE_LOADER is not set
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_LANTIQ=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_UIMAGE_SPLIT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEED_PER_CPU_KM=y
+CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_DEVICE=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_PCIE_LANTIQ is not set
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_LANTIQ=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PHYLIB=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_EXYNOS4 is not set
+CONFIG_PINCTRL_LANTIQ=y
+# CONFIG_PINCTRL_SAMSUNG is not set
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_PINCTRL_XWAY=y
+CONFIG_PINMUX=y
+# CONFIG_PREEMPT_RCU is not set
+CONFIG_PROC_DEVICETREE=y
+CONFIG_PSB6970_PHY=y
+CONFIG_RTL8366RB_PHY=y
+CONFIG_RTL8366_SMI=y
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_LANTIQ=y
+# CONFIG_SOC_AMAZON_SE is not set
+# CONFIG_SOC_FALCON is not set
+# CONFIG_SOC_SVIP is not set
+CONFIG_SOC_TYPE_XWAY=y
+CONFIG_SOC_XWAY=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_SWCONFIG=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_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_MULTITHREADING=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_UIDGID_CONVERTED=y
+CONFIG_USB_ARCH_HAS_XHCI=y
+CONFIG_USE_OF=y
+CONFIG_XRX200_PHY_FW=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/lantiq/falcon/config-default b/target/linux/lantiq/falcon/config-default
index b12bdd835d..88a6f3c5f0 100644
--- a/target/linux/lantiq/falcon/config-default
+++ b/target/linux/lantiq/falcon/config-default
@@ -1,20 +1,19 @@
-# CONFIG_ATMEL_PWM is not set
-CONFIG_CLKDEV_LOOKUP=y
-CONFIG_FSNOTIFY=y
-CONFIG_HAVE_MACH_CLKDEV=y
-CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_GPIO_FALCON=y
+CONFIG_GPIO_GENERIC=y
CONFIG_M25PXX_USE_FAST_READ=y
-CONFIG_MDIO_BOARDINFO=y
CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_FALCON=y
CONFIG_MTD_NAND_PLATFORM=y
# CONFIG_MTD_SM_COMMON is not set
-# CONFIG_SOC_AMAZON_SE is not set
+CONFIG_PINCTRL_FALCON=y
CONFIG_SOC_FALCON=y
-# CONFIG_SOC_SVIP is not set
# CONFIG_SOC_TYPE_XWAY is not set
# CONFIG_SOC_XWAY is not set
CONFIG_SPI=y
CONFIG_SPI_FALCON=y
CONFIG_SPI_MASTER=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_XHCI is not set
diff --git a/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy11g_a1x.bin b/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy11g_a1x.bin
new file mode 100644
index 0000000000..cdf3d30634
--- /dev/null
+++ b/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy11g_a1x.bin
Binary files differ
diff --git a/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy11g_a2x.bin b/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy11g_a2x.bin
new file mode 100644
index 0000000000..44fc39ef06
--- /dev/null
+++ b/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy11g_a2x.bin
Binary files differ
diff --git a/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy22f_a1x.bin b/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy22f_a1x.bin
new file mode 100644
index 0000000000..02b88a078b
--- /dev/null
+++ b/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy22f_a1x.bin
Binary files differ
diff --git a/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy22f_a2x.bin b/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy22f_a2x.bin
new file mode 100644
index 0000000000..1fed6ad65e
--- /dev/null
+++ b/target/linux/lantiq/files-3.7/firmware/lantiq/vr9_phy22f_a2x.bin
Binary files differ
diff --git a/target/linux/lantiq/image/Makefile b/target/linux/lantiq/image/Makefile
index ef289823dd..f0f4d4f8ed 100644
--- a/target/linux/lantiq/image/Makefile
+++ b/target/linux/lantiq/image/Makefile
@@ -21,12 +21,8 @@ endef
define PatchKernelLzma
cp $(KDIR)/vmlinux $(KDIR)/vmlinux-$(1)
-ifeq ($(CONFIG_LINUX_3_6),y)
$(LINUX_DIR)/scripts/dtc/dtc -O dtb -o $(KDIR)/$(1).dtb ./$(1).dts
$(STAGING_DIR_HOST)/bin/patch-dtb $(KDIR)/vmlinux-$(1) $(KDIR)/$(1).dtb
-else
- $(STAGING_DIR_HOST)/bin/patch-cmdline $(KDIR)/vmlinux-$(1) '$(strip $(2))'
-endif
$(call CompressLzma,$(KDIR)/vmlinux-$(1),$(KDIR)/vmlinux-$(1).lzma)
endef
diff --git a/target/linux/lantiq/patches-3.7/0001-MIPS-lantiq-unbreak-devicetree-init.patch b/target/linux/lantiq/patches-3.7/0001-MIPS-lantiq-unbreak-devicetree-init.patch
new file mode 100644
index 0000000000..e3ffdc1902
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0001-MIPS-lantiq-unbreak-devicetree-init.patch
@@ -0,0 +1,41 @@
+From a15d129a352e5f6ab821b81bc3f692ecc952a815 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 9 Nov 2012 12:09:57 +0100
+Subject: [PATCH 1/6] MIPS: lantiq: unbreak devicetree init
+
+The bootmem was incorrectly freed resulting in lots of dangling pointers.
+Additionally we should use of_platform_populate() as the Documentaion tells us
+to do so.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Patchwork: http://patchwork.linux-mips.org/patch/4518
+---
+ arch/mips/lantiq/prom.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
+index 6cfd611..9f9e875 100644
+--- a/arch/mips/lantiq/prom.c
++++ b/arch/mips/lantiq/prom.c
+@@ -87,9 +87,6 @@ void __init device_tree_init(void)
+ reserve_bootmem(base, size, BOOTMEM_DEFAULT);
+
+ unflatten_device_tree();
+-
+- /* free the space reserved for the dt blob */
+- free_bootmem(base, size);
+ }
+
+ void __init prom_init(void)
+@@ -119,7 +116,7 @@ int __init plat_of_setup(void)
+ sizeof(of_ids[0].compatible));
+ strncpy(of_ids[1].compatible, "simple-bus",
+ sizeof(of_ids[1].compatible));
+- return of_platform_bus_probe(NULL, of_ids, NULL);
++ return of_platform_populate(NULL, of_ids, NULL, NULL);
+ }
+
+ arch_initcall(plat_of_setup);
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0002-MIPS-lantiq-fix-bootselect-bits-on-XRX200-SoC.patch b/target/linux/lantiq/patches-3.7/0002-MIPS-lantiq-fix-bootselect-bits-on-XRX200-SoC.patch
new file mode 100644
index 0000000000..2a305b4afe
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0002-MIPS-lantiq-fix-bootselect-bits-on-XRX200-SoC.patch
@@ -0,0 +1,71 @@
+From 15753b6586710d788f36cfd5fbb98d0805b390ab Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 9 Nov 2012 13:31:51 +0100
+Subject: [PATCH 2/6] MIPS: lantiq: fix bootselect bits on XRX200 SoC
+
+The XRX200 SoC family has a different register layout for reading the boot
+selection bits.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Patchwork: http://patchwork.linux-mips.org/patch/4519
+---
+ arch/mips/lantiq/xway/reset.c | 22 +++++++++++++++-------
+ 1 file changed, 15 insertions(+), 7 deletions(-)
+
+diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
+index 22c55f7..2799212 100644
+--- a/arch/mips/lantiq/xway/reset.c
++++ b/arch/mips/lantiq/xway/reset.c
+@@ -34,11 +34,12 @@
+ /* reset cause */
+ #define RCU_STAT_SHIFT 26
+ /* boot selection */
+-#define RCU_BOOT_SEL_SHIFT 26
+-#define RCU_BOOT_SEL_MASK 0x7
++#define RCU_BOOT_SEL(x) ((x >> 18) & 0x7)
++#define RCU_BOOT_SEL_XRX200(x) (((x >> 17) & 0xf) | ((x >> 8) & 0x10))
+
+ /* remapped base addr of the reset control unit */
+ static void __iomem *ltq_rcu_membase;
++static struct device_node *ltq_rcu_np;
+
+ /* This function is used by the watchdog driver */
+ int ltq_reset_cause(void)
+@@ -52,7 +53,11 @@ EXPORT_SYMBOL_GPL(ltq_reset_cause);
+ unsigned char ltq_boot_select(void)
+ {
+ u32 val = ltq_rcu_r32(RCU_RST_STAT);
+- return (val >> RCU_BOOT_SEL_SHIFT) & RCU_BOOT_SEL_MASK;
++
++ if (of_device_is_compatible(ltq_rcu_np, "lantiq,rcu-xrx200"))
++ return RCU_BOOT_SEL_XRX200(val);
++
++ return RCU_BOOT_SEL(val);
+ }
+
+ /* reset a io domain for u micro seconds */
+@@ -85,14 +90,17 @@ static void ltq_machine_power_off(void)
+ static int __init mips_reboot_setup(void)
+ {
+ struct resource res;
+- struct device_node *np =
+- of_find_compatible_node(NULL, NULL, "lantiq,rcu-xway");
++
++ ltq_rcu_np = of_find_compatible_node(NULL, NULL, "lantiq,rcu-xway");
++ if (!ltq_rcu_np)
++ ltq_rcu_np = of_find_compatible_node(NULL, NULL,
++ "lantiq,rcu-xrx200");
+
+ /* check if all the reset register range is available */
+- if (!np)
++ if (!ltq_rcu_np)
+ panic("Failed to load reset resources from devicetree");
+
+- if (of_address_to_resource(np, 0, &res))
++ if (of_address_to_resource(ltq_rcu_np, 0, &res))
+ panic("Failed to get rcu memory range");
+
+ if (request_mem_region(res.start, resource_size(&res), res.name) < 0)
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0003-MIPS-lantiq-verbose-init-of-dma-core.patch b/target/linux/lantiq/patches-3.7/0003-MIPS-lantiq-verbose-init-of-dma-core.patch
new file mode 100644
index 0000000000..597cbc6f08
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0003-MIPS-lantiq-verbose-init-of-dma-core.patch
@@ -0,0 +1,50 @@
+From b8b3acbe6077b4736f641ec445be8a42cdd1f08b Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 9 Nov 2012 12:16:14 +0100
+Subject: [PATCH 3/6] MIPS: lantiq: verbose init of dma core
+
+Print the hardware revision and port/channel info when starting the dma core.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Patchwork: http://patchwork.linux-mips.org/patch/4520
+---
+ arch/mips/lantiq/xway/dma.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
+index 55d2c4f..b5d76d1 100644
+--- a/arch/mips/lantiq/xway/dma.c
++++ b/arch/mips/lantiq/xway/dma.c
+@@ -25,6 +25,7 @@
+ #include <lantiq_soc.h>
+ #include <xway_dma.h>
+
++#define LTQ_DMA_ID 0x08
+ #define LTQ_DMA_CTRL 0x10
+ #define LTQ_DMA_CPOLL 0x14
+ #define LTQ_DMA_CS 0x18
+@@ -214,6 +215,7 @@ ltq_dma_init(struct platform_device *pdev)
+ {
+ struct clk *clk;
+ struct resource *res;
++ unsigned id;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -243,7 +245,12 @@ ltq_dma_init(struct platform_device *pdev)
+ ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+ }
+- dev_info(&pdev->dev, "init done\n");
++
++ id = ltq_dma_r32(LTQ_DMA_ID);
++ dev_info(&pdev->dev,
++ "Init done - hw rev: %X, ports: %d, channels: %d\n",
++ id & 0x1f, (id >> 16) & 0xf, id >> 20);
++
+ return 0;
+ }
+
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0004-MIPS-lantiq-adds-xrx200-ethernet-clock-definition.patch b/target/linux/lantiq/patches-3.7/0004-MIPS-lantiq-adds-xrx200-ethernet-clock-definition.patch
new file mode 100644
index 0000000000..771dd4f1b4
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0004-MIPS-lantiq-adds-xrx200-ethernet-clock-definition.patch
@@ -0,0 +1,29 @@
+From f2bbe41c507b475c6f0ae1fca69c7aac6d31d228 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 9 Nov 2012 13:34:18 +0100
+Subject: [PATCH 4/6] MIPS: lantiq: adds xrx200 ethernet clock definition
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Patchwork: http://patchwork.linux-mips.org/patch/4521
+---
+ arch/mips/lantiq/xway/sysctrl.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
+index 2917b56..3925e66 100644
+--- a/arch/mips/lantiq/xway/sysctrl.c
++++ b/arch/mips/lantiq/xway/sysctrl.c
+@@ -370,6 +370,10 @@ void __init ltq_soc_init(void)
+ clkdev_add_pmu("1d900000.pcie", "pdi", 1, PMU1_PCIE_PDI);
+ clkdev_add_pmu("1d900000.pcie", "ctl", 1, PMU1_PCIE_CTL);
+ clkdev_add_pmu("1d900000.pcie", "ahb", 0, PMU_AHBM | PMU_AHBS);
++ clkdev_add_pmu("1e108000.eth", NULL, 0,
++ PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
++ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
++ PMU_PPE_QSB | PMU_PPE_TOP);
+ } else if (of_machine_is_compatible("lantiq,ar9")) {
+ clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
+ ltq_ar9_fpi_hz());
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0005-MIPS-lantiq-adds-code-for-booting-GPHY.patch b/target/linux/lantiq/patches-3.7/0005-MIPS-lantiq-adds-code-for-booting-GPHY.patch
new file mode 100644
index 0000000000..84aa965231
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0005-MIPS-lantiq-adds-code-for-booting-GPHY.patch
@@ -0,0 +1,89 @@
+From af14a456c58c153c6d761e6c0af48157692b52ad Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 9 Nov 2012 13:43:30 +0100
+Subject: [PATCH 5/6] MIPS: lantiq: adds code for booting GPHY
+
+The XRX200 family of SoCs has embedded gigabit PHYs. This patch adds code to
+boot them up.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Patchwork: http://patchwork.linux-mips.org/patch/4522
+---
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 ++
+ arch/mips/lantiq/xway/reset.c | 36 ++++++++++++++++++++
+ 2 files changed, 39 insertions(+)
+
+diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+index 6a2df70..133336b 100644
+--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+@@ -82,6 +82,9 @@ extern __iomem void *ltq_cgu_membase;
+ #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000)
+ #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344))
+
++/* allow booting xrx200 phys */
++int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr);
++
+ /* request a non-gpio and set the PIO config */
+ #define PMU_PPE BIT(13)
+ extern void ltq_pmu_enable(unsigned int module);
+diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
+index 2799212..544dbb7 100644
+--- a/arch/mips/lantiq/xway/reset.c
++++ b/arch/mips/lantiq/xway/reset.c
+@@ -28,9 +28,15 @@
+ #define RCU_RST_REQ 0x0010
+ /* reset status register */
+ #define RCU_RST_STAT 0x0014
++/* vr9 gphy registers */
++#define RCU_GFS_ADD0_XRX200 0x0020
++#define RCU_GFS_ADD1_XRX200 0x0068
+
+ /* reboot bit */
++#define RCU_RD_GPHY0_XRX200 BIT(31)
+ #define RCU_RD_SRST BIT(30)
++#define RCU_RD_GPHY1_XRX200 BIT(29)
++
+ /* reset cause */
+ #define RCU_STAT_SHIFT 26
+ /* boot selection */
+@@ -60,6 +66,36 @@ unsigned char ltq_boot_select(void)
+ return RCU_BOOT_SEL(val);
+ }
+
++/* reset / boot a gphy */
++static struct ltq_xrx200_gphy_reset {
++ u32 rd;
++ u32 addr;
++} xrx200_gphy[] = {
++ {RCU_RD_GPHY0_XRX200, RCU_GFS_ADD0_XRX200},
++ {RCU_RD_GPHY1_XRX200, RCU_GFS_ADD1_XRX200},
++};
++
++/* reset and boot a gphy. these phys only exist on xrx200 SoC */
++int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr)
++{
++ if (!of_device_is_compatible(ltq_rcu_np, "lantiq,rcu-xrx200")) {
++ dev_err(dev, "this SoC has no GPHY\n");
++ return -EINVAL;
++ }
++ if (id > 1) {
++ dev_err(dev, "%u is an invalid gphy id\n", id);
++ return -EINVAL;
++ }
++ dev_info(dev, "booting GPHY%u firmware at %X\n", id, dev_addr);
++
++ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | xrx200_gphy[id].rd,
++ RCU_RST_REQ);
++ ltq_rcu_w32(dev_addr, xrx200_gphy[id].addr);
++ ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~xrx200_gphy[id].rd,
++ RCU_RST_REQ);
++ return 0;
++}
++
+ /* reset a io domain for u micro seconds */
+ void ltq_reset_once(unsigned int module, ulong u)
+ {
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0006-MIPS-lantiq-adds-GPHY-firmware-loader.patch b/target/linux/lantiq/patches-3.7/0006-MIPS-lantiq-adds-GPHY-firmware-loader.patch
new file mode 100644
index 0000000000..56e43d552a
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0006-MIPS-lantiq-adds-GPHY-firmware-loader.patch
@@ -0,0 +1,144 @@
+From 0224cde212df4abf251f89c3724a800b1949a774 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 22 Oct 2012 07:52:50 +0200
+Subject: [PATCH 6/6] MIPS: lantiq: adds GPHY firmware loader
+
+The internal GPHYs need a firmware blob to function properly. This patch adds
+the code needed to request the blob and load it to the PHY.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Patchwork: http://patchwork.linux-mips.org/patch/4523
+---
+ arch/mips/lantiq/Kconfig | 4 ++
+ arch/mips/lantiq/xway/Makefile | 2 +
+ arch/mips/lantiq/xway/xrx200_phy_fw.c | 97 +++++++++++++++++++++++++++++++++
+ 3 files changed, 103 insertions(+)
+ create mode 100644 arch/mips/lantiq/xway/xrx200_phy_fw.c
+
+diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
+index d84f361..c002191 100644
+--- a/arch/mips/lantiq/Kconfig
++++ b/arch/mips/lantiq/Kconfig
+@@ -36,4 +36,8 @@ config PCI_LANTIQ
+ bool "PCI Support"
+ depends on SOC_XWAY && PCI
+
++config XRX200_PHY_FW
++ bool "XRX200 PHY firmware loader"
++ depends on SOC_XWAY
++
+ endif
+diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
+index 70a58c7..7a13660 100644
+--- a/arch/mips/lantiq/xway/Makefile
++++ b/arch/mips/lantiq/xway/Makefile
+@@ -1 +1,3 @@
+ obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o
++
++obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o
+diff --git a/arch/mips/lantiq/xway/xrx200_phy_fw.c b/arch/mips/lantiq/xway/xrx200_phy_fw.c
+new file mode 100644
+index 0000000..fe808bf
+--- /dev/null
++++ b/arch/mips/lantiq/xway/xrx200_phy_fw.c
+@@ -0,0 +1,97 @@
++/*
++ * 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) 2012 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/module.h>
++#include <linux/firmware.h>
++#include <linux/of_platform.h>
++
++#include <lantiq_soc.h>
++
++#define XRX200_GPHY_FW_ALIGN (16 * 1024)
++
++static dma_addr_t xway_gphy_load(struct platform_device *pdev)
++{
++ const struct firmware *fw;
++ dma_addr_t dev_addr = 0;
++ const char *fw_name;
++ void *fw_addr;
++ size_t size;
++
++ if (of_property_read_string(pdev->dev.of_node, "firmware", &fw_name)) {
++ dev_err(&pdev->dev, "failed to load firmware filename\n");
++ return 0;
++ }
++
++ dev_info(&pdev->dev, "requesting %s\n", fw_name);
++ if (request_firmware(&fw, fw_name, &pdev->dev)) {
++ dev_err(&pdev->dev, "failed to load firmware: %s\n", fw_name);
++ return 0;
++ }
++
++ /*
++ * GPHY cores need the firmware code in a persistent and contiguous
++ * memory area with a 16 kB boundary aligned start address
++ */
++ size = fw->size + XRX200_GPHY_FW_ALIGN;
++
++ fw_addr = dma_alloc_coherent(&pdev->dev, size, &dev_addr, GFP_KERNEL);
++ if (fw_addr) {
++ fw_addr = PTR_ALIGN(fw_addr, XRX200_GPHY_FW_ALIGN);
++ dev_addr = ALIGN(dev_addr, XRX200_GPHY_FW_ALIGN);
++ memcpy(fw_addr, fw->data, fw->size);
++ } else {
++ dev_err(&pdev->dev, "failed to alloc firmware memory\n");
++ }
++
++ release_firmware(fw);
++ return dev_addr;
++}
++
++static int __devinit xway_phy_fw_probe(struct platform_device *pdev)
++{
++ dma_addr_t fw_addr;
++ struct property *pp;
++ unsigned char *phyids;
++ int i, ret = 0;
++
++ fw_addr = xway_gphy_load(pdev);
++ if (!fw_addr)
++ return -EINVAL;
++ pp = of_find_property(pdev->dev.of_node, "phys", NULL);
++ if (!pp)
++ return -ENOENT;
++ phyids = pp->value;
++ for (i = 0; i < pp->length && !ret; i++)
++ ret = xrx200_gphy_boot(&pdev->dev, phyids[i], fw_addr);
++ if (!ret)
++ mdelay(100);
++ return ret;
++}
++
++static const struct of_device_id xway_phy_match[] = {
++ { .compatible = "lantiq,phy-xrx200" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, xway_phy_match);
++
++static struct platform_driver xway_phy_driver = {
++ .probe = xway_phy_fw_probe,
++ .driver = {
++ .name = "phy-xrx200",
++ .owner = THIS_MODULE,
++ .of_match_table = xway_phy_match,
++ },
++};
++
++module_platform_driver(xway_phy_driver);
++
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_DESCRIPTION("Lantiq XRX200 PHY Firmware Loader");
++MODULE_LICENSE("GPL");
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0100-MIPS-lantiq-honour-model-property-inside-devicetree-.patch b/target/linux/lantiq/patches-3.7/0100-MIPS-lantiq-honour-model-property-inside-devicetree-.patch
new file mode 100644
index 0000000000..cef266fbc9
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0100-MIPS-lantiq-honour-model-property-inside-devicetree-.patch
@@ -0,0 +1,59 @@
+From 60bc3043590bf74ca1c9dd88a4e5f28a40d5b348 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 6 Dec 2012 10:26:05 +0100
+Subject: [PATCH 100/123] MIPS: lantiq: honour model property inside
+ devicetree during board init
+
+---
+ arch/mips/lantiq/prom.c | 20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
+index 9f9e875..fa12dc1 100644
+--- a/arch/mips/lantiq/prom.c
++++ b/arch/mips/lantiq/prom.c
+@@ -57,6 +57,21 @@ static void __init prom_init_cmdline(void)
+ }
+ }
+
++int __init early_init_dt_scan_model(unsigned long node,
++ const char *uname, int depth,
++ void *data)
++{
++ if (!depth) {
++ char *model = of_get_flat_dt_prop(node, "model", NULL);
++ if (model) {
++ pr_info("Board: %s\n", model);
++ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN, "%s - %s",
++ soc_info.sys_type, model);
++ }
++ }
++ return 0;
++}
++
+ void __init plat_mem_setup(void)
+ {
+ ioport_resource.start = IOPORT_RESOURCE_START;
+@@ -71,6 +86,8 @@ void __init plat_mem_setup(void)
+ * parsed resulting in our memory appearing
+ */
+ __dt_setup_arch(&__dtb_start);
++
++ of_scan_flat_dt(early_init_dt_scan_model, NULL);
+ }
+
+ void __init device_tree_init(void)
+@@ -93,9 +110,8 @@ void __init prom_init(void)
+ {
+ /* call the soc specific detetcion code and get it to fill soc_info */
+ ltq_soc_detect(&soc_info);
+- snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev %s",
++ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN, "%s rev %s",
+ soc_info.name, soc_info.rev_type);
+- soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
+ pr_info("SoC: %s\n", soc_info.sys_type);
+ prom_init_cmdline();
+
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0101-MIPS-lantiq-adds-support-for-SVIP-SoC-Family.patch b/target/linux/lantiq/patches-3.7/0101-MIPS-lantiq-adds-support-for-SVIP-SoC-Family.patch
new file mode 100644
index 0000000000..0de4005d6f
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0101-MIPS-lantiq-adds-support-for-SVIP-SoC-Family.patch
@@ -0,0 +1,439 @@
+From 4d77ad216ad86b3b25c196a189fa28f3e53c3ffd Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 30 Nov 2012 21:32:00 +0100
+Subject: [PATCH 101/123] MIPS: lantiq: adds support for SVIP SoC Family
+
+---
+ arch/mips/kernel/cevt-r4k.c | 4 +-
+ arch/mips/lantiq/Kconfig | 4 ++
+ arch/mips/lantiq/Makefile | 1 +
+ arch/mips/lantiq/Platform | 1 +
+ arch/mips/lantiq/clk.c | 7 +++
+ arch/mips/lantiq/clk.h | 4 ++
+ arch/mips/lantiq/svip/Makefile | 1 +
+ arch/mips/lantiq/svip/clk.c | 70 ++++++++++++++++++++++++++
+ arch/mips/lantiq/svip/prom.c | 43 ++++++++++++++++
+ arch/mips/lantiq/svip/reset.c | 105 +++++++++++++++++++++++++++++++++++++++
+ arch/mips/lantiq/svip/sysctrl.c | 81 ++++++++++++++++++++++++++++++
+ 11 files changed, 320 insertions(+), 1 deletion(-)
+ create mode 100644 arch/mips/lantiq/svip/Makefile
+ create mode 100644 arch/mips/lantiq/svip/clk.c
+ create mode 100644 arch/mips/lantiq/svip/prom.c
+ create mode 100644 arch/mips/lantiq/svip/reset.c
+ create mode 100644 arch/mips/lantiq/svip/sysctrl.c
+
+diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
+index 7532392..06b45e4 100644
+--- a/arch/mips/kernel/cevt-r4k.c
++++ b/arch/mips/kernel/cevt-r4k.c
+@@ -176,8 +176,10 @@ int __cpuinit r4k_clockevent_init(void)
+ if (!cpu_has_counter || !mips_hpt_frequency)
+ return -ENXIO;
+
+- if (!c0_compare_int_usable())
++ if (!c0_compare_int_usable()) {
++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+ return -ENXIO;
++ }
+
+ /*
+ * With vectored interrupts things are getting platform specific.
+diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
+index c002191..edeb58c 100644
+--- a/arch/mips/lantiq/Kconfig
++++ b/arch/mips/lantiq/Kconfig
+@@ -22,6 +22,10 @@ config SOC_FALCON
+ bool "FALCON"
+ select PINCTRL_FALCON
+
++config SOC_SVIP
++ bool "SVIP"
++ select MIPS_CPU_SCACHE
++
+ endchoice
+
+ choice
+diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
+index d6bdc57..edeb30b 100644
+--- a/arch/mips/lantiq/Makefile
++++ b/arch/mips/lantiq/Makefile
+@@ -12,3 +12,4 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+ obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
+ obj-$(CONFIG_SOC_FALCON) += falcon/
++obj-$(CONFIG_SOC_SVIP) += svip/
+diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
+index b3ec498..857548c 100644
+--- a/arch/mips/lantiq/Platform
++++ b/arch/mips/lantiq/Platform
+@@ -7,3 +7,4 @@ cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
+ load-$(CONFIG_LANTIQ) = 0xffffffff80002000
+ cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
+ cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon
++cflags-$(CONFIG_SOC_SVIP) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/svip
+diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
+index ce2f129..9128ff8 100644
+--- a/arch/mips/lantiq/clk.c
++++ b/arch/mips/lantiq/clk.c
+@@ -163,8 +163,15 @@ void __init plat_time_init(void)
+ ltq_soc_init();
+
+ clk = clk_get_cpu();
++#ifdef CONFIG_SOC_SVIP
++ mips_hpt_frequency = ltq_svip_cpu_hz() / get_counter_resolution();
++ write_c0_count(0);
++ write_c0_compare(mips_hpt_frequency / HZ);
++ enable_irq(MIPS_CPU_TIMER_IRQ);
++#else
+ mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution();
+ write_c0_compare(read_c0_count());
++#endif
+ pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
+ clk_put(clk);
+ }
+diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
+index fa67060..c169e2b 100644
+--- a/arch/mips/lantiq/clk.h
++++ b/arch/mips/lantiq/clk.h
+@@ -75,4 +75,8 @@ extern unsigned long ltq_ar9_fpi_hz(void);
+ extern unsigned long ltq_vr9_cpu_hz(void);
+ extern unsigned long ltq_vr9_fpi_hz(void);
+
++extern unsigned long ltq_svip_cpu_hz(void);
++extern unsigned long ltq_svip_fpi_hz(void);
++extern unsigned long ltq_svip_io_hz(void);
++
+ #endif
+diff --git a/arch/mips/lantiq/svip/Makefile b/arch/mips/lantiq/svip/Makefile
+new file mode 100644
+index 0000000..74308b2
+--- /dev/null
++++ b/arch/mips/lantiq/svip/Makefile
+@@ -0,0 +1 @@
++obj-y := prom.o reset.o sysctrl.o clk.o
+diff --git a/arch/mips/lantiq/svip/clk.c b/arch/mips/lantiq/svip/clk.c
+new file mode 100644
+index 0000000..3a7b665
+--- /dev/null
++++ b/arch/mips/lantiq/svip/clk.c
+@@ -0,0 +1,70 @@
++/*
++ * 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) 2010 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/io.h>
++#include <linux/export.h>
++#include <linux/init.h>
++#include <linux/clk.h>
++
++#include <asm/time.h>
++#include <asm/irq.h>
++#include <asm/div64.h>
++
++#include <lantiq_soc.h>
++
++#include "../clk.h"
++
++#define STATUS_CONFIG_CLK_MODE (0x1 << 1)
++#define STATUS_CONFIG_CLK_MODE_GET(val) ((((val) & STATUS_CONFIG_CLK_MODE) >> 4) & 0x1)
++#define STATUS_CONFIG 0x0010
++
++#define SYS0_PLL1CR_PLLDIV (0x3)
++#define SYS0_PLL1CR_PLLDIV_GET(val) ((((val) & SYS0_PLL1CR_PLLDIV) >> 0) & 0x3)
++#define SYS0_PLL1CR 0x0008
++
++#define SYS1_FPICR_FPIDIV (0x1)
++#define SYS1_FPICR_FPIDIV_GET(val) ((((val) & SYS1_FPICR_FPIDIV) >> 0) & 0x1)
++#define SYS1_FPICR 0x0014
++
++unsigned long ltq_svip_io_hz(void)
++{
++ return 200000000; /* 200 MHz */
++}
++
++unsigned long ltq_svip_cpu_hz(void)
++{
++ /* Magic BootROM speed location... */
++ if ((*(u32 *)0x9fc07ff0) == 1)
++ return *(u32 *)0x9fc07ff4;
++
++ if (STATUS_CONFIG_CLK_MODE_GET(ltq_status_r32(STATUS_CONFIG)) == 1) {
++ /* xT16 */
++ return 393216000;
++ } else {
++ switch (SYS0_PLL1CR_PLLDIV_GET(ltq_sys0_r32(SYS0_PLL1CR))) {
++ case 3:
++ return 475000000;
++ case 2:
++ return 450000000;
++ case 1:
++ return 425000000;
++ default:
++ break;
++ }
++ }
++ return 400000000;
++}
++
++unsigned long ltq_svip_fpi_hz(void)
++{
++ u32 fbs0_div[2] = {4, 8};
++ u32 div;
++
++ div = SYS1_FPICR_FPIDIV_GET(ltq_sys1_r32(SYS1_FPICR));
++ return ltq_svip_cpu_hz() / fbs0_div[div];
++}
+diff --git a/arch/mips/lantiq/svip/prom.c b/arch/mips/lantiq/svip/prom.c
+new file mode 100644
+index 0000000..01d2018
+--- /dev/null
++++ b/arch/mips/lantiq/svip/prom.c
+@@ -0,0 +1,43 @@
++/*
++ * 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) 2012 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/kernel.h>
++#include <asm/io.h>
++
++#include <lantiq_soc.h>
++
++#include "../prom.h"
++
++#define SOC_SVIP "SVIP"
++
++#define COMP_SVIP "lantiq,svip"
++
++#define PART_SHIFT 12
++#define PART_MASK 0x0FFFF000
++#define REV_SHIFT 28
++#define REV_MASK 0xF0000000
++
++void __init ltq_soc_detect(struct ltq_soc_info *i)
++{
++ i->partnum = (ltq_r32(LTQ_STATUS_CHIPID) & PART_MASK) >> PART_SHIFT;
++ i->rev = (ltq_r32(LTQ_STATUS_CHIPID) & REV_MASK) >> REV_SHIFT;
++ sprintf(i->rev_type, "1.%d", i->rev);
++
++ switch (i->partnum) {
++ case SOC_ID_SVIP:
++ i->name = SOC_SVIP;
++ i->type = SOC_TYPE_SVIP;
++ i->compatible = COMP_SVIP;
++ break;
++
++ default:
++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++ break;
++ }
++}
+diff --git a/arch/mips/lantiq/svip/reset.c b/arch/mips/lantiq/svip/reset.c
+new file mode 100644
+index 0000000..4b41dd1
+--- /dev/null
++++ b/arch/mips/lantiq/svip/reset.c
+@@ -0,0 +1,105 @@
++/*
++ * 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) 2012 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/pm.h>
++#include <linux/module.h>
++#include <asm/reboot.h>
++
++#include <lantiq_soc.h>
++
++#define CPLD_CMDREG3 ((volatile unsigned char*)(KSEG1 + 0x120000f3))
++
++#define LTQ_EBU_ADDRSEL2 0x0028
++#define LTQ_EBU_BUSCON2 0x0068
++#define LTQ_BOOT_CPU_OFFSET 0x20
++
++#define LTQ_L2_SPRAM_BASE (KSEG1 + 0x1F1E8000)
++#define LTQ_BOOT_RVEC(cpu) (volatile u32*)(LTQ_L2_SPRAM_BASE + \
++ (cpu * LTQ_BOOT_CPU_OFFSET))
++
++#define SYS0_BCR 0x0004
++#define BMODE_SHIFT 16
++#define BMODE_MASK 0x1f
++
++#define SYS1_CLKCLR 0x0008
++#define SYS1_RREQR 0x0044
++#define SYS1_RRLSR 0x0048
++#define SYS1_RBTR 0x004c
++#define SYS1_CPU0RSR 0x0060
++#define SYS1_CPU0RSR_MASK 0x0007
++
++/* This function is used by the watchdog driver */
++int ltq_reset_cause(void)
++{
++ return ltq_sys1_r32(SYS1_CPU0RSR) & SYS1_CPU0RSR_MASK;
++}
++EXPORT_SYMBOL_GPL(ltq_reset_cause);
++
++/* allow platform code to find out what source we booted from */
++unsigned char ltq_boot_select(void)
++{
++ return (ltq_sys0_r32(SYS0_BCR) >> BMODE_SHIFT) & BMODE_MASK;
++}
++
++static void ltq_machine_restart(char *command)
++{
++ local_irq_disable();
++ if (/*mips_machtype == LANTIQ_MACH_EASY33016 ||
++ mips_machtype == LANTIQ_MACH_EASY336)*/
++ 1) {
++ /* We just use the CPLD function to reset the entire system as a
++ workaround for the switch reset problem */
++ local_irq_disable();
++ ltq_ebu_w32(0x120000f1, LTQ_EBU_ADDRSEL2);
++ ltq_ebu_w32(0x404027ff, LTQ_EBU_BUSCON2);
++
++ if (/*mips_machtype == LANTIQ_MACH_EASY336*/
++ 0)
++ /* set bit 0 to reset SVIP */
++ *CPLD_CMDREG3 = (1<<0);
++ else
++ /* set bit 7 to reset SVIP, set bit 3 to reset xT */
++ *CPLD_CMDREG3 = (1<<7) | (1<<3);
++ } else {
++ *LTQ_BOOT_RVEC(0) = 0;
++ /* reset all except PER, SUBSYS and CPU0 */
++ ltq_sys1_w32(0x00043F3E, SYS1_RREQR);
++ /* release WDT0 reset */
++ ltq_sys1_w32(0x00000100, SYS1_RRLSR);
++ /* restore reset value for clock enables */
++ ltq_sys1_w32(~0x0c000040, SYS1_CLKCLR);
++ /* reset SUBSYS (incl. DDR2) and CPU0 */
++ ltq_sys1_w32(0x00030001, SYS1_RBTR);
++ }
++
++ unreachable();
++}
++
++static void ltq_machine_halt(void)
++{
++ local_irq_disable();
++ unreachable();
++}
++
++static void ltq_machine_power_off(void)
++{
++ local_irq_disable();
++}
++
++static int __init mips_reboot_setup(void)
++{
++ _machine_restart = ltq_machine_restart;
++ _machine_halt = ltq_machine_halt;
++ pm_power_off = ltq_machine_power_off;
++ return 0;
++}
++
++arch_initcall(mips_reboot_setup);
+diff --git a/arch/mips/lantiq/svip/sysctrl.c b/arch/mips/lantiq/svip/sysctrl.c
+new file mode 100644
+index 0000000..d2b636b
+--- /dev/null
++++ b/arch/mips/lantiq/svip/sysctrl.c
+@@ -0,0 +1,81 @@
++/*
++ * 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) 2011-2012 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/ioport.h>
++#include <linux/export.h>
++#include <linux/clkdev.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/of_address.h>
++
++#include <lantiq_soc.h>
++
++#include "../clk.h"
++#include "../prom.h"
++
++void __iomem *ltq_sys0_membase;
++void __iomem *ltq_sys1_membase;
++void __iomem *ltq_sys2_membase;
++void __iomem *ltq_status_membase;
++void __iomem *ltq_ebu_membase;
++
++/* bring up all register ranges that we need for basic system control */
++void __init ltq_soc_init(void)
++{
++ struct resource res_sys0, res_sys1, res_sys2, res_status, res_ebu;
++ struct device_node *np_sys0 =
++ of_find_compatible_node(NULL, NULL, "lantiq,sys0-svip");
++ struct device_node *np_sys1 =
++ of_find_compatible_node(NULL, NULL, "lantiq,sys1-svip");
++ struct device_node *np_sys2 =
++ of_find_compatible_node(NULL, NULL, "lantiq,sys2-svip");
++ struct device_node *np_status =
++ of_find_compatible_node(NULL, NULL, "lantiq,status-svip");
++ struct device_node *np_ebu =
++ of_find_compatible_node(NULL, NULL, "lantiq,ebu-svip");
++
++ /* check if all the core register ranges are available */
++ if (!np_sys0 || !np_sys1 || !np_sys2 || !np_status || !np_ebu)
++ panic("Failed to load core nodes from devicetree");
++
++ if (of_address_to_resource(np_sys0, 0, &res_sys0) ||
++ of_address_to_resource(np_sys1, 0, &res_sys1) ||
++ of_address_to_resource(np_sys2, 0, &res_sys2) ||
++ of_address_to_resource(np_status, 0, &res_status) ||
++ of_address_to_resource(np_ebu, 0, &res_ebu))
++ panic("Failed to get core resources");
++
++ if ((request_mem_region(res_sys0.start, resource_size(&res_sys0),
++ res_sys0.name) < 0) ||
++ (request_mem_region(res_sys1.start, resource_size(&res_sys1),
++ res_sys1.name) < 0) ||
++ (request_mem_region(res_sys2.start, resource_size(&res_sys2),
++ res_sys2.name) < 0) ||
++ (request_mem_region(res_status.start, resource_size(&res_status),
++ res_status.name) < 0) ||
++ (request_mem_region(res_ebu.start, resource_size(&res_ebu),
++ res_ebu.name) < 0))
++ pr_err("Failed to request core reources");
++
++ ltq_sys0_membase = ioremap_nocache(res_sys0.start,
++ resource_size(&res_sys0));
++ ltq_sys1_membase = ioremap_nocache(res_sys1.start,
++ resource_size(&res_sys1));
++ ltq_sys2_membase = ioremap_nocache(res_sys2.start,
++ resource_size(&res_sys2));
++ ltq_status_membase = ioremap_nocache(res_status.start,
++ resource_size(&res_status));
++ ltq_ebu_membase = ioremap_nocache(res_ebu.start,
++ resource_size(&res_ebu));
++ if (!ltq_sys0_membase || !ltq_sys1_membase || !ltq_sys2_membase ||
++ !ltq_status_membase || !ltq_ebu_membase)
++ panic("Failed to remap core resources");
++
++ clkdev_add_static(ltq_svip_cpu_hz(), ltq_svip_fpi_hz(),
++ ltq_svip_io_hz());
++}
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0102-MIPS-lantiq-add-GPHY-clock-gate-bits.patch b/target/linux/lantiq/patches-3.7/0102-MIPS-lantiq-add-GPHY-clock-gate-bits.patch
new file mode 100644
index 0000000000..e979e1e112
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0102-MIPS-lantiq-add-GPHY-clock-gate-bits.patch
@@ -0,0 +1,52 @@
+From 05d6c964722224e8cf2902606744e29a835e7d5f Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 3 Dec 2012 21:35:01 +0100
+Subject: [PATCH 102/123] MIPS: lantiq: add GPHY clock gate bits
+
+Explicitly enable the clock gate of the internal GPHYs found on xrx200.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/lantiq/xway/reset.c | 9 +++++++++
+ arch/mips/lantiq/xway/sysctrl.c | 1 +
+ 2 files changed, 10 insertions(+)
+
+diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
+index 544dbb7..1fa0f17 100644
+--- a/arch/mips/lantiq/xway/reset.c
++++ b/arch/mips/lantiq/xway/reset.c
+@@ -78,10 +78,19 @@ static struct ltq_xrx200_gphy_reset {
+ /* reset and boot a gphy. these phys only exist on xrx200 SoC */
+ int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr)
+ {
++ struct clk *clk;
++
+ if (!of_device_is_compatible(ltq_rcu_np, "lantiq,rcu-xrx200")) {
+ dev_err(dev, "this SoC has no GPHY\n");
+ return -EINVAL;
+ }
++
++ clk = clk_get_sys("1f203000.rcu", "gphy");
++ if (IS_ERR(clk))
++ return PTR_ERR(clk);
++
++ clk_enable(clk);
++
+ if (id > 1) {
+ dev_err(dev, "%u is an invalid gphy id\n", id);
+ return -EINVAL;
+diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
+index 3925e66..6e0e135 100644
+--- a/arch/mips/lantiq/xway/sysctrl.c
++++ b/arch/mips/lantiq/xway/sysctrl.c
+@@ -374,6 +374,7 @@ void __init ltq_soc_init(void)
+ PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
+ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
+ PMU_PPE_QSB | PMU_PPE_TOP);
++ clkdev_add_pmu("1f203000.rcu", "gphy", 0, PMU_GPHY);
+ } else if (of_machine_is_compatible("lantiq,ar9")) {
+ clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
+ ltq_ar9_fpi_hz());
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0103-MIPS-lantiq-adds-static-clock-for-PP32.patch b/target/linux/lantiq/patches-3.7/0103-MIPS-lantiq-adds-static-clock-for-PP32.patch
new file mode 100644
index 0000000000..1ab7b07da1
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0103-MIPS-lantiq-adds-static-clock-for-PP32.patch
@@ -0,0 +1,219 @@
+From 8cbac4b30bed1552503b95bc0ac6276e3cdda9d8 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 30 Nov 2012 21:08:49 +0100
+Subject: [PATCH 103/123] MIPS: lantiq: adds static clock for PP32
+
+The Lantiq DSL SoCs have an internal networking processor. Add code to read
+the static clock rate.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/include/asm/mach-lantiq/lantiq.h | 1 +
+ arch/mips/lantiq/clk.c | 12 ++++++--
+ arch/mips/lantiq/clk.h | 7 ++++-
+ arch/mips/lantiq/falcon/sysctrl.c | 4 +--
+ arch/mips/lantiq/xway/clk.c | 43 ++++++++++++++++++++++++++++
+ arch/mips/lantiq/xway/sysctrl.c | 12 ++++----
+ 6 files changed, 69 insertions(+), 10 deletions(-)
+
+diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
+index 5e8a6e9..76be7a0 100644
+--- a/arch/mips/include/asm/mach-lantiq/lantiq.h
++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
+@@ -41,6 +41,7 @@ extern void clk_deactivate(struct clk *clk);
+ extern struct clk *clk_get_cpu(void);
+ extern struct clk *clk_get_fpi(void);
+ extern struct clk *clk_get_io(void);
++extern struct clk *clk_get_ppe(void);
+
+ /* find out what bootsource we have */
+ extern unsigned char ltq_boot_select(void);
+diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
+index 9128ff8..292ef1a 100644
+--- a/arch/mips/lantiq/clk.c
++++ b/arch/mips/lantiq/clk.c
+@@ -26,13 +26,15 @@
+ #include "prom.h"
+
+ /* lantiq socs have 3 static clocks */
+-static struct clk cpu_clk_generic[3];
++static struct clk cpu_clk_generic[4];
+
+-void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io)
++void clkdev_add_static(unsigned long cpu, unsigned long fpi,
++ unsigned long io, unsigned long ppe)
+ {
+ cpu_clk_generic[0].rate = cpu;
+ cpu_clk_generic[1].rate = fpi;
+ cpu_clk_generic[2].rate = io;
++ cpu_clk_generic[3].rate = ppe;
+ }
+
+ struct clk *clk_get_cpu(void)
+@@ -51,6 +53,12 @@ struct clk *clk_get_io(void)
+ return &cpu_clk_generic[2];
+ }
+
++struct clk *clk_get_ppe(void)
++{
++ return &cpu_clk_generic[3];
++}
++EXPORT_SYMBOL_GPL(clk_get_ppe);
++
+ static inline int clk_good(struct clk *clk)
+ {
+ return clk && !IS_ERR(clk);
+diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
+index c169e2b..4739366 100644
+--- a/arch/mips/lantiq/clk.h
++++ b/arch/mips/lantiq/clk.h
+@@ -27,12 +27,15 @@
+ #define CLOCK_167M 166666667
+ #define CLOCK_196_608M 196608000
+ #define CLOCK_200M 200000000
++#define CLOCK_222M 222000000
++#define CLOCK_240M 240000000
+ #define CLOCK_250M 250000000
+ #define CLOCK_266M 266666666
+ #define CLOCK_300M 300000000
+ #define CLOCK_333M 333333333
+ #define CLOCK_393M 393215332
+ #define CLOCK_400M 400000000
++#define CLOCK_450M 450000000
+ #define CLOCK_500M 500000000
+ #define CLOCK_600M 600000000
+
+@@ -64,16 +67,18 @@ struct clk {
+ };
+
+ extern void clkdev_add_static(unsigned long cpu, unsigned long fpi,
+- unsigned long io);
++ unsigned long io, unsigned long ppe);
+
+ extern unsigned long ltq_danube_cpu_hz(void);
+ extern unsigned long ltq_danube_fpi_hz(void);
++extern unsigned long ltq_danube_pp32_hz(void);
+
+ extern unsigned long ltq_ar9_cpu_hz(void);
+ extern unsigned long ltq_ar9_fpi_hz(void);
+
+ extern unsigned long ltq_vr9_cpu_hz(void);
+ extern unsigned long ltq_vr9_fpi_hz(void);
++extern unsigned long ltq_vr9_pp32_hz(void);
+
+ extern unsigned long ltq_svip_cpu_hz(void);
+ extern unsigned long ltq_svip_fpi_hz(void);
+diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c
+index 2d4ced3..ff4894a 100644
+--- a/arch/mips/lantiq/falcon/sysctrl.c
++++ b/arch/mips/lantiq/falcon/sysctrl.c
+@@ -241,9 +241,9 @@ void __init ltq_soc_init(void)
+
+ /* get our 3 static rates for cpu, fpi and io clocks */
+ if (ltq_sys1_r32(SYS1_CPU0CC) & CPU0CC_CPUDIV)
+- clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M);
++ clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M, 0);
+ else
+- clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M);
++ clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M, 0);
+
+ /* add our clock domains */
+ clkdev_add_sys("1d810000.gpio", SYSCTL_SYSETH, ACTS_P0);
+diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c
+index 9aa17f7..1ab576d 100644
+--- a/arch/mips/lantiq/xway/clk.c
++++ b/arch/mips/lantiq/xway/clk.c
+@@ -53,6 +53,29 @@ unsigned long ltq_danube_cpu_hz(void)
+ }
+ }
+
++unsigned long ltq_danube_pp32_hz(void)
++{
++ unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 7) & 3;
++ unsigned long clk;
++
++ switch (clksys) {
++ case 1:
++ clk = CLOCK_240M;
++ break;
++ case 2:
++ clk = CLOCK_222M;
++ break;
++ case 3:
++ clk = CLOCK_133M;
++ break;
++ default:
++ clk = CLOCK_266M;
++ break;
++ }
++
++ return clk;
++}
++
+ unsigned long ltq_ar9_sys_hz(void)
+ {
+ if (((ltq_cgu_r32(CGU_SYS) >> 3) & 0x3) == 0x2)
+@@ -149,3 +172,23 @@ unsigned long ltq_vr9_fpi_hz(void)
+
+ return clk;
+ }
++
++unsigned long ltq_vr9_pp32_hz(void)
++{
++ unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 3;
++ unsigned long clk;
++
++ switch (clksys) {
++ case 1:
++ clk = CLOCK_450M;
++ break;
++ case 2:
++ clk = CLOCK_300M;
++ break;
++ default:
++ clk = CLOCK_500M;
++ break;
++ }
++
++ return clk;
++}
+diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
+index 6e0e135..75e1b7d 100644
+--- a/arch/mips/lantiq/xway/sysctrl.c
++++ b/arch/mips/lantiq/xway/sysctrl.c
+@@ -356,14 +356,16 @@ void __init ltq_soc_init(void)
+
+ if (of_machine_is_compatible("lantiq,ase")) {
+ if (ltq_cgu_r32(CGU_SYS) & (1 << 5))
+- clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M);
++ clkdev_add_static(CLOCK_266M, CLOCK_133M,
++ CLOCK_133M, CLOCK_266M);
+ else
+- clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M);
++ clkdev_add_static(CLOCK_133M, CLOCK_133M,
++ CLOCK_133M, CLOCK_133M);
+ clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY),
+ clkdev_add_pmu("1e180000.etop", "ephy", 0, PMU_EPHY);
+ } else if (of_machine_is_compatible("lantiq,vr9")) {
+ clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(),
+- ltq_vr9_fpi_hz());
++ ltq_vr9_fpi_hz(), ltq_vr9_pp32_hz());
+ clkdev_add_pmu("1d900000.pcie", "phy", 1, PMU1_PCIE_PHY);
+ clkdev_add_pmu("1d900000.pcie", "bus", 0, PMU_PCIE_CLK);
+ clkdev_add_pmu("1d900000.pcie", "msi", 1, PMU1_PCIE_MSI);
+@@ -377,10 +379,10 @@ void __init ltq_soc_init(void)
+ clkdev_add_pmu("1f203000.rcu", "gphy", 0, PMU_GPHY);
+ } else if (of_machine_is_compatible("lantiq,ar9")) {
+ clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
+- ltq_ar9_fpi_hz());
++ ltq_ar9_fpi_hz(), CLOCK_250M);
+ clkdev_add_pmu("1e180000.etop", "switch", 0, PMU_SWITCH);
+ } else {
+ clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(),
+- ltq_danube_fpi_hz());
++ ltq_danube_fpi_hz(), ltq_danube_pp32_hz());
+ }
+ }
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0104-MIPS-lantiq-adds-4dword-burst-length-for-dma.patch b/target/linux/lantiq/patches-3.7/0104-MIPS-lantiq-adds-4dword-burst-length-for-dma.patch
new file mode 100644
index 0000000000..5ef0249c6a
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0104-MIPS-lantiq-adds-4dword-burst-length-for-dma.patch
@@ -0,0 +1,34 @@
+From 07f7321c0f79c0b800d28898a480d044f839e813 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 6 Dec 2012 11:59:23 +0100
+Subject: [PATCH 104/123] MIPS: lantiq: adds 4dword burst length for dma
+
+---
+ arch/mips/lantiq/xway/dma.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
+index b5d76d1..986fbce 100644
+--- a/arch/mips/lantiq/xway/dma.c
++++ b/arch/mips/lantiq/xway/dma.c
+@@ -47,6 +47,7 @@
+ #define DMA_IRQ_ACK 0x7e /* IRQ status register */
+ #define DMA_POLL BIT(31) /* turn on channel polling */
+ #define DMA_CLK_DIV4 BIT(6) /* polling clock divider */
++#define DMA_4W_BURST BIT(2) /* 4 word burst length */
+ #define DMA_2W_BURST BIT(1) /* 2 word burst length */
+ #define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */
+ #define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */
+@@ -195,7 +196,8 @@ ltq_dma_init_port(int p)
+ * Tell the DMA engine to swap the endianess of data frames and
+ * drop packets if the channel arbitration fails.
+ */
+- ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN,
++ ltq_dma_w32_mask(0, (DMA_4W_BURST << 4) | (DMA_4W_BURST << 2) |
++ DMA_ETOP_ENDIANESS | DMA_PDEN,
+ LTQ_DMA_PCTRL);
+ break;
+
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch b/target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch
new file mode 100644
index 0000000000..88659c2448
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0105-MIPS-lantiq-rework-external-irq-code.patch
@@ -0,0 +1,214 @@
+From edd237c93d564e698e169a89d1b1b35248c5ef4a Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 3 Dec 2012 21:44:30 +0100
+Subject: [PATCH 105/123] MIPS: lantiq: rework external irq code
+
+This code makes the irqs used by the EIU loadable from the DT. Additionally we
+add a helper that allows the pinctrl layer to map external irqs to real irq
+numbers.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/include/asm/mach-lantiq/lantiq.h | 1 +
+ arch/mips/lantiq/irq.c | 104 +++++++++++++++++++---------
+ 2 files changed, 73 insertions(+), 32 deletions(-)
+
+diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
+index 76be7a0..f196cce 100644
+--- a/arch/mips/include/asm/mach-lantiq/lantiq.h
++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
+@@ -34,6 +34,7 @@ extern spinlock_t ebu_lock;
+ extern void ltq_disable_irq(struct irq_data *data);
+ extern void ltq_mask_and_ack_irq(struct irq_data *data);
+ extern void ltq_enable_irq(struct irq_data *data);
++extern int ltq_eiu_get_irq(int exin);
+
+ /* clock handling */
+ extern int clk_activate(struct clk *clk);
+diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
+index f36acd1..48407f6 100644
+--- a/arch/mips/lantiq/irq.c
++++ b/arch/mips/lantiq/irq.c
+@@ -33,17 +33,10 @@
+ /* register definitions - external irqs */
+ #define LTQ_EIU_EXIN_C 0x0000
+ #define LTQ_EIU_EXIN_INIC 0x0004
++#define LTQ_EIU_EXIN_INC 0x0008
+ #define LTQ_EIU_EXIN_INEN 0x000C
+
+-/* irq numbers used by the external interrupt unit (EIU) */
+-#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30)
+-#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31)
+-#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26)
+-#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0
+-#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1)
+-#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2)
+-#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30)
+-#define XWAY_EXIN_COUNT 3
++/* number of external interrupts */
+ #define MAX_EIU 6
+
+ /* the performance counter */
+@@ -72,20 +65,19 @@
+ int gic_present;
+ #endif
+
+-static unsigned short ltq_eiu_irq[MAX_EIU] = {
+- LTQ_EIU_IR0,
+- LTQ_EIU_IR1,
+- LTQ_EIU_IR2,
+- LTQ_EIU_IR3,
+- LTQ_EIU_IR4,
+- LTQ_EIU_IR5,
+-};
+-
+ static int exin_avail;
++static struct resource ltq_eiu_irq[MAX_EIU];
+ static void __iomem *ltq_icu_membase[MAX_IM];
+ static void __iomem *ltq_eiu_membase;
+ static struct irq_domain *ltq_domain;
+
++int ltq_eiu_get_irq(int exin)
++{
++ if (exin < exin_avail)
++ return ltq_eiu_irq[exin].start;
++ return -1;
++}
++
+ void ltq_disable_irq(struct irq_data *d)
+ {
+ u32 ier = LTQ_ICU_IM0_IER;
+@@ -128,19 +120,64 @@ void ltq_enable_irq(struct irq_data *d)
+ ltq_icu_w32(im, ltq_icu_r32(im, ier) | BIT(offset), ier);
+ }
+
++static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
++{
++ int i;
++
++ for (i = 0; i < MAX_EIU; i++) {
++ if (d->hwirq == ltq_eiu_irq[i].start) {
++ int val = 0;
++ int edge = 0;
++
++ switch (type) {
++ case IRQF_TRIGGER_NONE:
++ break;
++ case IRQF_TRIGGER_RISING:
++ val = 1;
++ edge = 1;
++ break;
++ case IRQF_TRIGGER_FALLING:
++ val = 2;
++ edge = 1;
++ break;
++ case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
++ val = 3;
++ edge = 1;
++ break;
++ case IRQF_TRIGGER_HIGH:
++ val = 5;
++ break;
++ case IRQF_TRIGGER_LOW:
++ val = 6;
++ break;
++ default:
++ pr_err("invalid type %d for irq %ld\n", type, d->hwirq);
++ return -EINVAL;
++ }
++
++ if (edge)
++ irq_set_handler(d->hwirq, handle_edge_irq);
++
++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
++ (val << (i * 4)), LTQ_EIU_EXIN_C);
++ }
++ }
++
++ return 0;
++}
++
+ static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
+ {
+ int i;
+
+ ltq_enable_irq(d);
+ for (i = 0; i < MAX_EIU; i++) {
+- if (d->hwirq == ltq_eiu_irq[i]) {
+- /* low level - we should really handle set_type */
+- ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
+- (0x6 << (i * 4)), LTQ_EIU_EXIN_C);
++ if (d->hwirq == ltq_eiu_irq[i].start) {
++ /* by default we are low level triggered */
++ ltq_eiu_settype(d, IRQF_TRIGGER_LOW);
+ /* clear all pending */
+- ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~BIT(i),
+- LTQ_EIU_EXIN_INIC);
++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i),
++ LTQ_EIU_EXIN_INC);
+ /* enable */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i),
+ LTQ_EIU_EXIN_INEN);
+@@ -157,7 +194,7 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d)
+
+ ltq_disable_irq(d);
+ for (i = 0; i < MAX_EIU; i++) {
+- if (d->hwirq == ltq_eiu_irq[i]) {
++ if (d->hwirq == ltq_eiu_irq[i].start) {
+ /* disable */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i),
+ LTQ_EIU_EXIN_INEN);
+@@ -186,6 +223,7 @@ static struct irq_chip ltq_eiu_type = {
+ .irq_ack = ltq_ack_irq,
+ .irq_mask = ltq_disable_irq,
+ .irq_mask_ack = ltq_mask_and_ack_irq,
++ .irq_set_type = ltq_eiu_settype,
+ };
+
+ static void ltq_hw_irqdispatch(int module)
+@@ -301,7 +339,7 @@ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+ return 0;
+
+ for (i = 0; i < exin_avail; i++)
+- if (hw == ltq_eiu_irq[i])
++ if (hw == ltq_eiu_irq[i].start)
+ chip = &ltq_eiu_type;
+
+ irq_set_chip_and_handler(hw, chip, handle_level_irq);
+@@ -323,7 +361,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
+ {
+ struct device_node *eiu_node;
+ struct resource res;
+- int i;
++ int i, ret;
+
+ for (i = 0; i < MAX_IM; i++) {
+ if (of_address_to_resource(node, i, &res))
+@@ -340,17 +378,19 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
+ }
+
+ /* the external interrupts are optional and xway only */
+- eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu");
++ eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway");
+ if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) {
+ /* find out how many external irq sources we have */
+- const __be32 *count = of_get_property(node,
+- "lantiq,count", NULL);
++ exin_avail = of_irq_count(eiu_node);
+
+- if (count)
+- exin_avail = *count;
+ if (exin_avail > MAX_EIU)
+ exin_avail = MAX_EIU;
+
++ ret = of_irq_to_resource_table(eiu_node,
++ ltq_eiu_irq, exin_avail);
++ if (ret != exin_avail)
++ panic("failed to load external irq resources\n");
++
+ if (request_mem_region(res.start, resource_size(&res),
+ res.name) < 0)
+ pr_err("Failed to request eiu memory");
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0106-MIPS-lantiq-adds-minimal-dcdc-driver.patch b/target/linux/lantiq/patches-3.7/0106-MIPS-lantiq-adds-minimal-dcdc-driver.patch
new file mode 100644
index 0000000000..78967efd4d
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0106-MIPS-lantiq-adds-minimal-dcdc-driver.patch
@@ -0,0 +1,106 @@
+From 3aa46ed76b27df771f75db9c74ff011aca505fc5 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 5 Dec 2012 17:38:48 +0100
+Subject: [PATCH 106/123] MIPS: lantiq: adds minimal dcdc driver
+
+This driver so far only reads the core voltage.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ arch/mips/lantiq/xway/Makefile | 2 +-
+ arch/mips/lantiq/xway/dcdc.c | 74 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 75 insertions(+), 1 deletion(-)
+ create mode 100644 arch/mips/lantiq/xway/dcdc.c
+
+diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
+index 7a13660..087497d 100644
+--- a/arch/mips/lantiq/xway/Makefile
++++ b/arch/mips/lantiq/xway/Makefile
+@@ -1,3 +1,3 @@
+-obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o
++obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o dcdc.o
+
+ obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o
+diff --git a/arch/mips/lantiq/xway/dcdc.c b/arch/mips/lantiq/xway/dcdc.c
+new file mode 100644
+index 0000000..0ac73a5
+--- /dev/null
++++ b/arch/mips/lantiq/xway/dcdc.c
+@@ -0,0 +1,74 @@
++/*
++ * 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) 2012 John Crispin <blogic@openwrt.org>
++ * Copyright (C) 2010 Sameer Ahmad, Lantiq GmbH
++ */
++
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/of_irq.h>
++
++#include <lantiq_soc.h>
++
++/* Bias and regulator Setup Register */
++#define DCDC_BIAS_VREG0 0xa
++/* Bias and regulator Setup Register */
++#define DCDC_BIAS_VREG1 0xb
++
++#define dcdc_w8(x, y) ltq_w8((x), dcdc_membase + (y))
++#define dcdc_r8(x) ltq_r8(dcdc_membase + (x))
++
++static void __iomem *dcdc_membase;
++
++static int __devinit dcdc_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "Failed to get resource\n");
++ return -ENOMEM;
++ }
++
++ /* remap dcdc register range */
++ dcdc_membase = devm_request_and_ioremap(&pdev->dev, res);
++ if (!dcdc_membase) {
++ dev_err(&pdev->dev, "Failed to remap resource\n");
++ return -ENOMEM;
++ }
++
++ dev_info(&pdev->dev, "Core Voltage : %d mV\n", dcdc_r8(DCDC_BIAS_VREG1) * 8);
++
++ return 0;
++}
++
++static const struct of_device_id dcdc_match[] = {
++ { .compatible = "lantiq,dcdc-xrx200" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, dcdc_match);
++
++static struct platform_driver dcdc_driver = {
++ .probe = dcdc_probe,
++ .driver = {
++ .name = "dcdc-xrx200",
++ .owner = THIS_MODULE,
++ .of_match_table = dcdc_match,
++ },
++};
++
++int __init dcdc_init(void)
++{
++ int ret = platform_driver_register(&dcdc_driver);
++
++ if (ret)
++ pr_info("dcdc: Error registering platform driver\n");
++ return ret;
++}
++
++arch_initcall(dcdc_init);
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0107-PINCTRL-lantiq-pinconf-uses-port-instead-of-pin.patch b/target/linux/lantiq/patches-3.7/0107-PINCTRL-lantiq-pinconf-uses-port-instead-of-pin.patch
new file mode 100644
index 0000000000..5d9e5a308c
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0107-PINCTRL-lantiq-pinconf-uses-port-instead-of-pin.patch
@@ -0,0 +1,92 @@
+From 84ce6d4b2802fd428a76e5f2692fd4c102ed35ea Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 30 Nov 2012 21:11:22 +0100
+Subject: [PATCH 107/123] PINCTRL: lantiq: pinconf uses port instead of pin
+
+The XWAY pinctrl driver invalidly uses the port and not the pin number to work
+out the registeres and bits to be set for the opendrain and pullup/down
+resistors.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/pinctrl/pinctrl-xway.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
+index b9bcaec..48ab09b 100644
+--- a/drivers/pinctrl/pinctrl-xway.c
++++ b/drivers/pinctrl/pinctrl-xway.c
+@@ -441,17 +441,17 @@ static int xway_pinconf_get(struct pinctrl_dev *pctldev,
+ if (port == PORT3)
+ reg = GPIO3_OD;
+ else
+- reg = GPIO_OD(port);
++ reg = GPIO_OD(pin);
+ *config = LTQ_PINCONF_PACK(param,
+- !!gpio_getbit(info->membase[0], reg, PORT_PIN(port)));
++ !!gpio_getbit(info->membase[0], reg, PORT_PIN(pin)));
+ break;
+
+ case LTQ_PINCONF_PARAM_PULL:
+ if (port == PORT3)
+ reg = GPIO3_PUDEN;
+ else
+- reg = GPIO_PUDEN(port);
+- if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port))) {
++ reg = GPIO_PUDEN(pin);
++ if (!gpio_getbit(info->membase[0], reg, PORT_PIN(pin))) {
+ *config = LTQ_PINCONF_PACK(param, 0);
+ break;
+ }
+@@ -459,8 +459,8 @@ static int xway_pinconf_get(struct pinctrl_dev *pctldev,
+ if (port == PORT3)
+ reg = GPIO3_PUDSEL;
+ else
+- reg = GPIO_PUDSEL(port);
+- if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port)))
++ reg = GPIO_PUDSEL(pin);
++ if (!gpio_getbit(info->membase[0], reg, PORT_PIN(pin)))
+ *config = LTQ_PINCONF_PACK(param, 2);
+ else
+ *config = LTQ_PINCONF_PACK(param, 1);
+@@ -488,29 +488,29 @@ static int xway_pinconf_set(struct pinctrl_dev *pctldev,
+ if (port == PORT3)
+ reg = GPIO3_OD;
+ else
+- reg = GPIO_OD(port);
+- gpio_setbit(info->membase[0], reg, PORT_PIN(port));
++ reg = GPIO_OD(pin);
++ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+ break;
+
+ case LTQ_PINCONF_PARAM_PULL:
+ if (port == PORT3)
+ reg = GPIO3_PUDEN;
+ else
+- reg = GPIO_PUDEN(port);
++ reg = GPIO_PUDEN(pin);
+ if (arg == 0) {
+- gpio_clearbit(info->membase[0], reg, PORT_PIN(port));
++ gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
+ break;
+ }
+- gpio_setbit(info->membase[0], reg, PORT_PIN(port));
++ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+
+ if (port == PORT3)
+ reg = GPIO3_PUDSEL;
+ else
+- reg = GPIO_PUDSEL(port);
++ reg = GPIO_PUDSEL(pin);
+ if (arg == 1)
+- gpio_clearbit(info->membase[0], reg, PORT_PIN(port));
++ gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
+ else if (arg == 2)
+- gpio_setbit(info->membase[0], reg, PORT_PIN(port));
++ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+ else
+ dev_err(pctldev->dev, "Invalid pull value %d\n", arg);
+ break;
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0108-PINCTRL-lantiq-fixes.patch b/target/linux/lantiq/patches-3.7/0108-PINCTRL-lantiq-fixes.patch
new file mode 100644
index 0000000000..9ce8a785f9
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0108-PINCTRL-lantiq-fixes.patch
@@ -0,0 +1,281 @@
+From 13e754b5fff5be1930e2b8fe534a52b608c9e479 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 3 Dec 2012 19:27:28 +0100
+Subject: [PATCH] PINCTRL: lantiq: fixes
+
+---
+ drivers/pinctrl/pinctrl-lantiq.c | 54 ++++++++++++++++++-----------
+ drivers/pinctrl/pinctrl-lantiq.h | 1 +
+ drivers/pinctrl/pinctrl-xway.c | 70 ++++++++++++++++++++++++++++++++++----
+ 3 files changed, 99 insertions(+), 26 deletions(-)
+
+Index: linux-3.7-rc8/drivers/pinctrl/pinctrl-lantiq.c
+===================================================================
+--- linux-3.7-rc8.orig/drivers/pinctrl/pinctrl-lantiq.c 2012-12-03 20:22:37.000000000 +0100
++++ linux-3.7-rc8/drivers/pinctrl/pinctrl-lantiq.c 2012-12-14 22:59:40.687563565 +0100
+@@ -64,11 +64,13 @@
+ seq_printf(s, " %s", dev_name(pctldev->dev));
+ }
+
+-static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
++static void ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map)
+ {
+ struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
++ struct property *pins = of_find_property(np, "lantiq,pins", NULL);
++ struct property *groups = of_find_property(np, "lantiq,groups", NULL);
+ unsigned long configs[3];
+ unsigned num_configs = 0;
+ struct property *prop;
+@@ -76,8 +78,20 @@
+ const char *function;
+ int ret, i;
+
++ if (!pins && !groups) {
++ dev_err(pctldev->dev, "%s defines neither pins nor groups\n",
++ np->name);
++ return;
++ }
++
++ if (pins && groups) {
++ dev_err(pctldev->dev, "%s defines both pins and groups\n",
++ np->name);
++ return;
++ }
++
+ ret = of_property_read_string(np, "lantiq,function", &function);
+- if (!ret) {
++ if (groups && !ret) {
+ of_property_for_each_string(np, "lantiq,groups", prop, group) {
+ (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)->name = function;
+@@ -85,11 +99,6 @@
+ (*map)->data.mux.function = function;
+ (*map)++;
+ }
+- if (of_find_property(np, "lantiq,pins", NULL))
+- dev_err(pctldev->dev,
+- "%s mixes pins and groups settings\n",
+- np->name);
+- return 0;
+ }
+
+ for (i = 0; i < info->num_params; i++) {
+@@ -103,7 +112,7 @@
+ }
+
+ if (!num_configs)
+- return -EINVAL;
++ return;
+
+ of_property_for_each_string(np, "lantiq,pins", prop, pin) {
+ (*map)->data.configs.configs = kmemdup(configs,
+@@ -115,7 +124,16 @@
+ (*map)->data.configs.num_configs = num_configs;
+ (*map)++;
+ }
+- return 0;
++ of_property_for_each_string(np, "lantiq,groups", prop, group) {
++ (*map)->data.configs.configs = kmemdup(configs,
++ num_configs * sizeof(unsigned long),
++ GFP_KERNEL);
++ (*map)->type = PIN_MAP_TYPE_CONFIGS_GROUP;
++ (*map)->name = group;
++ (*map)->data.configs.group_or_pin = group;
++ (*map)->data.configs.num_configs = num_configs;
++ (*map)++;
++ }
+ }
+
+ static int ltq_pinctrl_dt_subnode_size(struct device_node *np)
+@@ -135,23 +153,19 @@
+ {
+ struct pinctrl_map *tmp;
+ struct device_node *np;
+- int ret;
++ int max_maps = 0;
+
+- *num_maps = 0;
+ for_each_child_of_node(np_config, np)
+- *num_maps += ltq_pinctrl_dt_subnode_size(np);
+- *map = kzalloc(*num_maps * sizeof(struct pinctrl_map), GFP_KERNEL);
++ max_maps += ltq_pinctrl_dt_subnode_size(np);
++ *map = kzalloc(max_maps * sizeof(struct pinctrl_map) * 2, GFP_KERNEL);
+ if (!*map)
+ return -ENOMEM;
+ tmp = *map;
+
+- for_each_child_of_node(np_config, np) {
+- ret = ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp);
+- if (ret < 0) {
+- ltq_pinctrl_dt_free_map(pctldev, *map, *num_maps);
+- return ret;
+- }
+- }
++ for_each_child_of_node(np_config, np)
++ ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp);
++ *num_maps = ((int)(tmp - *map));
++
+ return 0;
+ }
+
+Index: linux-3.7-rc8/drivers/pinctrl/pinctrl-lantiq.h
+===================================================================
+--- linux-3.7-rc8.orig/drivers/pinctrl/pinctrl-lantiq.h 2012-12-03 20:22:37.000000000 +0100
++++ linux-3.7-rc8/drivers/pinctrl/pinctrl-lantiq.h 2012-12-14 22:55:26.591557194 +0100
+@@ -34,6 +34,7 @@
+ LTQ_PINCONF_PARAM_OPEN_DRAIN,
+ LTQ_PINCONF_PARAM_DRIVE_CURRENT,
+ LTQ_PINCONF_PARAM_SLEW_RATE,
++ LTQ_PINCONF_PARAM_OUTPUT,
+ };
+
+ struct ltq_cfg_param {
+Index: linux-3.7-rc8/drivers/pinctrl/pinctrl-xway.c
+===================================================================
+--- linux-3.7-rc8.orig/drivers/pinctrl/pinctrl-xway.c 2012-12-14 22:55:26.567557195 +0100
++++ linux-3.7-rc8/drivers/pinctrl/pinctrl-xway.c 2012-12-14 22:55:26.595557195 +0100
+@@ -443,7 +443,7 @@
+ else
+ reg = GPIO_OD(pin);
+ *config = LTQ_PINCONF_PACK(param,
+- !!gpio_getbit(info->membase[0], reg, PORT_PIN(pin)));
++ !gpio_getbit(info->membase[0], reg, PORT_PIN(pin)));
+ break;
+
+ case LTQ_PINCONF_PARAM_PULL:
+@@ -466,6 +466,11 @@
+ *config = LTQ_PINCONF_PACK(param, 1);
+ break;
+
++ case LTQ_PINCONF_PARAM_OUTPUT:
++ reg = GPIO_DIR(pin);
++ *config = LTQ_PINCONF_PACK(param,
++ gpio_getbit(info->membase[0], reg, PORT_PIN(pin)));
++ break;
+ default:
+ dev_err(pctldev->dev, "Invalid config param %04x\n", param);
+ return -ENOTSUPP;
+@@ -489,7 +494,10 @@
+ reg = GPIO3_OD;
+ else
+ reg = GPIO_OD(pin);
+- gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
++ if (arg == 0)
++ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
++ else
++ gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
+ break;
+
+ case LTQ_PINCONF_PARAM_PULL:
+@@ -515,6 +523,14 @@
+ dev_err(pctldev->dev, "Invalid pull value %d\n", arg);
+ break;
+
++ case LTQ_PINCONF_PARAM_OUTPUT:
++ reg = GPIO_DIR(pin);
++ if (arg == 0)
++ gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
++ else
++ gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
++ break;
++
+ default:
+ dev_err(pctldev->dev, "Invalid config param %04x\n", param);
+ return -ENOTSUPP;
+@@ -522,9 +538,25 @@
+ return 0;
+ }
+
++int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
++ unsigned selector,
++ unsigned long config)
++{
++ struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
++ int i, ret = 0;
++
++ for (i = 0; i < info->grps[selector].npins && !ret; i++)
++ ret = xway_pinconf_set(pctldev,
++ info->grps[selector].pins[i], config);
++
++ return ret;
++}
++
++
+ struct pinconf_ops xway_pinconf_ops = {
+ .pin_config_get = xway_pinconf_get,
+ .pin_config_set = xway_pinconf_set,
++ .pin_config_group_set = xway_pinconf_group_set,
+ };
+
+ static struct pinctrl_desc xway_pctrl_desc = {
+@@ -532,10 +564,9 @@
+ .confops = &xway_pinconf_ops,
+ };
+
+-static inline int xway_mux_apply(struct pinctrl_dev *pctrldev,
++static int mux_apply(struct ltq_pinmux_info *info,
+ int pin, int mux)
+ {
+- struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+ int port = PORT(pin);
+ u32 alt1_reg = GPIO_ALT1(pin);
+
+@@ -555,9 +586,18 @@
+ return 0;
+ }
+
++static inline int xway_mux_apply(struct pinctrl_dev *pctrldev,
++ int pin, int mux)
++{
++ struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
++
++ return mux_apply(info, pin, mux);
++}
++
+ static const struct ltq_cfg_param xway_cfg_params[] = {
+ {"lantiq,pull", LTQ_PINCONF_PARAM_PULL},
+ {"lantiq,open-drain", LTQ_PINCONF_PARAM_OPEN_DRAIN},
++ {"lantiq,output", LTQ_PINCONF_PARAM_OUTPUT},
+ };
+
+ static struct ltq_pinmux_info xway_info = {
+@@ -598,6 +638,10 @@
+ {
+ struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+
++ if (PORT(pin) == PORT3)
++ gpio_setbit(info->membase[0], GPIO3_OD, PORT_PIN(pin));
++ else
++ gpio_setbit(info->membase[0], GPIO_OD(pin), PORT_PIN(pin));
+ gpio_setbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
+ xway_gpio_set(chip, pin, val);
+
+@@ -618,6 +662,18 @@
+ pinctrl_free_gpio(gpio);
+ }
+
++static int xway_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
++ int i;
++
++ for (i = 0; i < info->num_exin; i++)
++ if (info->exin[i] == offset)
++ return ltq_eiu_get_irq(i);
++
++ return -1;
++}
++
+ static struct gpio_chip xway_chip = {
+ .label = "gpio-xway",
+ .direction_input = xway_gpio_dir_in,
+@@ -626,6 +682,7 @@
+ .set = xway_gpio_set,
+ .request = xway_gpio_req,
+ .free = xway_gpio_free,
++ .to_irq = xway_gpio_to_irq,
+ .base = -1,
+ };
+
diff --git a/target/linux/lantiq/patches-3.7/0109-GPIO-MIPS-add-gpio-driver-for-falcon-SoC.patch b/target/linux/lantiq/patches-3.7/0109-GPIO-MIPS-add-gpio-driver-for-falcon-SoC.patch
new file mode 100644
index 0000000000..c76a2a146a
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0109-GPIO-MIPS-add-gpio-driver-for-falcon-SoC.patch
@@ -0,0 +1,404 @@
+From d4911be1cc44c8d3ca72b03d5da13f792d4a02d2 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sat, 23 Jun 2012 15:32:33 +0200
+Subject: [PATCH 109/123] GPIO: MIPS: add gpio driver for falcon SoC
+
+Add driver for GPIO blocks found on Lantiq FALCON SoC. The SoC has 5 banks of
+up to 32 pads. The GPIO blocks have a per pin IRQs.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Cc: linux-kernel@vger.kernel.org
+---
+ drivers/gpio/Kconfig | 5 +
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-falcon.c | 349 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 355 insertions(+)
+ create mode 100644 drivers/gpio/gpio-falcon.c
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 47150f5..0647e07 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -114,6 +114,11 @@ config GPIO_EP93XX
+ depends on ARCH_EP93XX
+ select GPIO_GENERIC
+
++config GPIO_FALCON
++ def_bool y
++ depends on MIPS && SOC_FALCON
++ select GPIO_GENERIC
++
+ config GPIO_MM_LANTIQ
+ bool "Lantiq Memory mapped GPIOs"
+ depends on LANTIQ && SOC_XWAY
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index 9aeed67..2a9e4a2 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
+ obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
+ obj-$(CONFIG_GPIO_EM) += gpio-em.o
+ obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
++obj-$(CONFIG_GPIO_FALCON) += gpio-falcon.o
+ obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
+ obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
+ obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
+diff --git a/drivers/gpio/gpio-falcon.c b/drivers/gpio/gpio-falcon.c
+new file mode 100644
+index 0000000..ae8b55d
+--- /dev/null
++++ b/drivers/gpio/gpio-falcon.c
+@@ -0,0 +1,349 @@
++/*
++ * 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) 2012 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/export.h>
++#include <linux/err.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/pinctrl/consumer.h>
++#include <linux/platform_device.h>
++
++#include <lantiq_soc.h>
++
++/* Data Output Register */
++#define GPIO_OUT 0x00000000
++/* Data Input Register */
++#define GPIO_IN 0x00000004
++/* Direction Register */
++#define GPIO_DIR 0x00000008
++/* External Interrupt Control Register 0 */
++#define GPIO_EXINTCR0 0x00000018
++/* External Interrupt Control Register 1 */
++#define GPIO_EXINTCR1 0x0000001C
++/* IRN Capture Register */
++#define GPIO_IRNCR 0x00000020
++/* IRN Interrupt Configuration Register */
++#define GPIO_IRNCFG 0x0000002C
++/* IRN Interrupt Enable Set Register */
++#define GPIO_IRNRNSET 0x00000030
++/* IRN Interrupt Enable Clear Register */
++#define GPIO_IRNENCLR 0x00000034
++/* Output Set Register */
++#define GPIO_OUTSET 0x00000040
++/* Output Cler Register */
++#define GPIO_OUTCLR 0x00000044
++/* Direction Clear Register */
++#define GPIO_DIRSET 0x00000048
++/* Direction Set Register */
++#define GPIO_DIRCLR 0x0000004C
++
++/* turn a gpio_chip into a falcon_gpio_port */
++#define ctop(c) container_of(c, struct falcon_gpio_port, gpio_chip)
++/* turn a irq_data into a falcon_gpio_port */
++#define itop(i) ((struct falcon_gpio_port *) irq_get_chip_data(i->irq))
++
++#define port_r32(p, reg) ltq_r32(p->port + reg)
++#define port_w32(p, val, reg) ltq_w32(val, p->port + reg)
++#define port_w32_mask(p, clear, set, reg) \
++ port_w32(p, (port_r32(p, reg) & ~(clear)) | (set), reg)
++
++#define MAX_PORTS 5
++#define PINS_PER_PORT 32
++
++struct falcon_gpio_port {
++ struct gpio_chip gpio_chip;
++ void __iomem *port;
++ unsigned int irq_base;
++ unsigned int chained_irq;
++ struct clk *clk;
++ char name[6];
++};
++
++static int falcon_gpio_direction_input(struct gpio_chip *chip,
++ unsigned int offset)
++{
++ port_w32(ctop(chip), 1 << offset, GPIO_DIRCLR);
++
++ return 0;
++}
++
++static void falcon_gpio_set(struct gpio_chip *chip, unsigned int offset,
++ int value)
++{
++ if (value)
++ port_w32(ctop(chip), 1 << offset, GPIO_OUTSET);
++ else
++ port_w32(ctop(chip), 1 << offset, GPIO_OUTCLR);
++}
++
++static int falcon_gpio_direction_output(struct gpio_chip *chip,
++ unsigned int offset, int value)
++{
++ falcon_gpio_set(chip, offset, value);
++ port_w32(ctop(chip), 1 << offset, GPIO_DIRSET);
++
++ return 0;
++}
++
++static int falcon_gpio_get(struct gpio_chip *chip, unsigned int offset)
++{
++ if ((port_r32(ctop(chip), GPIO_DIR) >> offset) & 1)
++ return (port_r32(ctop(chip), GPIO_OUT) >> offset) & 1;
++ else
++ return (port_r32(ctop(chip), GPIO_IN) >> offset) & 1;
++}
++
++static int falcon_gpio_request(struct gpio_chip *chip, unsigned offset)
++{
++ int gpio = chip->base + offset;
++
++ return pinctrl_request_gpio(gpio);
++}
++
++static void falcon_gpio_free(struct gpio_chip *chip, unsigned offset)
++{
++ int gpio = chip->base + offset;
++
++ pinctrl_free_gpio(gpio);
++}
++
++static int falcon_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ return ctop(chip)->irq_base + offset;
++}
++
++static void falcon_gpio_disable_irq(struct irq_data *d)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++
++ port_w32(itop(d), 1 << offset, GPIO_IRNENCLR);
++}
++
++static void falcon_gpio_enable_irq(struct irq_data *d)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++
++ port_w32(itop(d), 1 << offset, GPIO_IRNRNSET);
++}
++
++static void falcon_gpio_ack_irq(struct irq_data *d)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++
++ port_w32(itop(d), 1 << offset, GPIO_IRNCR);
++}
++
++static void falcon_gpio_mask_and_ack_irq(struct irq_data *d)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++
++ port_w32(itop(d), 1 << offset, GPIO_IRNENCLR);
++ port_w32(itop(d), 1 << offset, GPIO_IRNCR);
++}
++
++static struct irq_chip falcon_gpio_irq_chip;
++static int falcon_gpio_irq_type(struct irq_data *d, unsigned int type)
++{
++ unsigned int offset = d->irq - itop(d)->irq_base;
++ unsigned int mask = 1 << offset;
++
++ if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE)
++ return 0;
++
++ if ((type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) != 0) {
++ /* level triggered */
++ port_w32_mask(itop(d), 0, mask, GPIO_IRNCFG);
++ irq_set_chip_and_handler_name(d->irq,
++ &falcon_gpio_irq_chip, handle_level_irq, "mux");
++ } else {
++ /* edge triggered */
++ port_w32_mask(itop(d), mask, 0, GPIO_IRNCFG);
++ irq_set_chip_and_handler_name(d->irq,
++ &falcon_gpio_irq_chip, handle_simple_irq, "mux");
++ }
++
++ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
++ port_w32_mask(itop(d), mask, 0, GPIO_EXINTCR0);
++ port_w32_mask(itop(d), 0, mask, GPIO_EXINTCR1);
++ } else {
++ if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH)) != 0)
++ /* positive logic: rising edge, high level */
++ port_w32_mask(itop(d), mask, 0, GPIO_EXINTCR0);
++ else
++ /* negative logic: falling edge, low level */
++ port_w32_mask(itop(d), 0, mask, GPIO_EXINTCR0);
++ port_w32_mask(itop(d), mask, 0, GPIO_EXINTCR1);
++ }
++
++ return gpio_direction_input(itop(d)->gpio_chip.base + offset);
++}
++
++static void falcon_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
++{
++ struct falcon_gpio_port *gpio_port = irq_desc_get_handler_data(desc);
++ unsigned long irncr;
++ int offset;
++
++ /* acknowledge interrupt */
++ irncr = port_r32(gpio_port, GPIO_IRNCR);
++ port_w32(gpio_port, irncr, GPIO_IRNCR);
++
++ desc->irq_data.chip->irq_ack(&desc->irq_data);
++
++ for_each_set_bit(offset, &irncr, gpio_port->gpio_chip.ngpio)
++ generic_handle_irq(gpio_port->irq_base + offset);
++}
++
++static int falcon_gpio_irq_map(struct irq_domain *d, unsigned int irq,
++ irq_hw_number_t hw)
++{
++ struct falcon_gpio_port *port = d->host_data;
++
++ irq_set_chip_and_handler_name(irq, &falcon_gpio_irq_chip,
++ handle_simple_irq, "mux");
++ irq_set_chip_data(irq, port);
++
++ /* set to negative logic (falling edge, low level) */
++ port_w32_mask(port, 0, 1 << hw, GPIO_EXINTCR0);
++ return 0;
++}
++
++static struct irq_chip falcon_gpio_irq_chip = {
++ .name = "gpio_irq_mux",
++ .irq_mask = falcon_gpio_disable_irq,
++ .irq_unmask = falcon_gpio_enable_irq,
++ .irq_ack = falcon_gpio_ack_irq,
++ .irq_mask_ack = falcon_gpio_mask_and_ack_irq,
++ .irq_set_type = falcon_gpio_irq_type,
++};
++
++static const struct irq_domain_ops irq_domain_ops = {
++ .xlate = irq_domain_xlate_onetwocell,
++ .map = falcon_gpio_irq_map,
++};
++
++static struct irqaction gpio_cascade = {
++ .handler = no_action,
++ .flags = IRQF_DISABLED,
++ .name = "gpio_cascade",
++};
++
++static int falcon_gpio_probe(struct platform_device *pdev)
++{
++ struct pinctrl_gpio_range *gpio_range;
++ struct device_node *node = pdev->dev.of_node;
++ const __be32 *bank = of_get_property(node, "lantiq,bank", NULL);
++ struct falcon_gpio_port *gpio_port;
++ struct resource *gpiores, irqres;
++ int ret, size;
++
++ if (!bank || *bank >= MAX_PORTS)
++ return -ENODEV;
++
++ size = pinctrl_falcon_get_range_size(*bank);
++ if (size < 1) {
++ dev_err(&pdev->dev, "pad not loaded for bank %d\n", *bank);
++ return size;
++ }
++
++ gpiores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!gpiores)
++ return -ENODEV;
++
++ gpio_range = devm_kzalloc(&pdev->dev, sizeof(struct pinctrl_gpio_range),
++ GFP_KERNEL);
++ if (!gpio_range)
++ return -ENOMEM;
++
++ gpio_port = devm_kzalloc(&pdev->dev, sizeof(struct falcon_gpio_port),
++ GFP_KERNEL);
++ if (!gpio_port)
++ return -ENOMEM;
++ snprintf(gpio_port->name, 6, "gpio%d", *bank);
++ gpio_port->gpio_chip.label = gpio_port->name;
++ gpio_port->gpio_chip.direction_input = falcon_gpio_direction_input;
++ gpio_port->gpio_chip.direction_output = falcon_gpio_direction_output;
++ gpio_port->gpio_chip.get = falcon_gpio_get;
++ gpio_port->gpio_chip.set = falcon_gpio_set;
++ gpio_port->gpio_chip.request = falcon_gpio_request;
++ gpio_port->gpio_chip.free = falcon_gpio_free;
++ gpio_port->gpio_chip.base = -1;
++ gpio_port->gpio_chip.ngpio = size;
++ gpio_port->gpio_chip.dev = &pdev->dev;
++
++ gpio_port->port = devm_request_and_ioremap(&pdev->dev, gpiores);
++ if (!gpio_port->port) {
++ dev_err(&pdev->dev, "Could not map io ranges\n");
++ return -ENOMEM;
++ }
++
++ gpio_port->clk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(gpio_port->clk)) {
++ dev_err(&pdev->dev, "Could not get clock\n");
++ return PTR_ERR(gpio_port->clk);
++ }
++ clk_enable(gpio_port->clk);
++
++ if (of_irq_to_resource_table(node, &irqres, 1) == 1) {
++ gpio_port->irq_base = INT_NUM_EXTRA_START + (32 * *bank);
++ gpio_port->gpio_chip.to_irq = falcon_gpio_to_irq;
++ gpio_port->chained_irq = irqres.start;
++ irq_domain_add_legacy(node, size, gpio_port->irq_base, 0,
++ &irq_domain_ops, gpio_port);
++ setup_irq(irqres.start, &gpio_cascade);
++ irq_set_handler_data(irqres.start, gpio_port);
++ irq_set_chained_handler(irqres.start, falcon_gpio_irq_handler);
++ }
++
++ ret = gpiochip_add(&gpio_port->gpio_chip);
++ if (!ret)
++ platform_set_drvdata(pdev, gpio_port);
++
++ gpio_range->name = "FALCON GPIO";
++ gpio_range->id = *bank;
++ gpio_range->base = gpio_port->gpio_chip.base;
++ gpio_range->npins = gpio_port->gpio_chip.ngpio;
++ gpio_range->gc = &gpio_port->gpio_chip;
++ pinctrl_falcon_add_gpio_range(gpio_range);
++
++ return ret;
++}
++
++static const struct of_device_id falcon_gpio_match[] = {
++ { .compatible = "lantiq,gpio-falcon" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, falcon_gpio_match);
++
++static struct platform_driver falcon_gpio_driver = {
++ .probe = falcon_gpio_probe,
++ .driver = {
++ .name = "gpio-falcon",
++ .owner = THIS_MODULE,
++ .of_match_table = falcon_gpio_match,
++ },
++};
++
++int __init falcon_gpio_init(void)
++{
++ int ret;
++
++ pr_info("FALC(tm) ON GPIO Driver, (C) 2012 Lantiq Deutschland Gmbh\n");
++ ret = platform_driver_register(&falcon_gpio_driver);
++ if (ret)
++ pr_err("falcon_gpio: Error registering platform driver!");
++ return ret;
++}
++
++subsys_initcall(falcon_gpio_init);
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0110-Document-devicetree-add-OF-documents-for-lantiq-seri.patch b/target/linux/lantiq/patches-3.7/0110-Document-devicetree-add-OF-documents-for-lantiq-seri.patch
new file mode 100644
index 0000000000..a553f49a02
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0110-Document-devicetree-add-OF-documents-for-lantiq-seri.patch
@@ -0,0 +1,39 @@
+From ed881db69430dd62765d02e2f4f1321ddc2f5fb5 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 20 Jul 2012 18:58:34 +0200
+Subject: [PATCH 110/123] Document: devicetree: add OF documents for lantiq
+ serial port
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: Rob Herring <rob.herring@calxeda.com>
+Cc: devicetree-discuss@lists.ozlabs.org
+---
+ .../devicetree/bindings/serial/lantiq_asc.txt | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/serial/lantiq_asc.txt
+
+diff --git a/Documentation/devicetree/bindings/serial/lantiq_asc.txt b/Documentation/devicetree/bindings/serial/lantiq_asc.txt
+new file mode 100644
+index 0000000..5b78591
+--- /dev/null
++++ b/Documentation/devicetree/bindings/serial/lantiq_asc.txt
+@@ -0,0 +1,16 @@
++Lantiq SoC ASC serial controller
++
++Required properties:
++- compatible : Should be "lantiq,asc"
++- reg : Address and length of the register set for the device
++- interrupts: the 3 (tx rx err) interrupt numbers. The interrupt specifier
++ depends on the interrupt-parent interrupt controller.
++
++Example:
++
++asc1: serial@E100C00 {
++ compatible = "lantiq,asc";
++ reg = <0xE100C00 0x400>;
++ interrupt-parent = <&icu0>;
++ interrupts = <112 113 114>;
++};
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0111-MTD-MIPS-lantiq-Add-NAND-support-on-Lantiq-FALCON-So.patch b/target/linux/lantiq/patches-3.7/0111-MTD-MIPS-lantiq-Add-NAND-support-on-Lantiq-FALCON-So.patch
new file mode 100644
index 0000000000..3f15b2180c
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0111-MTD-MIPS-lantiq-Add-NAND-support-on-Lantiq-FALCON-So.patch
@@ -0,0 +1,139 @@
+From 72112b91624dca6c636bd3a592471642d3988b27 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 20 Jul 2012 19:09:01 +0200
+Subject: [PATCH 111/123] MTD: MIPS: lantiq: Add NAND support on Lantiq FALCON
+ SoC.
+
+The driver uses plat_nand. As the platform_device is loaded from DT, we need
+to lookup the node and attach our falocn specific "struct platform_nand_data"
+to it.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Cc: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
+Cc: linux-mtd@lists.infradead.org
+---
+ drivers/mtd/nand/Kconfig | 8 ++++
+ drivers/mtd/nand/Makefile | 1 +
+ drivers/mtd/nand/falcon_nand.c | 82 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 91 insertions(+)
+ create mode 100644 drivers/mtd/nand/falcon_nand.c
+
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 4883139..a3b05be 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -572,4 +572,12 @@ config MTD_NAND_XWAY
+ Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
+ to the External Bus Unit (EBU).
+
++config MTD_NAND_FALCON
++ tristate "Support for NAND on Lantiq FALC-ON SoC"
++ depends on LANTIQ && SOC_FALCON
++ select MTD_NAND_PLATFORM
++ help
++ Enables support for NAND Flash chips on Lantiq FALC-ON SoCs. NAND is
++ attached to the External Bus Unit (EBU).
++
+ endif # MTD_NAND
+diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
+index 2cbd091..a97e1b5 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -53,5 +53,6 @@ obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
+ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
+ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
+ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
++obj-$(CONFIG_MTD_NAND_FALCON) += falcon_nand.o
+
+ nand-objs := nand_base.o nand_bbt.o
+diff --git a/drivers/mtd/nand/falcon_nand.c b/drivers/mtd/nand/falcon_nand.c
+new file mode 100644
+index 0000000..b3b850c
+--- /dev/null
++++ b/drivers/mtd/nand/falcon_nand.c
+@@ -0,0 +1,82 @@
++/*
++ * 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) 2011 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/mtd/nand.h>
++#include <linux/of_platform.h>
++
++#include <lantiq_soc.h>
++
++/* nand flash */
++/* address lines used for NAND control signals */
++#define NAND_ADDR_ALE 0x10000
++#define NAND_ADDR_CLE 0x20000
++/* Ready/Busy Status */
++#define MODCON_STS 0x0002
++/* Ready/Busy Status Edge */
++#define MODCON_STSEDGE 0x0004
++#define LTQ_EBU_MODCON 0x000C
++
++static const char *part_probes[] = { "cmdlinepart", "ofpart", NULL };
++
++static int falcon_nand_ready(struct mtd_info *mtd)
++{
++ u32 modcon = ltq_ebu_r32(LTQ_EBU_MODCON);
++
++ return (((modcon & (MODCON_STS | MODCON_STSEDGE)) ==
++ (MODCON_STS | MODCON_STSEDGE)));
++}
++
++static void falcon_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++ struct nand_chip *this = mtd->priv;
++ unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
++
++ if (ctrl & NAND_CTRL_CHANGE) {
++ nandaddr &= ~(NAND_ADDR_ALE | NAND_ADDR_CLE);
++
++ if (ctrl & NAND_CLE)
++ nandaddr |= NAND_ADDR_CLE;
++ if (ctrl & NAND_ALE)
++ nandaddr |= NAND_ADDR_ALE;
++
++ this->IO_ADDR_W = (void __iomem *) nandaddr;
++ }
++
++ if (cmd != NAND_CMD_NONE)
++ writeb(cmd, this->IO_ADDR_W);
++}
++
++static struct platform_nand_data falcon_nand_data = {
++ .chip = {
++ .nr_chips = 1,
++ .chip_delay = 25,
++ .part_probe_types = part_probes,
++ },
++ .ctrl = {
++ .cmd_ctrl = falcon_hwcontrol,
++ .dev_ready = falcon_nand_ready,
++ }
++};
++
++static int __init falcon_register_nand(void)
++{
++ struct device_node *node;
++ struct platform_device *pdev;
++
++ node = of_find_compatible_node(NULL, NULL, "lantiq,nand-falcon");
++ if (!node)
++ return -1;
++ pdev = of_find_device_by_node(node);
++ if (pdev)
++ pdev->dev.platform_data = &falcon_nand_data;
++ of_node_put(node);
++ return 0;
++}
++
++arch_initcall(falcon_register_nand);
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0112-MTD-lantiq-xway-fix-NAND-reset-timeout-handling.patch b/target/linux/lantiq/patches-3.7/0112-MTD-lantiq-xway-fix-NAND-reset-timeout-handling.patch
new file mode 100644
index 0000000000..447c0615c0
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0112-MTD-lantiq-xway-fix-NAND-reset-timeout-handling.patch
@@ -0,0 +1,47 @@
+From d8d9b9055d704d6f84ef6346d6826b8a9640f209 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 22 Oct 2012 10:25:39 +0200
+Subject: [PATCH 112/123] MTD: lantiq: xway: fix NAND reset timeout handling
+
+Fixes a possible deadlock in the code that resets the NAND flash.
+
+http://lists.infradead.org/pipermail/linux-mtd/2012-September/044240.html
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/mtd/nand/xway_nand.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c
+index 3f81dc8..4731300 100644
+--- a/drivers/mtd/nand/xway_nand.c
++++ b/drivers/mtd/nand/xway_nand.c
+@@ -58,15 +58,23 @@ static void xway_reset_chip(struct nand_chip *chip)
+ {
+ unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W;
+ unsigned long flags;
++ unsigned long timeout;
+
+ nandaddr &= ~NAND_WRITE_ADDR;
+ nandaddr |= NAND_WRITE_CMD;
+
+ /* finish with a reset */
++ timeout = jiffies + msecs_to_jiffies(200);
++
+ spin_lock_irqsave(&ebu_lock, flags);
++
+ writeb(NAND_WRITE_CMD_RESET, (void __iomem *) nandaddr);
+- while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
+- ;
++ do {
++ if ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
++ break;
++ cond_resched();
++ } while (!time_after_eq(jiffies, timeout));
++
+ spin_unlock_irqrestore(&ebu_lock, flags);
+ }
+
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0113-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch b/target/linux/lantiq/patches-3.7/0113-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch
new file mode 100644
index 0000000000..863f790539
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0113-I2C-MIPS-lantiq-add-FALC-ON-i2c-bus-master.patch
@@ -0,0 +1,1047 @@
+From f2ac37c0a5297ca4663da9e4328c77736504b484 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Sun, 20 May 2012 00:42:39 +0200
+Subject: [PATCH 113/123] I2C: MIPS: lantiq: add FALC-ON i2c bus master
+
+This patch adds the driver needed to make the I2C bus work on FALC-ON SoCs.
+
+Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/i2c/busses/Kconfig | 10 +
+ drivers/i2c/busses/Makefile | 1 +
+ drivers/i2c/busses/i2c-lantiq.c | 747 +++++++++++++++++++++++++++++++++++++++
+ drivers/i2c/busses/i2c-lantiq.h | 234 ++++++++++++
+ 4 files changed, 992 insertions(+)
+ create mode 100644 drivers/i2c/busses/i2c-lantiq.c
+ create mode 100644 drivers/i2c/busses/i2c-lantiq.h
+
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index e9df461..e03f821 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -460,6 +460,16 @@ config I2C_IOP3XX
+ This driver can also be built as a module. If so, the module
+ will be called i2c-iop3xx.
+
++config I2C_LANTIQ
++ tristate "Lantiq I2C interface"
++ depends on LANTIQ && SOC_FALCON
++ help
++ If you say yes to this option, support will be included for the
++ Lantiq I2C core.
++
++ This driver can also be built as a module. If so, the module
++ will be called i2c-lantiq.
++
+ config I2C_MPC
+ tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
+ depends on PPC
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index 395b516..74a789a 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -45,6 +45,7 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
+ obj-$(CONFIG_I2C_IMX) += i2c-imx.o
+ obj-$(CONFIG_I2C_INTEL_MID) += i2c-intel-mid.o
+ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
++obj-$(CONFIG_I2C_LANTIQ) += i2c-lantiq.o
+ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
+ obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
+ obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
+diff --git a/drivers/i2c/busses/i2c-lantiq.c b/drivers/i2c/busses/i2c-lantiq.c
+new file mode 100644
+index 0000000..9a5f58b
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-lantiq.c
+@@ -0,0 +1,747 @@
++
++/*
++ * Lantiq I2C bus adapter
++ *
++ * Parts based on i2c-designware.c and other i2c drivers from Linux 2.6.33
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You 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.
++ *
++ * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/slab.h> /* for kzalloc, kfree */
++#include <linux/i2c.h>
++#include <linux/errno.h>
++#include <linux/completion.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/of_irq.h>
++#include <linux/of_i2c.h>
++
++#include <lantiq_soc.h>
++#include "i2c-lantiq.h"
++
++/*
++ * CURRENT ISSUES:
++ * - no high speed support
++ * - ten bit mode is not tested (no slave devices)
++ */
++
++/* access macros */
++#define i2c_r32(reg) \
++ __raw_readl(&(priv->membase)->reg)
++#define i2c_w32(val, reg) \
++ __raw_writel(val, &(priv->membase)->reg)
++#define i2c_w32_mask(clear, set, reg) \
++ i2c_w32((i2c_r32(reg) & ~(clear)) | (set), reg)
++
++#define DRV_NAME "i2c-lantiq"
++#define DRV_VERSION "1.00"
++
++#define LTQ_I2C_BUSY_TIMEOUT 20 /* ms */
++
++#ifdef DEBUG
++#define LTQ_I2C_XFER_TIMEOUT (25*HZ)
++#else
++#define LTQ_I2C_XFER_TIMEOUT HZ
++#endif
++
++#define LTQ_I2C_IMSC_DEFAULT_MASK (I2C_IMSC_I2C_P_INT_EN | \
++ I2C_IMSC_I2C_ERR_INT_EN)
++
++#define LTQ_I2C_ARB_LOST (1 << 0)
++#define LTQ_I2C_NACK (1 << 1)
++#define LTQ_I2C_RX_UFL (1 << 2)
++#define LTQ_I2C_RX_OFL (1 << 3)
++#define LTQ_I2C_TX_UFL (1 << 4)
++#define LTQ_I2C_TX_OFL (1 << 5)
++
++struct ltq_i2c {
++ struct mutex mutex;
++
++
++ /* active clock settings */
++ unsigned int input_clock; /* clock input for i2c hardware block */
++ unsigned int i2c_clock; /* approximated bus clock in kHz */
++
++ struct clk *clk_gate;
++ struct clk *clk_input;
++
++
++ /* resources (memory and interrupts) */
++ int irq_lb; /* last burst irq */
++
++ struct lantiq_reg_i2c __iomem *membase; /* base of mapped registers */
++
++ struct i2c_adapter adap;
++ struct device *dev;
++
++ struct completion cmd_complete;
++
++
++ /* message transfer data */
++ struct i2c_msg *current_msg; /* current message */
++ int msgs_num; /* number of messages to handle */
++ u8 *msg_buf; /* current buffer */
++ u32 msg_buf_len; /* remaining length of current buffer */
++ int msg_err; /* error status of the current transfer */
++
++
++ /* master status codes */
++ enum {
++ STATUS_IDLE,
++ STATUS_ADDR, /* address phase */
++ STATUS_WRITE,
++ STATUS_READ,
++ STATUS_READ_END,
++ STATUS_STOP
++ } status;
++};
++
++static irqreturn_t ltq_i2c_isr(int irq, void *dev_id);
++
++static inline void enable_burst_irq(struct ltq_i2c *priv)
++{
++ i2c_w32_mask(0, I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, imsc);
++}
++static inline void disable_burst_irq(struct ltq_i2c *priv)
++{
++ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, 0, imsc);
++}
++
++static void prepare_msg_send_addr(struct ltq_i2c *priv)
++{
++ struct i2c_msg *msg = priv->current_msg;
++ int rd = !!(msg->flags & I2C_M_RD); /* extends to 0 or 1 */
++ u16 addr = msg->addr;
++
++ /* new i2c_msg */
++ priv->msg_buf = msg->buf;
++ priv->msg_buf_len = msg->len;
++ if (rd)
++ priv->status = STATUS_READ;
++ else
++ priv->status = STATUS_WRITE;
++
++ /* send slave address */
++ if (msg->flags & I2C_M_TEN) {
++ i2c_w32(0xf0 | ((addr & 0x300) >> 7) | rd, txd);
++ i2c_w32(addr & 0xff, txd);
++ } else {
++ i2c_w32((addr & 0x7f) << 1 | rd, txd);
++ }
++}
++
++static void ltq_i2c_set_tx_len(struct ltq_i2c *priv)
++{
++ struct i2c_msg *msg = priv->current_msg;
++ int len = (msg->flags & I2C_M_TEN) ? 2 : 1;
++
++ pr_debug("set_tx_len %cX\n", (msg->flags & I2C_M_RD) ? 'R' : 'T');
++
++ priv->status = STATUS_ADDR;
++
++ if (!(msg->flags & I2C_M_RD))
++ len += msg->len;
++ else
++ /* set maximum received packet size (before rx int!) */
++ i2c_w32(msg->len, mrps_ctrl);
++ i2c_w32(len, tps_ctrl);
++ enable_burst_irq(priv);
++}
++
++static int ltq_i2c_hw_set_clock(struct i2c_adapter *adap)
++{
++ struct ltq_i2c *priv = i2c_get_adapdata(adap);
++ unsigned int input_clock = clk_get_rate(priv->clk_input);
++ u32 dec, inc = 1;
++
++ /* clock changed? */
++ if (priv->input_clock == input_clock)
++ return 0;
++
++ /*
++ * this formula is only an approximation, found by the recommended
++ * values in the "I2C Architecture Specification 1.7.1"
++ */
++ dec = input_clock / (priv->i2c_clock * 2);
++ if (dec <= 6)
++ return -ENXIO;
++
++ i2c_w32(0, fdiv_high_cfg);
++ i2c_w32((inc << I2C_FDIV_CFG_INC_OFFSET) |
++ (dec << I2C_FDIV_CFG_DEC_OFFSET),
++ fdiv_cfg);
++
++ dev_info(priv->dev, "setup clocks (in %d kHz, bus %d kHz, dec=%d)\n",
++ input_clock, priv->i2c_clock, dec);
++
++ priv->input_clock = input_clock;
++ return 0;
++}
++
++static int ltq_i2c_hw_init(struct i2c_adapter *adap)
++{
++ int ret = 0;
++ struct ltq_i2c *priv = i2c_get_adapdata(adap);
++
++ /* disable bus */
++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
++
++#ifndef DEBUG
++ /* set normal operation clock divider */
++ i2c_w32(1 << I2C_CLC_RMC_OFFSET, clc);
++#else
++ /* for debugging a higher divider value! */
++ i2c_w32(0xF0 << I2C_CLC_RMC_OFFSET, clc);
++#endif
++
++ /* setup clock */
++ ret = ltq_i2c_hw_set_clock(adap);
++ if (ret != 0) {
++ dev_warn(priv->dev, "invalid clock settings\n");
++ return ret;
++ }
++
++ /* configure fifo */
++ i2c_w32(I2C_FIFO_CFG_TXFC | /* tx fifo as flow controller */
++ I2C_FIFO_CFG_RXFC | /* rx fifo as flow controller */
++ I2C_FIFO_CFG_TXFA_TXFA2 | /* tx fifo 4-byte aligned */
++ I2C_FIFO_CFG_RXFA_RXFA2 | /* rx fifo 4-byte aligned */
++ I2C_FIFO_CFG_TXBS_TXBS0 | /* tx fifo burst size is 1 word */
++ I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */
++ fifo_cfg);
++
++ /* configure address */
++ i2c_w32(I2C_ADDR_CFG_SOPE_EN | /* generate stop when no more data in
++ the fifo */
++ I2C_ADDR_CFG_SONA_EN | /* generate stop when NA received */
++ I2C_ADDR_CFG_MnS_EN | /* we are master device */
++ 0, /* our slave address (not used!) */
++ addr_cfg);
++
++ /* enable bus */
++ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
++
++ return 0;
++}
++
++static int ltq_i2c_wait_bus_not_busy(struct ltq_i2c *priv)
++{
++ unsigned long timeout;
++
++ timeout = jiffies + msecs_to_jiffies(LTQ_I2C_BUSY_TIMEOUT);
++
++ do {
++ u32 stat = i2c_r32(bus_stat);
++
++ if ((stat & I2C_BUS_STAT_BS_MASK) == I2C_BUS_STAT_BS_FREE)
++ return 0;
++
++ cond_resched();
++ } while (!time_after_eq(jiffies, timeout));
++
++ dev_err(priv->dev, "timeout waiting for bus ready\n");
++ return -ETIMEDOUT;
++}
++
++static void ltq_i2c_tx(struct ltq_i2c *priv, int last)
++{
++ if (priv->msg_buf_len && priv->msg_buf) {
++ i2c_w32(*priv->msg_buf, txd);
++
++ if (--priv->msg_buf_len)
++ priv->msg_buf++;
++ else
++ priv->msg_buf = NULL;
++ } else {
++ last = 1;
++ }
++
++ if (last)
++ disable_burst_irq(priv);
++}
++
++static void ltq_i2c_rx(struct ltq_i2c *priv, int last)
++{
++ u32 fifo_stat, timeout;
++ if (priv->msg_buf_len && priv->msg_buf) {
++ timeout = 5000000;
++ do {
++ fifo_stat = i2c_r32(ffs_stat);
++ } while (!fifo_stat && --timeout);
++ if (!timeout) {
++ last = 1;
++ pr_debug("\nrx timeout\n");
++ goto err;
++ }
++ while (fifo_stat) {
++ *priv->msg_buf = i2c_r32(rxd);
++ if (--priv->msg_buf_len) {
++ priv->msg_buf++;
++ } else {
++ priv->msg_buf = NULL;
++ last = 1;
++ break;
++ }
++ /*
++ * do not read more than burst size, otherwise no "last
++ * burst" is generated and the transaction is blocked!
++ */
++ fifo_stat = 0;
++ }
++ } else {
++ last = 1;
++ }
++err:
++ if (last) {
++ disable_burst_irq(priv);
++
++ if (priv->status == STATUS_READ_END) {
++ /*
++ * do the STATUS_STOP and complete() here, as sometimes
++ * the tx_end is already seen before this is finished
++ */
++ priv->status = STATUS_STOP;
++ complete(&priv->cmd_complete);
++ } else {
++ i2c_w32(I2C_ENDD_CTRL_SETEND, endd_ctrl);
++ priv->status = STATUS_READ_END;
++ }
++ }
++}
++
++static void ltq_i2c_xfer_init(struct ltq_i2c *priv)
++{
++ /* enable interrupts */
++ i2c_w32(LTQ_I2C_IMSC_DEFAULT_MASK, imsc);
++
++ /* trigger transfer of first msg */
++ ltq_i2c_set_tx_len(priv);
++}
++
++static void dump_msgs(struct i2c_msg msgs[], int num, int rx)
++{
++#if defined(DEBUG)
++ int i, j;
++ pr_debug("Messages %d %s\n", num, rx ? "out" : "in");
++ for (i = 0; i < num; i++) {
++ pr_debug("%2d %cX Msg(%d) addr=0x%X: ", i,
++ (msgs[i].flags & I2C_M_RD) ? 'R' : 'T',
++ msgs[i].len, msgs[i].addr);
++ if (!(msgs[i].flags & I2C_M_RD) || rx) {
++ for (j = 0; j < msgs[i].len; j++)
++ pr_debug("%02X ", msgs[i].buf[j]);
++ }
++ pr_debug("\n");
++ }
++#endif
++}
++
++static void ltq_i2c_release_bus(struct ltq_i2c *priv)
++{
++ if ((i2c_r32(bus_stat) & I2C_BUS_STAT_BS_MASK) == I2C_BUS_STAT_BS_BM)
++ i2c_w32(I2C_ENDD_CTRL_SETEND, endd_ctrl);
++}
++
++static int ltq_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
++ int num)
++{
++ struct ltq_i2c *priv = i2c_get_adapdata(adap);
++ int ret;
++
++ dev_dbg(priv->dev, "xfer %u messages\n", num);
++ dump_msgs(msgs, num, 0);
++
++ mutex_lock(&priv->mutex);
++
++ INIT_COMPLETION(priv->cmd_complete);
++ priv->current_msg = msgs;
++ priv->msgs_num = num;
++ priv->msg_err = 0;
++ priv->status = STATUS_IDLE;
++
++ /* wait for the bus to become ready */
++ ret = ltq_i2c_wait_bus_not_busy(priv);
++ if (ret)
++ goto done;
++
++ while (priv->msgs_num) {
++ /* start the transfers */
++ ltq_i2c_xfer_init(priv);
++
++ /* wait for transfers to complete */
++ ret = wait_for_completion_interruptible_timeout(
++ &priv->cmd_complete, LTQ_I2C_XFER_TIMEOUT);
++ if (ret == 0) {
++ dev_err(priv->dev, "controller timed out\n");
++ ltq_i2c_hw_init(adap);
++ ret = -ETIMEDOUT;
++ goto done;
++ } else if (ret < 0)
++ goto done;
++
++ if (priv->msg_err) {
++ if (priv->msg_err & LTQ_I2C_NACK)
++ ret = -ENXIO;
++ else
++ ret = -EREMOTEIO;
++ goto done;
++ }
++ if (--priv->msgs_num)
++ priv->current_msg++;
++ }
++ /* no error? */
++ ret = num;
++
++done:
++ ltq_i2c_release_bus(priv);
++
++ mutex_unlock(&priv->mutex);
++
++ if (ret >= 0)
++ dump_msgs(msgs, num, 1);
++
++ pr_debug("XFER ret %d\n", ret);
++ return ret;
++}
++
++static irqreturn_t ltq_i2c_isr_burst(int irq, void *dev_id)
++{
++ struct ltq_i2c *priv = dev_id;
++ struct i2c_msg *msg = priv->current_msg;
++ int last = (irq == priv->irq_lb);
++
++ if (last)
++ pr_debug("LB ");
++ else
++ pr_debug("B ");
++
++ if (msg->flags & I2C_M_RD) {
++ switch (priv->status) {
++ case STATUS_ADDR:
++ pr_debug("X");
++ prepare_msg_send_addr(priv);
++ disable_burst_irq(priv);
++ break;
++ case STATUS_READ:
++ case STATUS_READ_END:
++ pr_debug("R");
++ ltq_i2c_rx(priv, last);
++ break;
++ default:
++ disable_burst_irq(priv);
++ pr_warn("Status R %d\n", priv->status);
++ break;
++ }
++ } else {
++ switch (priv->status) {
++ case STATUS_ADDR:
++ pr_debug("x");
++ prepare_msg_send_addr(priv);
++ break;
++ case STATUS_WRITE:
++ pr_debug("w");
++ ltq_i2c_tx(priv, last);
++ break;
++ default:
++ disable_burst_irq(priv);
++ pr_warn("Status W %d\n", priv->status);
++ break;
++ }
++ }
++
++ i2c_w32(I2C_ICR_BREQ_INT_CLR | I2C_ICR_LBREQ_INT_CLR, icr);
++ return IRQ_HANDLED;
++}
++
++static void ltq_i2c_isr_prot(struct ltq_i2c *priv)
++{
++ u32 i_pro = i2c_r32(p_irqss);
++
++ pr_debug("i2c-p");
++
++ /* not acknowledge */
++ if (i_pro & I2C_P_IRQSS_NACK) {
++ priv->msg_err |= LTQ_I2C_NACK;
++ pr_debug(" nack");
++ }
++
++ /* arbitration lost */
++ if (i_pro & I2C_P_IRQSS_AL) {
++ priv->msg_err |= LTQ_I2C_ARB_LOST;
++ pr_debug(" arb-lost");
++ }
++ /* tx -> rx switch */
++ if (i_pro & I2C_P_IRQSS_RX)
++ pr_debug(" rx");
++
++ /* tx end */
++ if (i_pro & I2C_P_IRQSS_TX_END)
++ pr_debug(" txend");
++ pr_debug("\n");
++
++ if (!priv->msg_err) {
++ /* tx -> rx switch */
++ if (i_pro & I2C_P_IRQSS_RX) {
++ priv->status = STATUS_READ;
++ enable_burst_irq(priv);
++ }
++ if (i_pro & I2C_P_IRQSS_TX_END) {
++ if (priv->status == STATUS_READ)
++ priv->status = STATUS_READ_END;
++ else {
++ disable_burst_irq(priv);
++ priv->status = STATUS_STOP;
++ }
++ }
++ }
++
++ i2c_w32(i_pro, p_irqsc);
++}
++
++static irqreturn_t ltq_i2c_isr(int irq, void *dev_id)
++{
++ u32 i_raw, i_err = 0;
++ struct ltq_i2c *priv = dev_id;
++
++ i_raw = i2c_r32(mis);
++ pr_debug("i_raw 0x%08X\n", i_raw);
++
++ /* error interrupt */
++ if (i_raw & I2C_RIS_I2C_ERR_INT_INTOCC) {
++ i_err = i2c_r32(err_irqss);
++ pr_debug("i_err 0x%08X bus_stat 0x%04X\n",
++ i_err, i2c_r32(bus_stat));
++
++ /* tx fifo overflow (8) */
++ if (i_err & I2C_ERR_IRQSS_TXF_OFL)
++ priv->msg_err |= LTQ_I2C_TX_OFL;
++
++ /* tx fifo underflow (4) */
++ if (i_err & I2C_ERR_IRQSS_TXF_UFL)
++ priv->msg_err |= LTQ_I2C_TX_UFL;
++
++ /* rx fifo overflow (2) */
++ if (i_err & I2C_ERR_IRQSS_RXF_OFL)
++ priv->msg_err |= LTQ_I2C_RX_OFL;
++
++ /* rx fifo underflow (1) */
++ if (i_err & I2C_ERR_IRQSS_RXF_UFL)
++ priv->msg_err |= LTQ_I2C_RX_UFL;
++
++ i2c_w32(i_err, err_irqsc);
++ }
++
++ /* protocol interrupt */
++ if (i_raw & I2C_RIS_I2C_P_INT_INTOCC)
++ ltq_i2c_isr_prot(priv);
++
++ if ((priv->msg_err) || (priv->status == STATUS_STOP))
++ complete(&priv->cmd_complete);
++
++ return IRQ_HANDLED;
++}
++
++static u32 ltq_i2c_functionality(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C |
++ I2C_FUNC_10BIT_ADDR |
++ I2C_FUNC_SMBUS_EMUL;
++}
++
++static struct i2c_algorithm ltq_i2c_algorithm = {
++ .master_xfer = ltq_i2c_xfer,
++ .functionality = ltq_i2c_functionality,
++};
++
++static int __devinit ltq_i2c_probe(struct platform_device *pdev)
++{
++ struct device_node *node = pdev->dev.of_node;
++ struct ltq_i2c *priv;
++ struct i2c_adapter *adap;
++ struct resource *mmres, irqres[4];
++ int ret = 0;
++
++ dev_dbg(&pdev->dev, "probing\n");
++
++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ ret = of_irq_to_resource_table(node, irqres, 4);
++ if (!mmres || (ret != 4)) {
++ dev_err(&pdev->dev, "no resources\n");
++ return -ENODEV;
++ }
++
++ /* allocate private data */
++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv) {
++ dev_err(&pdev->dev, "can't allocate private data\n");
++ return -ENOMEM;
++ }
++
++ adap = &priv->adap;
++ i2c_set_adapdata(adap, priv);
++ adap->owner = THIS_MODULE;
++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
++ strlcpy(adap->name, DRV_NAME "-adapter", sizeof(adap->name));
++ adap->algo = &ltq_i2c_algorithm;
++
++ if (of_property_read_u32(node, "clock-frequency", &priv->i2c_clock)) {
++ dev_warn(&pdev->dev, "No I2C speed selected, using 100kHz\n");
++ priv->i2c_clock = 100000;
++ }
++
++ init_completion(&priv->cmd_complete);
++ mutex_init(&priv->mutex);
++
++ priv->membase = devm_request_and_ioremap(&pdev->dev, mmres);
++ if (priv->membase == NULL)
++ return -ENOMEM;
++
++ priv->dev = &pdev->dev;
++ priv->irq_lb = irqres[0].start;
++
++ ret = devm_request_irq(&pdev->dev, irqres[0].start, ltq_i2c_isr_burst,
++ IRQF_DISABLED, "i2c lb", priv);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get last burst IRQ %d\n",
++ irqres[0].start);
++ return -ENODEV;
++ }
++
++ ret = devm_request_irq(&pdev->dev, irqres[1].start, ltq_i2c_isr_burst,
++ IRQF_DISABLED, "i2c b", priv);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get burst IRQ %d\n",
++ irqres[1].start);
++ return -ENODEV;
++ }
++
++ ret = devm_request_irq(&pdev->dev, irqres[2].start, ltq_i2c_isr,
++ IRQF_DISABLED, "i2c err", priv);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get error IRQ %d\n",
++ irqres[2].start);
++ return -ENODEV;
++ }
++
++ ret = devm_request_irq(&pdev->dev, irqres[3].start, ltq_i2c_isr,
++ IRQF_DISABLED, "i2c p", priv);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get protocol IRQ %d\n",
++ irqres[3].start);
++ return -ENODEV;
++ }
++
++ dev_dbg(&pdev->dev, "mapped io-space to %p\n", priv->membase);
++ dev_dbg(&pdev->dev, "use IRQs %d, %d, %d, %d\n", irqres[0].start,
++ irqres[1].start, irqres[2].start, irqres[3].start);
++
++ priv->clk_gate = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(priv->clk_gate)) {
++ dev_err(&pdev->dev, "failed to get i2c clk\n");
++ return -ENOENT;
++ }
++
++ /* this is a static clock, which has no refcounting */
++ priv->clk_input = clk_get_fpi();
++ if (IS_ERR(priv->clk_input)) {
++ dev_err(&pdev->dev, "failed to get fpi clk\n");
++ return -ENOENT;
++ }
++
++ clk_activate(priv->clk_gate);
++
++ /* add our adapter to the i2c stack */
++ ret = i2c_add_numbered_adapter(adap);
++ if (ret) {
++ dev_err(&pdev->dev, "can't register I2C adapter\n");
++ goto out;
++ }
++
++ platform_set_drvdata(pdev, priv);
++ i2c_set_adapdata(adap, priv);
++
++ /* print module version information */
++ dev_dbg(&pdev->dev, "module id=%u revision=%u\n",
++ (i2c_r32(id) & I2C_ID_ID_MASK) >> I2C_ID_ID_OFFSET,
++ (i2c_r32(id) & I2C_ID_REV_MASK) >> I2C_ID_REV_OFFSET);
++
++ /* initialize HW */
++ ret = ltq_i2c_hw_init(adap);
++ if (ret) {
++ dev_err(&pdev->dev, "can't configure adapter\n");
++ i2c_del_adapter(adap);
++ platform_set_drvdata(pdev, NULL);
++ } else {
++ dev_info(&pdev->dev, "version %s\n", DRV_VERSION);
++ }
++
++ of_i2c_register_devices(adap);
++
++out:
++ /* if init failed, we need to deactivate the clock gate */
++ if (ret)
++ clk_deactivate(priv->clk_gate);
++
++ return ret;
++}
++
++static int __devexit ltq_i2c_remove(struct platform_device *pdev)
++{
++ struct ltq_i2c *priv = platform_get_drvdata(pdev);
++
++ /* disable bus */
++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
++
++ /* power down the core */
++ clk_deactivate(priv->clk_gate);
++
++ /* remove driver */
++ i2c_del_adapter(&priv->adap);
++ kfree(priv);
++
++ dev_dbg(&pdev->dev, "removed\n");
++ platform_set_drvdata(pdev, NULL);
++
++ return 0;
++}
++static const struct of_device_id ltq_i2c_match[] = {
++ { .compatible = "lantiq,lantiq-i2c" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, ltq_i2c_match);
++
++static struct platform_driver ltq_i2c_driver = {
++ .probe = ltq_i2c_probe,
++ .remove = __devexit_p(ltq_i2c_remove),
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = ltq_i2c_match,
++ },
++};
++
++module_platform_driver(ltq_i2c_driver);
++
++MODULE_DESCRIPTION("Lantiq I2C bus adapter");
++MODULE_AUTHOR("Thomas Langer <thomas.langer@lantiq.com>");
++MODULE_ALIAS("platform:" DRV_NAME);
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
+diff --git a/drivers/i2c/busses/i2c-lantiq.h b/drivers/i2c/busses/i2c-lantiq.h
+new file mode 100644
+index 0000000..7a86b89
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-lantiq.h
+@@ -0,0 +1,234 @@
++#ifndef I2C_LANTIQ_H
++#define I2C_LANTIQ_H
++
++/* I2C register structure */
++struct lantiq_reg_i2c {
++ /* I2C Kernel Clock Control Register */
++ unsigned int clc; /* 0x00000000 */
++ /* Reserved */
++ unsigned int res_0; /* 0x00000004 */
++ /* I2C Identification Register */
++ unsigned int id; /* 0x00000008 */
++ /* Reserved */
++ unsigned int res_1; /* 0x0000000C */
++ /*
++ * I2C RUN Control Register
++ * This register enables and disables the I2C peripheral. Before
++ * enabling, the I2C has to be configured properly. After enabling
++ * no configuration is possible
++ */
++ unsigned int run_ctrl; /* 0x00000010 */
++ /*
++ * I2C End Data Control Register
++ * This register is used to either turn around the data transmission
++ * direction or to address another slave without sending a stop
++ * condition. Also the software can stop the slave-transmitter by
++ * sending a not-accolade when working as master-receiver or even
++ * stop data transmission immediately when operating as
++ * master-transmitter. The writing to the bits of this control
++ * register is only effective when in MASTER RECEIVES BYTES, MASTER
++ * TRANSMITS BYTES, MASTER RESTART or SLAVE RECEIVE BYTES state
++ */
++ unsigned int endd_ctrl; /* 0x00000014 */
++ /*
++ * I2C Fractional Divider Configuration Register
++ * These register is used to program the fractional divider of the I2C
++ * bus. Before the peripheral is switched on by setting the RUN-bit the
++ * two (fixed) values for the two operating frequencies are programmed
++ * into these (configuration) registers. The Register FDIV_HIGH_CFG has
++ * the same layout as I2C_FDIV_CFG.
++ */
++ unsigned int fdiv_cfg; /* 0x00000018 */
++ /*
++ * I2C Fractional Divider (highspeed mode) Configuration Register
++ * These register is used to program the fractional divider of the I2C
++ * bus. Before the peripheral is switched on by setting the RUN-bit the
++ * two (fixed) values for the two operating frequencies are programmed
++ * into these (configuration) registers. The Register FDIV_CFG has the
++ * same layout as I2C_FDIV_CFG.
++ */
++ unsigned int fdiv_high_cfg; /* 0x0000001C */
++ /* I2C Address Configuration Register */
++ unsigned int addr_cfg; /* 0x00000020 */
++ /* I2C Bus Status Register
++ * This register gives a status information of the I2C. This additional
++ * information can be used by the software to start proper actions.
++ */
++ unsigned int bus_stat; /* 0x00000024 */
++ /* I2C FIFO Configuration Register */
++ unsigned int fifo_cfg; /* 0x00000028 */
++ /* I2C Maximum Received Packet Size Register */
++ unsigned int mrps_ctrl; /* 0x0000002C */
++ /* I2C Received Packet Size Status Register */
++ unsigned int rps_stat; /* 0x00000030 */
++ /* I2C Transmit Packet Size Register */
++ unsigned int tps_ctrl; /* 0x00000034 */
++ /* I2C Filled FIFO Stages Status Register */
++ unsigned int ffs_stat; /* 0x00000038 */
++ /* Reserved */
++ unsigned int res_2; /* 0x0000003C */
++ /* I2C Timing Configuration Register */
++ unsigned int tim_cfg; /* 0x00000040 */
++ /* Reserved */
++ unsigned int res_3[7]; /* 0x00000044 */
++ /* I2C Error Interrupt Request Source Mask Register */
++ unsigned int err_irqsm; /* 0x00000060 */
++ /* I2C Error Interrupt Request Source Status Register */
++ unsigned int err_irqss; /* 0x00000064 */
++ /* I2C Error Interrupt Request Source Clear Register */
++ unsigned int err_irqsc; /* 0x00000068 */
++ /* Reserved */
++ unsigned int res_4; /* 0x0000006C */
++ /* I2C Protocol Interrupt Request Source Mask Register */
++ unsigned int p_irqsm; /* 0x00000070 */
++ /* I2C Protocol Interrupt Request Source Status Register */
++ unsigned int p_irqss; /* 0x00000074 */
++ /* I2C Protocol Interrupt Request Source Clear Register */
++ unsigned int p_irqsc; /* 0x00000078 */
++ /* Reserved */
++ unsigned int res_5; /* 0x0000007C */
++ /* I2C Raw Interrupt Status Register */
++ unsigned int ris; /* 0x00000080 */
++ /* I2C Interrupt Mask Control Register */
++ unsigned int imsc; /* 0x00000084 */
++ /* I2C Masked Interrupt Status Register */
++ unsigned int mis; /* 0x00000088 */
++ /* I2C Interrupt Clear Register */
++ unsigned int icr; /* 0x0000008C */
++ /* I2C Interrupt Set Register */
++ unsigned int isr; /* 0x00000090 */
++ /* I2C DMA Enable Register */
++ unsigned int dmae; /* 0x00000094 */
++ /* Reserved */
++ unsigned int res_6[8154]; /* 0x00000098 */
++ /* I2C Transmit Data Register */
++ unsigned int txd; /* 0x00008000 */
++ /* Reserved */
++ unsigned int res_7[4095]; /* 0x00008004 */
++ /* I2C Receive Data Register */
++ unsigned int rxd; /* 0x0000C000 */
++ /* Reserved */
++ unsigned int res_8[4095]; /* 0x0000C004 */
++};
++
++/*
++ * Clock Divider for Normal Run Mode
++ * Max 8-bit divider value. IF RMC is 0 the module is disabled. Note: As long
++ * as the new divider value RMC is not valid, the register returns 0x0000 00xx
++ * on reading.
++ */
++#define I2C_CLC_RMC_MASK 0x0000FF00
++/* field offset */
++#define I2C_CLC_RMC_OFFSET 8
++
++/* Fields of "I2C Identification Register" */
++/* Module ID */
++#define I2C_ID_ID_MASK 0x0000FF00
++/* field offset */
++#define I2C_ID_ID_OFFSET 8
++/* Revision */
++#define I2C_ID_REV_MASK 0x000000FF
++/* field offset */
++#define I2C_ID_REV_OFFSET 0
++
++/* Fields of "I2C Interrupt Mask Control Register" */
++/* Enable */
++#define I2C_IMSC_BREQ_INT_EN 0x00000008
++/* Enable */
++#define I2C_IMSC_LBREQ_INT_EN 0x00000004
++
++/* Fields of "I2C Fractional Divider Configuration Register" */
++/* field offset */
++#define I2C_FDIV_CFG_INC_OFFSET 16
++
++/* Fields of "I2C Interrupt Mask Control Register" */
++/* Enable */
++#define I2C_IMSC_I2C_P_INT_EN 0x00000020
++/* Enable */
++#define I2C_IMSC_I2C_ERR_INT_EN 0x00000010
++
++/* Fields of "I2C Error Interrupt Request Source Status Register" */
++/* TXF_OFL */
++#define I2C_ERR_IRQSS_TXF_OFL 0x00000008
++/* TXF_UFL */
++#define I2C_ERR_IRQSS_TXF_UFL 0x00000004
++/* RXF_OFL */
++#define I2C_ERR_IRQSS_RXF_OFL 0x00000002
++/* RXF_UFL */
++#define I2C_ERR_IRQSS_RXF_UFL 0x00000001
++
++/* Fields of "I2C Raw Interrupt Status Register" */
++/* Read: Interrupt occurred. */
++#define I2C_RIS_I2C_ERR_INT_INTOCC 0x00000010
++/* Read: Interrupt occurred. */
++#define I2C_RIS_I2C_P_INT_INTOCC 0x00000020
++
++/* Fields of "I2C FIFO Configuration Register" */
++/* TX FIFO Flow Control */
++#define I2C_FIFO_CFG_TXFC 0x00020000
++/* RX FIFO Flow Control */
++#define I2C_FIFO_CFG_RXFC 0x00010000
++/* Word aligned (character alignment of four characters) */
++#define I2C_FIFO_CFG_TXFA_TXFA2 0x00002000
++/* Word aligned (character alignment of four characters) */
++#define I2C_FIFO_CFG_RXFA_RXFA2 0x00000200
++/* 1 word */
++#define I2C_FIFO_CFG_TXBS_TXBS0 0x00000000
++
++/* Fields of "I2C FIFO Configuration Register" */
++/* 1 word */
++#define I2C_FIFO_CFG_RXBS_RXBS0 0x00000000
++/* Stop on Packet End Enable */
++#define I2C_ADDR_CFG_SOPE_EN 0x00200000
++/* Stop on Not Acknowledge Enable */
++#define I2C_ADDR_CFG_SONA_EN 0x00100000
++/* Enable */
++#define I2C_ADDR_CFG_MnS_EN 0x00080000
++
++/* Fields of "I2C Interrupt Clear Register" */
++/* Clear */
++#define I2C_ICR_BREQ_INT_CLR 0x00000008
++/* Clear */
++#define I2C_ICR_LBREQ_INT_CLR 0x00000004
++
++/* Fields of "I2C Fractional Divider Configuration Register" */
++/* field offset */
++#define I2C_FDIV_CFG_DEC_OFFSET 0
++
++/* Fields of "I2C Bus Status Register" */
++/* Bus Status */
++#define I2C_BUS_STAT_BS_MASK 0x00000003
++/* Read from I2C Bus. */
++#define I2C_BUS_STAT_RNW_READ 0x00000004
++/* I2C Bus is free. */
++#define I2C_BUS_STAT_BS_FREE 0x00000000
++/*
++ * The device is working as master and has claimed the control on the
++ * I2C-bus (busy master).
++ */
++#define I2C_BUS_STAT_BS_BM 0x00000002
++
++/* Fields of "I2C RUN Control Register" */
++/* Enable */
++#define I2C_RUN_CTRL_RUN_EN 0x00000001
++
++/* Fields of "I2C End Data Control Register" */
++/*
++ * Set End of Transmission
++ * Note:Do not write '1' to this bit when bus is free. This will cause an
++ * abort after the first byte when a new transfer is started.
++ */
++#define I2C_ENDD_CTRL_SETEND 0x00000002
++
++/* Fields of "I2C Protocol Interrupt Request Source Status Register" */
++/* NACK */
++#define I2C_P_IRQSS_NACK 0x00000010
++/* AL */
++#define I2C_P_IRQSS_AL 0x00000008
++/* RX */
++#define I2C_P_IRQSS_RX 0x00000040
++/* TX_END */
++#define I2C_P_IRQSS_TX_END 0x00000020
++
++
++#endif /* I2C_LANTIQ_H */
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0114-SPI-MIPS-lantiq-adds-spi-xway.patch b/target/linux/lantiq/patches-3.7/0114-SPI-MIPS-lantiq-adds-spi-xway.patch
new file mode 100644
index 0000000000..d8c6dd08d5
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0114-SPI-MIPS-lantiq-adds-spi-xway.patch
@@ -0,0 +1,1033 @@
+From db447f1a18106aa4d32438ab72ff57024b34cee4 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 16 Aug 2012 09:57:01 +0200
+Subject: [PATCH 114/123] SPI: MIPS: lantiq: adds spi-xway
+
+This patch adds support for the SPI core found on several Lantiq SoCs.
+The Driver has been runtime tested in combination with m25p80 Flash Devices
+on Amazon_SE and VR9.
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/spi/Kconfig | 8 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-xway.c | 977 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 986 insertions(+)
+ create mode 100644 drivers/spi/spi-xway.c
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 1acae35..d79a587 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -434,6 +434,14 @@ config SPI_NUC900
+ help
+ SPI driver for Nuvoton NUC900 series ARM SoCs
+
++config SPI_XWAY
++ tristate "Lantiq XWAY SPI controller"
++ depends on LANTIQ && SOC_TYPE_XWAY
++ select SPI_BITBANG
++ help
++ This driver supports the Lantiq SoC SPI controller in master
++ mode.
++
+ #
+ # Add new SPI master controllers in alphabetical order above this line
+ #
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index c48df47..7e344a9 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -66,4 +66,5 @@ obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
+ obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
+ obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
+ obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
++obj-$(CONFIG_SPI_XWAY) += spi-xway.o
+
+diff --git a/drivers/spi/spi-xway.c b/drivers/spi/spi-xway.c
+new file mode 100644
+index 0000000..8441085
+--- /dev/null
++++ b/drivers/spi/spi-xway.c
+@@ -0,0 +1,977 @@
++/*
++ * Lantiq SoC SPI controller
++ *
++ * Copyright (C) 2011 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++#include <linux/spinlock.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/of_irq.h>
++
++#include <lantiq_soc.h>
++
++#define LTQ_SPI_CLC 0x00 /* Clock control */
++#define LTQ_SPI_PISEL 0x04 /* Port input select */
++#define LTQ_SPI_ID 0x08 /* Identification */
++#define LTQ_SPI_CON 0x10 /* Control */
++#define LTQ_SPI_STAT 0x14 /* Status */
++#define LTQ_SPI_WHBSTATE 0x18 /* Write HW modified state */
++#define LTQ_SPI_TB 0x20 /* Transmit buffer */
++#define LTQ_SPI_RB 0x24 /* Receive buffer */
++#define LTQ_SPI_RXFCON 0x30 /* Receive FIFO control */
++#define LTQ_SPI_TXFCON 0x34 /* Transmit FIFO control */
++#define LTQ_SPI_FSTAT 0x38 /* FIFO status */
++#define LTQ_SPI_BRT 0x40 /* Baudrate timer */
++#define LTQ_SPI_BRSTAT 0x44 /* Baudrate timer status */
++#define LTQ_SPI_SFCON 0x60 /* Serial frame control */
++#define LTQ_SPI_SFSTAT 0x64 /* Serial frame status */
++#define LTQ_SPI_GPOCON 0x70 /* General purpose output control */
++#define LTQ_SPI_GPOSTAT 0x74 /* General purpose output status */
++#define LTQ_SPI_FGPO 0x78 /* Forced general purpose output */
++#define LTQ_SPI_RXREQ 0x80 /* Receive request */
++#define LTQ_SPI_RXCNT 0x84 /* Receive count */
++#define LTQ_SPI_DMACON 0xEC /* DMA control */
++#define LTQ_SPI_IRNEN 0xF4 /* Interrupt node enable */
++#define LTQ_SPI_IRNICR 0xF8 /* Interrupt node interrupt capture */
++#define LTQ_SPI_IRNCR 0xFC /* Interrupt node control */
++
++#define LTQ_SPI_CLC_SMC_SHIFT 16 /* Clock divider for sleep mode */
++#define LTQ_SPI_CLC_SMC_MASK 0xFF
++#define LTQ_SPI_CLC_RMC_SHIFT 8 /* Clock divider for normal run mode */
++#define LTQ_SPI_CLC_RMC_MASK 0xFF
++#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */
++#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */
++
++#define LTQ_SPI_ID_TXFS_SHIFT 24 /* Implemented TX FIFO size */
++#define LTQ_SPI_ID_TXFS_MASK 0x3F
++#define LTQ_SPI_ID_RXFS_SHIFT 16 /* Implemented RX FIFO size */
++#define LTQ_SPI_ID_RXFS_MASK 0x3F
++#define LTQ_SPI_ID_REV_MASK 0x1F /* Hardware revision number */
++#define LTQ_SPI_ID_CFG BIT(5) /* DMA interface support */
++
++#define LTQ_SPI_CON_BM_SHIFT 16 /* Data width selection */
++#define LTQ_SPI_CON_BM_MASK 0x1F
++#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */
++#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */
++#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */
++#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */
++#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */
++#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */
++#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */
++#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */
++#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */
++#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */
++#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */
++#define LTQ_SPI_CON_HB BIT(4) /* Heading control */
++#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */
++#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */
++
++#define LTQ_SPI_STAT_RXBV_MASK 0x7
++#define LTQ_SPI_STAT_RXBV_SHIFT 28
++#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */
++#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */
++#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */
++#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */
++#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */
++#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */
++#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */
++#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */
++
++#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */
++#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */
++#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */
++#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */
++#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error
++ flag */
++#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */
++#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */
++#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */
++#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */
++#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */
++#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */
++#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */
++#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */
++#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */
++#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */
++#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */
++#define LTQ_SPI_WHBSTATE_CLR_ERRORS 0x0F50
++
++#define LTQ_SPI_RXFCON_RXFITL_SHIFT 8 /* FIFO interrupt trigger level */
++#define LTQ_SPI_RXFCON_RXFITL_MASK 0x3F
++#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */
++#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */
++
++#define LTQ_SPI_TXFCON_TXFITL_SHIFT 8 /* FIFO interrupt trigger level */
++#define LTQ_SPI_TXFCON_TXFITL_MASK 0x3F
++#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */
++#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */
++
++#define LTQ_SPI_FSTAT_RXFFL_MASK 0x3f
++#define LTQ_SPI_FSTAT_RXFFL_SHIFT 0
++#define LTQ_SPI_FSTAT_TXFFL_MASK 0x3f
++#define LTQ_SPI_FSTAT_TXFFL_SHIFT 8
++
++#define LTQ_SPI_GPOCON_ISCSBN_SHIFT 8
++#define LTQ_SPI_GPOCON_INVOUTN_SHIFT 0
++
++#define LTQ_SPI_FGPO_SETOUTN_SHIFT 8
++#define LTQ_SPI_FGPO_CLROUTN_SHIFT 0
++
++#define LTQ_SPI_RXREQ_RXCNT_MASK 0xFFFF /* Receive count value */
++#define LTQ_SPI_RXCNT_TODO_MASK 0xFFFF /* Recevie to-do value */
++
++#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */
++#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */
++#define LTQ_SPI_IRNEN_T BIT(1) /* Transmit end interrupt request */
++#define LTQ_SPI_IRNEN_R BIT(0) /* Receive end interrupt request */
++#define LTQ_SPI_IRNEN_ALL 0xF
++
++struct ltq_spi {
++ struct spi_bitbang bitbang;
++ struct completion done;
++ spinlock_t lock;
++
++ struct device *dev;
++ void __iomem *base;
++ struct clk *fpiclk;
++ struct clk *spiclk;
++
++ int status;
++ int irq[3];
++
++ const u8 *tx;
++ u8 *rx;
++ u32 tx_cnt;
++ u32 rx_cnt;
++ u32 len;
++ struct spi_transfer *curr_transfer;
++
++ u32 (*get_tx) (struct ltq_spi *);
++
++ u16 txfs;
++ u16 rxfs;
++ unsigned dma_support:1;
++ unsigned cfg_mode:1;
++};
++
++static inline struct ltq_spi *ltq_spi_to_hw(struct spi_device *spi)
++{
++ return spi_master_get_devdata(spi->master);
++}
++
++static inline u32 ltq_spi_reg_read(struct ltq_spi *hw, u32 reg)
++{
++ return ioread32be(hw->base + reg);
++}
++
++static inline void ltq_spi_reg_write(struct ltq_spi *hw, u32 val, u32 reg)
++{
++ iowrite32be(val, hw->base + reg);
++}
++
++static inline void ltq_spi_reg_setbit(struct ltq_spi *hw, u32 bits, u32 reg)
++{
++ u32 val;
++
++ val = ltq_spi_reg_read(hw, reg);
++ val |= bits;
++ ltq_spi_reg_write(hw, val, reg);
++}
++
++static inline void ltq_spi_reg_clearbit(struct ltq_spi *hw, u32 bits, u32 reg)
++{
++ u32 val;
++
++ val = ltq_spi_reg_read(hw, reg);
++ val &= ~bits;
++ ltq_spi_reg_write(hw, val, reg);
++}
++
++static void ltq_spi_hw_enable(struct ltq_spi *hw)
++{
++ u32 clc;
++
++ /* Power-up module */
++ clk_enable(hw->spiclk);
++
++ /*
++ * Set clock divider for run mode to 1 to
++ * run at same frequency as FPI bus
++ */
++ clc = (1 << LTQ_SPI_CLC_RMC_SHIFT);
++ ltq_spi_reg_write(hw, clc, LTQ_SPI_CLC);
++}
++
++static void ltq_spi_hw_disable(struct ltq_spi *hw)
++{
++ /* Set clock divider to 0 and set module disable bit */
++ ltq_spi_reg_write(hw, LTQ_SPI_CLC_DISS, LTQ_SPI_CLC);
++
++ /* Power-down module */
++ clk_disable(hw->spiclk);
++}
++
++static void ltq_spi_reset_fifos(struct ltq_spi *hw)
++{
++ u32 val;
++
++ /*
++ * Enable and flush FIFOs. Set interrupt trigger level to
++ * half of FIFO count implemented in hardware.
++ */
++ if (hw->txfs > 1) {
++ val = hw->txfs << (LTQ_SPI_TXFCON_TXFITL_SHIFT - 1);
++ val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU;
++ ltq_spi_reg_write(hw, val, LTQ_SPI_TXFCON);
++ }
++
++ if (hw->rxfs > 1) {
++ val = hw->rxfs << (LTQ_SPI_RXFCON_RXFITL_SHIFT - 1);
++ val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU;
++ ltq_spi_reg_write(hw, val, LTQ_SPI_RXFCON);
++ }
++}
++
++static inline int ltq_spi_wait_ready(struct ltq_spi *hw)
++{
++ u32 stat;
++ unsigned long timeout;
++
++ timeout = jiffies + msecs_to_jiffies(200);
++
++ do {
++ stat = ltq_spi_reg_read(hw, LTQ_SPI_STAT);
++ if (!(stat & LTQ_SPI_STAT_BSY))
++ return 0;
++
++ cond_resched();
++ } while (!time_after_eq(jiffies, timeout));
++
++ dev_err(hw->dev, "SPI wait ready timed out stat: %x\n", stat);
++
++ return -ETIMEDOUT;
++}
++
++static void ltq_spi_config_mode_set(struct ltq_spi *hw)
++{
++ if (hw->cfg_mode)
++ return;
++
++ /*
++ * Putting the SPI module in config mode is only safe if no
++ * transfer is in progress as indicated by busy flag STATE.BSY.
++ */
++ if (ltq_spi_wait_ready(hw)) {
++ ltq_spi_reset_fifos(hw);
++ hw->status = -ETIMEDOUT;
++ }
++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE);
++
++ hw->cfg_mode = 1;
++}
++
++static void ltq_spi_run_mode_set(struct ltq_spi *hw)
++{
++ if (!hw->cfg_mode)
++ return;
++
++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE);
++
++ hw->cfg_mode = 0;
++}
++
++static u32 ltq_spi_tx_word_u8(struct ltq_spi *hw)
++{
++ const u8 *tx = hw->tx;
++ u32 data = *tx++;
++
++ hw->tx_cnt++;
++ hw->tx++;
++
++ return data;
++}
++
++static u32 ltq_spi_tx_word_u16(struct ltq_spi *hw)
++{
++ const u16 *tx = (u16 *) hw->tx;
++ u32 data = *tx++;
++
++ hw->tx_cnt += 2;
++ hw->tx += 2;
++
++ return data;
++}
++
++static u32 ltq_spi_tx_word_u32(struct ltq_spi *hw)
++{
++ const u32 *tx = (u32 *) hw->tx;
++ u32 data = *tx++;
++
++ hw->tx_cnt += 4;
++ hw->tx += 4;
++
++ return data;
++}
++
++static void ltq_spi_bits_per_word_set(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 bm;
++ u8 bits_per_word = spi->bits_per_word;
++
++ /*
++ * Use either default value of SPI device or value
++ * from current transfer.
++ */
++ if (hw->curr_transfer && hw->curr_transfer->bits_per_word)
++ bits_per_word = hw->curr_transfer->bits_per_word;
++
++ if (bits_per_word <= 8)
++ hw->get_tx = ltq_spi_tx_word_u8;
++ else if (bits_per_word <= 16)
++ hw->get_tx = ltq_spi_tx_word_u16;
++ else if (bits_per_word <= 32)
++ hw->get_tx = ltq_spi_tx_word_u32;
++
++ /* CON.BM value = bits_per_word - 1 */
++ bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_SHIFT;
++
++ ltq_spi_reg_clearbit(hw, LTQ_SPI_CON_BM_MASK <<
++ LTQ_SPI_CON_BM_SHIFT, LTQ_SPI_CON);
++ ltq_spi_reg_setbit(hw, bm, LTQ_SPI_CON);
++}
++
++static void ltq_spi_speed_set(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 br, max_speed_hz, spi_clk;
++ u32 speed_hz = spi->max_speed_hz;
++
++ /*
++ * Use either default value of SPI device or value
++ * from current transfer.
++ */
++ if (hw->curr_transfer && hw->curr_transfer->speed_hz)
++ speed_hz = hw->curr_transfer->speed_hz;
++
++ /*
++ * SPI module clock is derived from FPI bus clock dependent on
++ * divider value in CLC.RMS which is always set to 1.
++ */
++ spi_clk = clk_get_rate(hw->fpiclk);
++
++ /*
++ * Maximum SPI clock frequency in master mode is half of
++ * SPI module clock frequency. Maximum reload value of
++ * baudrate generator BR is 2^16.
++ */
++ max_speed_hz = spi_clk / 2;
++ if (speed_hz >= max_speed_hz)
++ br = 0;
++ else
++ br = (max_speed_hz / speed_hz) - 1;
++
++ if (br > 0xFFFF)
++ br = 0xFFFF;
++
++ ltq_spi_reg_write(hw, br, LTQ_SPI_BRT);
++}
++
++static void ltq_spi_clockmode_set(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 con;
++
++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON);
++
++ /*
++ * SPI mode mapping in CON register:
++ * Mode CPOL CPHA CON.PO CON.PH
++ * 0 0 0 0 1
++ * 1 0 1 0 0
++ * 2 1 0 1 1
++ * 3 1 1 1 0
++ */
++ if (spi->mode & SPI_CPHA)
++ con &= ~LTQ_SPI_CON_PH;
++ else
++ con |= LTQ_SPI_CON_PH;
++
++ if (spi->mode & SPI_CPOL)
++ con |= LTQ_SPI_CON_PO;
++ else
++ con &= ~LTQ_SPI_CON_PO;
++
++ /* Set heading control */
++ if (spi->mode & SPI_LSB_FIRST)
++ con &= ~LTQ_SPI_CON_HB;
++ else
++ con |= LTQ_SPI_CON_HB;
++
++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON);
++}
++
++static void ltq_spi_xmit_set(struct ltq_spi *hw, struct spi_transfer *t)
++{
++ u32 con;
++
++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON);
++
++ if (t) {
++ if (t->tx_buf && t->rx_buf) {
++ con &= ~(LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF);
++ } else if (t->rx_buf) {
++ con &= ~LTQ_SPI_CON_RXOFF;
++ con |= LTQ_SPI_CON_TXOFF;
++ } else if (t->tx_buf) {
++ con &= ~LTQ_SPI_CON_TXOFF;
++ con |= LTQ_SPI_CON_RXOFF;
++ }
++ } else
++ con |= (LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF);
++
++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON);
++}
++
++static void ltq_spi_internal_cs_activate(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 fgpo;
++
++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_CLROUTN_SHIFT));
++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO);
++}
++
++static void ltq_spi_internal_cs_deactivate(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 fgpo;
++
++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT));
++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO);
++}
++
++static void ltq_spi_chipselect(struct spi_device *spi, int cs)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++
++ switch (cs) {
++ case BITBANG_CS_ACTIVE:
++ ltq_spi_bits_per_word_set(spi);
++ ltq_spi_speed_set(spi);
++ ltq_spi_clockmode_set(spi);
++ ltq_spi_run_mode_set(hw);
++ ltq_spi_internal_cs_activate(spi);
++ break;
++
++ case BITBANG_CS_INACTIVE:
++ ltq_spi_internal_cs_deactivate(spi);
++ ltq_spi_config_mode_set(hw);
++ break;
++ }
++}
++
++static int ltq_spi_setup_transfer(struct spi_device *spi,
++ struct spi_transfer *t)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u8 bits_per_word = spi->bits_per_word;
++
++ hw->curr_transfer = t;
++
++ if (t && t->bits_per_word)
++ bits_per_word = t->bits_per_word;
++
++ if (bits_per_word > 32)
++ return -EINVAL;
++
++ ltq_spi_config_mode_set(hw);
++
++ return 0;
++}
++
++static int ltq_spi_setup(struct spi_device *spi)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 gpocon, fgpo;
++
++ /* Set default word length to 8 if not set */
++ if (!spi->bits_per_word)
++ spi->bits_per_word = 8;
++
++ if (spi->bits_per_word > 32)
++ return -EINVAL;
++
++ /*
++ * Up to six GPIOs can be connected to the SPI module
++ * via GPIO alternate function to control the chip select lines.
++ */
++ gpocon = (1 << (spi->chip_select +
++ LTQ_SPI_GPOCON_ISCSBN_SHIFT));
++
++ if (spi->mode & SPI_CS_HIGH)
++ gpocon |= (1 << spi->chip_select);
++
++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT));
++
++ ltq_spi_reg_setbit(hw, gpocon, LTQ_SPI_GPOCON);
++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO);
++
++ return 0;
++}
++
++static void ltq_spi_cleanup(struct spi_device *spi)
++{
++
++}
++
++static void ltq_spi_txfifo_write(struct ltq_spi *hw)
++{
++ u32 fstat, data;
++ u16 fifo_space;
++
++ /* Determine how much FIFOs are free for TX data */
++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT);
++ fifo_space = hw->txfs - ((fstat >> LTQ_SPI_FSTAT_TXFFL_SHIFT) &
++ LTQ_SPI_FSTAT_TXFFL_MASK);
++
++ if (!fifo_space)
++ return;
++
++ while (hw->tx_cnt < hw->len && fifo_space) {
++ data = hw->get_tx(hw);
++ ltq_spi_reg_write(hw, data, LTQ_SPI_TB);
++ fifo_space--;
++ }
++}
++
++static void ltq_spi_rxfifo_read(struct ltq_spi *hw)
++{
++ u32 fstat, data, *rx32;
++ u16 fifo_fill;
++ u8 rxbv, shift, *rx8;
++
++ /* Determine how much FIFOs are filled with RX data */
++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT);
++ fifo_fill = ((fstat >> LTQ_SPI_FSTAT_RXFFL_SHIFT)
++ & LTQ_SPI_FSTAT_RXFFL_MASK);
++
++ if (!fifo_fill)
++ return;
++
++ /*
++ * The 32 bit FIFO is always used completely independent from the
++ * bits_per_word value. Thus four bytes have to be read at once
++ * per FIFO.
++ */
++ rx32 = (u32 *) hw->rx;
++ while (hw->len - hw->rx_cnt >= 4 && fifo_fill) {
++ *rx32++ = ltq_spi_reg_read(hw, LTQ_SPI_RB);
++ hw->rx_cnt += 4;
++ hw->rx += 4;
++ fifo_fill--;
++ }
++
++ /*
++ * If there are remaining bytes, read byte count from STAT.RXBV
++ * register and read the data byte-wise.
++ */
++ while (fifo_fill && hw->rx_cnt < hw->len) {
++ rxbv = (ltq_spi_reg_read(hw, LTQ_SPI_STAT) >>
++ LTQ_SPI_STAT_RXBV_SHIFT) & LTQ_SPI_STAT_RXBV_MASK;
++ data = ltq_spi_reg_read(hw, LTQ_SPI_RB);
++
++ shift = (rxbv - 1) * 8;
++ rx8 = hw->rx;
++
++ while (rxbv) {
++ *rx8++ = (data >> shift) & 0xFF;
++ rxbv--;
++ shift -= 8;
++ hw->rx_cnt++;
++ hw->rx++;
++ }
++
++ fifo_fill--;
++ }
++}
++
++static void ltq_spi_rxreq_set(struct ltq_spi *hw)
++{
++ u32 rxreq, rxreq_max, rxtodo;
++
++ rxtodo = ltq_spi_reg_read(hw, LTQ_SPI_RXCNT) & LTQ_SPI_RXCNT_TODO_MASK;
++
++ /*
++ * In RX-only mode the serial clock is activated only after writing
++ * the expected amount of RX bytes into RXREQ register.
++ * To avoid receive overflows at high clocks it is better to request
++ * only the amount of bytes that fits into all FIFOs. This value
++ * depends on the FIFO size implemented in hardware.
++ */
++ rxreq = hw->len - hw->rx_cnt;
++ rxreq_max = hw->rxfs << 2;
++ rxreq = min(rxreq_max, rxreq);
++
++ if (!rxtodo && rxreq)
++ ltq_spi_reg_write(hw, rxreq, LTQ_SPI_RXREQ);
++}
++
++static inline void ltq_spi_complete(struct ltq_spi *hw)
++{
++ complete(&hw->done);
++}
++
++irqreturn_t ltq_spi_tx_irq(int irq, void *data)
++{
++ struct ltq_spi *hw = data;
++ unsigned long flags;
++ int completed = 0;
++
++ spin_lock_irqsave(&hw->lock, flags);
++
++ if (hw->tx_cnt < hw->len)
++ ltq_spi_txfifo_write(hw);
++
++ if (hw->tx_cnt == hw->len)
++ completed = 1;
++
++ spin_unlock_irqrestore(&hw->lock, flags);
++
++ if (completed)
++ ltq_spi_complete(hw);
++
++ return IRQ_HANDLED;
++}
++
++irqreturn_t ltq_spi_rx_irq(int irq, void *data)
++{
++ struct ltq_spi *hw = data;
++ unsigned long flags;
++ int completed = 0;
++
++ spin_lock_irqsave(&hw->lock, flags);
++
++ if (hw->rx_cnt < hw->len) {
++ ltq_spi_rxfifo_read(hw);
++
++ if (hw->tx && hw->tx_cnt < hw->len)
++ ltq_spi_txfifo_write(hw);
++ }
++
++ if (hw->rx_cnt == hw->len)
++ completed = 1;
++ else if (!hw->tx)
++ ltq_spi_rxreq_set(hw);
++
++ spin_unlock_irqrestore(&hw->lock, flags);
++
++ if (completed)
++ ltq_spi_complete(hw);
++
++ return IRQ_HANDLED;
++}
++
++irqreturn_t ltq_spi_err_irq(int irq, void *data)
++{
++ struct ltq_spi *hw = data;
++ unsigned long flags;
++
++ spin_lock_irqsave(&hw->lock, flags);
++
++ /* Disable all interrupts */
++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN);
++
++ /* Clear all error flags */
++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
++
++ /* Flush FIFOs */
++ ltq_spi_reg_setbit(hw, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON);
++ ltq_spi_reg_setbit(hw, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON);
++
++ hw->status = -EIO;
++ spin_unlock_irqrestore(&hw->lock, flags);
++
++ ltq_spi_complete(hw);
++
++ return IRQ_HANDLED;
++}
++
++static int ltq_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
++{
++ struct ltq_spi *hw = ltq_spi_to_hw(spi);
++ u32 irq_flags = 0;
++
++ hw->tx = t->tx_buf;
++ hw->rx = t->rx_buf;
++ hw->len = t->len;
++ hw->tx_cnt = 0;
++ hw->rx_cnt = 0;
++ hw->status = 0;
++ INIT_COMPLETION(hw->done);
++
++ ltq_spi_xmit_set(hw, t);
++
++ /* Enable error interrupts */
++ ltq_spi_reg_setbit(hw, LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN);
++
++ if (hw->tx) {
++ /* Initially fill TX FIFO with as much data as possible */
++ ltq_spi_txfifo_write(hw);
++ irq_flags |= LTQ_SPI_IRNEN_T;
++
++ /* Always enable RX interrupt in Full Duplex mode */
++ if (hw->rx)
++ irq_flags |= LTQ_SPI_IRNEN_R;
++ } else if (hw->rx) {
++ /* Start RX clock */
++ ltq_spi_rxreq_set(hw);
++
++ /* Enable RX interrupt to receive data from RX FIFOs */
++ irq_flags |= LTQ_SPI_IRNEN_R;
++ }
++
++ /* Enable TX or RX interrupts */
++ ltq_spi_reg_setbit(hw, irq_flags, LTQ_SPI_IRNEN);
++ wait_for_completion_interruptible(&hw->done);
++
++ /* Disable all interrupts */
++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN);
++
++ /*
++ * Return length of current transfer for bitbang utility code if
++ * no errors occured during transmission.
++ */
++ if (!hw->status)
++ hw->status = hw->len;
++
++ return hw->status;
++}
++
++static const struct ltq_spi_irq_map {
++ char *name;
++ irq_handler_t handler;
++} ltq_spi_irqs[] = {
++ { "spi_rx", ltq_spi_rx_irq },
++ { "spi_tx", ltq_spi_tx_irq },
++ { "spi_err", ltq_spi_err_irq },
++};
++
++static int __devinit ltq_spi_probe(struct platform_device *pdev)
++{
++ struct resource irqres[3];
++ struct spi_master *master;
++ struct resource *r;
++ struct ltq_spi *hw;
++ int ret, i;
++ u32 data, id;
++
++ if (of_irq_to_resource_table(pdev->dev.of_node, irqres, 3) != 3) {
++ dev_err(&pdev->dev, "IRQ settings missing in device tree\n");
++ return -EINVAL;
++ }
++
++ master = spi_alloc_master(&pdev->dev, sizeof(struct ltq_spi));
++ if (!master) {
++ dev_err(&pdev->dev, "spi_alloc_master\n");
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ hw = spi_master_get_devdata(master);
++
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (r == NULL) {
++ dev_err(&pdev->dev, "platform_get_resource\n");
++ ret = -ENOENT;
++ goto err_master;
++ }
++
++ r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r),
++ pdev->name);
++ if (!r) {
++ dev_err(&pdev->dev, "failed to request memory region\n");
++ ret = -ENXIO;
++ goto err_master;
++ }
++
++ hw->base = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r));
++ if (!hw->base) {
++ dev_err(&pdev->dev, "failed to remap memory region\n");
++ ret = -ENXIO;
++ goto err_master;
++ }
++
++ memset(hw->irq, 0, sizeof(hw->irq));
++ for (i = 0; i < ARRAY_SIZE(ltq_spi_irqs); i++) {
++ hw->irq[i] = irqres[i].start;
++ ret = request_irq(hw->irq[i], ltq_spi_irqs[i].handler,
++ 0, ltq_spi_irqs[i].name, hw);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to request %s irq (%d)\n",
++ ltq_spi_irqs[i].name, hw->irq[i]);
++ goto err_irq;
++ }
++ }
++
++ hw->fpiclk = clk_get_fpi();
++ if (IS_ERR(hw->fpiclk)) {
++ dev_err(&pdev->dev, "failed to get fpi clock\n");
++ ret = PTR_ERR(hw->fpiclk);
++ goto err_clk;
++ }
++
++ hw->spiclk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(hw->spiclk)) {
++ dev_err(&pdev->dev, "failed to get spi clock gate\n");
++ ret = PTR_ERR(hw->spiclk);
++ goto err_clk;
++ }
++
++ hw->bitbang.master = spi_master_get(master);
++ hw->bitbang.chipselect = ltq_spi_chipselect;
++ hw->bitbang.setup_transfer = ltq_spi_setup_transfer;
++ hw->bitbang.txrx_bufs = ltq_spi_txrx_bufs;
++
++ if (of_machine_is_compatible("lantiq,ase"))
++ master->num_chipselect = 3;
++ else
++ master->num_chipselect = 6;
++ master->bus_num = pdev->id;
++ master->setup = ltq_spi_setup;
++ master->cleanup = ltq_spi_cleanup;
++ master->dev.of_node = pdev->dev.of_node;
++
++ hw->dev = &pdev->dev;
++ init_completion(&hw->done);
++ spin_lock_init(&hw->lock);
++
++ ltq_spi_hw_enable(hw);
++
++ /* Read module capabilities */
++ id = ltq_spi_reg_read(hw, LTQ_SPI_ID);
++ hw->txfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK;
++ hw->rxfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK;
++ hw->dma_support = (id & LTQ_SPI_ID_CFG) ? 1 : 0;
++
++ ltq_spi_config_mode_set(hw);
++
++ /* Enable error checking, disable TX/RX, set idle value high */
++ data = LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN |
++ LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN |
++ LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF | LTQ_SPI_CON_IDLE;
++ ltq_spi_reg_write(hw, data, LTQ_SPI_CON);
++
++ /* Enable master mode and clear error flags */
++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETMS |
++ LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
++
++ /* Reset GPIO/CS registers */
++ ltq_spi_reg_write(hw, 0x0, LTQ_SPI_GPOCON);
++ ltq_spi_reg_write(hw, 0xFF00, LTQ_SPI_FGPO);
++
++ /* Enable and flush FIFOs */
++ ltq_spi_reset_fifos(hw);
++
++ ret = spi_bitbang_start(&hw->bitbang);
++ if (ret) {
++ dev_err(&pdev->dev, "spi_bitbang_start failed\n");
++ goto err_bitbang;
++ }
++
++ platform_set_drvdata(pdev, hw);
++
++ pr_info("Lantiq SoC SPI controller rev %u (TXFS %u, RXFS %u, DMA %u)\n",
++ id & LTQ_SPI_ID_REV_MASK, hw->txfs, hw->rxfs, hw->dma_support);
++
++ return 0;
++
++err_bitbang:
++ ltq_spi_hw_disable(hw);
++
++err_clk:
++ if (hw->fpiclk)
++ clk_put(hw->fpiclk);
++ if (hw->spiclk)
++ clk_put(hw->spiclk);
++
++err_irq:
++ clk_put(hw->fpiclk);
++
++ for (; i > 0; i--)
++ free_irq(hw->irq[i], hw);
++
++err_master:
++ spi_master_put(master);
++
++err:
++ return ret;
++}
++
++static int __devexit ltq_spi_remove(struct platform_device *pdev)
++{
++ struct ltq_spi *hw = platform_get_drvdata(pdev);
++ int ret, i;
++
++ ret = spi_bitbang_stop(&hw->bitbang);
++ if (ret)
++ return ret;
++
++ platform_set_drvdata(pdev, NULL);
++
++ ltq_spi_config_mode_set(hw);
++ ltq_spi_hw_disable(hw);
++
++ for (i = 0; i < ARRAY_SIZE(hw->irq); i++)
++ if (0 < hw->irq[i])
++ free_irq(hw->irq[i], hw);
++
++ if (hw->fpiclk)
++ clk_put(hw->fpiclk);
++ if (hw->spiclk)
++ clk_put(hw->spiclk);
++
++ spi_master_put(hw->bitbang.master);
++
++ return 0;
++}
++
++static const struct of_device_id ltq_spi_match[] = {
++ { .compatible = "lantiq,spi-xway" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, ltq_spi_match);
++
++static struct platform_driver ltq_spi_driver = {
++ .probe = ltq_spi_probe,
++ .remove = __devexit_p(ltq_spi_remove),
++ .driver = {
++ .name = "spi-xway",
++ .owner = THIS_MODULE,
++ .of_match_table = ltq_spi_match,
++ },
++};
++
++module_platform_driver(ltq_spi_driver);
++
++MODULE_DESCRIPTION("Lantiq SoC SPI controller driver");
++MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:spi-xway");
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0115-NET-PHY-adds-driver-for-lantiq-PHY11G.patch b/target/linux/lantiq/patches-3.7/0115-NET-PHY-adds-driver-for-lantiq-PHY11G.patch
new file mode 100644
index 0000000000..7d3a6b9d15
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0115-NET-PHY-adds-driver-for-lantiq-PHY11G.patch
@@ -0,0 +1,228 @@
+From 12f4b99d63edc15849357c09e22a36445c2752cc Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 22 Oct 2012 09:28:30 +0200
+Subject: [PATCH 115/123] NET: PHY: adds driver for lantiq PHY11G
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/net/phy/Kconfig | 5 ++
+ drivers/net/phy/Makefile | 1 +
+ drivers/net/phy/lantiq.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 184 insertions(+)
+ create mode 100644 drivers/net/phy/lantiq.c
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 961f0b2..41a2992 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -107,6 +107,11 @@ config MICREL_PHY
+ ---help---
+ Supports the KSZ9021, VSC8201, KS8001 PHYs.
+
++config LANTIQ_PHY
++ tristate "Driver for Lantiq PHYs"
++ ---help---
++ Supports the 11G and 22E PHYs.
++
+ config FIXED_PHY
+ bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ depends on PHYLIB=y
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index 9645e38..e2eeee3 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -23,6 +23,7 @@ obj-$(CONFIG_NATIONAL_PHY) += national.o
+ obj-$(CONFIG_DP83640_PHY) += dp83640.o
+ obj-$(CONFIG_STE10XP) += ste10Xp.o
+ obj-$(CONFIG_MICREL_PHY) += micrel.o
++obj-$(CONFIG_LANTIQ_PHY) += lantiq.o
+ obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
+ obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
+ obj-$(CONFIG_AT803X_PHY) += at803x.o
+diff --git a/drivers/net/phy/lantiq.c b/drivers/net/phy/lantiq.c
+new file mode 100644
+index 0000000..ba4d7b7
+--- /dev/null
++++ b/drivers/net/phy/lantiq.c
+@@ -0,0 +1,178 @@
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
++ */
++
++#include <linux/module.h>
++#include <linux/phy.h>
++
++#define MII_MMDCTRL 0x0d
++#define MII_MMDDATA 0x0e
++
++#define MII_VR9_11G_IMASK 0x19 /* interrupt mask */
++#define MII_VR9_11G_ISTAT 0x1a /* interrupt status */
++
++#define INT_VR9_11G_WOL BIT(15) /* Wake-On-LAN */
++#define INT_VR9_11G_ANE BIT(11) /* Auto-Neg error */
++#define INT_VR9_11G_ANC BIT(10) /* Auto-Neg complete */
++#define INT_VR9_11G_ADSC BIT(5) /* Link auto-downspeed detect */
++#define INT_VR9_11G_DXMC BIT(2) /* Duplex mode change */
++#define INT_VR9_11G_LSPC BIT(1) /* Link speed change */
++#define INT_VR9_11G_LSTC BIT(0) /* Link state change */
++#define INT_VR9_11G_MASK (INT_VR9_11G_LSTC | INT_VR9_11G_ADSC)
++
++#define ADVERTISED_MPD BIT(10) /* Multi-port device */
++
++#define MMD_DEVAD 0x1f
++#define MMD_ACTYPE_SHIFT 14
++#define MMD_ACTYPE_ADDRESS (0 << MMD_ACTYPE_SHIFT)
++#define MMD_ACTYPE_DATA (1 << MMD_ACTYPE_SHIFT)
++#define MMD_ACTYPE_DATA_PI (2 << MMD_ACTYPE_SHIFT)
++#define MMD_ACTYPE_DATA_PIWR (3 << MMD_ACTYPE_SHIFT)
++
++static __maybe_unused int vr9_gphy_mmd_read(struct phy_device *phydev,
++ u16 regnum)
++{
++ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_ADDRESS | MMD_DEVAD);
++ phy_write(phydev, MII_MMDDATA, regnum);
++ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_DATA | MMD_DEVAD);
++
++ return phy_read(phydev, MII_MMDDATA);
++}
++
++static __maybe_unused int vr9_gphy_mmd_write(struct phy_device *phydev,
++ u16 regnum, u16 val)
++{
++ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_ADDRESS | MMD_DEVAD);
++ phy_write(phydev, MII_MMDDATA, regnum);
++ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_DATA | MMD_DEVAD);
++ phy_write(phydev, MII_MMDDATA, val);
++
++ return 0;
++}
++
++static int vr9_gphy_config_init(struct phy_device *phydev)
++{
++ int err;
++
++ dev_dbg(&phydev->dev, "%s\n", __func__);
++
++ /* Mask all interrupts */
++ err = phy_write(phydev, MII_VR9_11G_IMASK, 0);
++ if (err)
++ return err;
++
++ /* Clear all pending interrupts */
++ phy_read(phydev, MII_VR9_11G_ISTAT);
++
++ return 0;
++}
++
++static int vr9_gphy_config_aneg(struct phy_device *phydev)
++{
++ int reg, err;
++
++ /* Advertise as multi-port device */
++ reg = phy_read(phydev, MII_CTRL1000);
++ reg |= ADVERTISED_MPD;
++ err = phy_write(phydev, MII_CTRL1000, reg);
++ if (err)
++ return err;
++
++ return genphy_config_aneg(phydev);
++}
++
++static int vr9_gphy_ack_interrupt(struct phy_device *phydev)
++{
++ int reg;
++
++ /*
++ * Possible IRQ numbers:
++ * - IM3_IRL18 for GPHY0
++ * - IM3_IRL17 for GPHY1
++ *
++ * Due to a silicon bug IRQ lines are not really independent from
++ * each other. Sometimes the two lines are driven at the same time
++ * if only one GPHY core raises the interrupt.
++ */
++
++ reg = phy_read(phydev, MII_VR9_11G_ISTAT);
++
++ return (reg < 0) ? reg : 0;
++}
++
++static int vr9_gphy_did_interrupt(struct phy_device *phydev)
++{
++ int reg;
++
++ reg = phy_read(phydev, MII_VR9_11G_ISTAT);
++
++ return reg > 0;
++}
++
++static int vr9_gphy_config_intr(struct phy_device *phydev)
++{
++ int err;
++
++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
++ err = phy_write(phydev, MII_VR9_11G_IMASK, INT_VR9_11G_MASK);
++ else
++ err = phy_write(phydev, MII_VR9_11G_IMASK, 0);
++
++ return err;
++}
++
++/* TODO: add vr9_gphy_22f_driver and drivers for external Lantiq PEF7071 PHYs */
++static struct phy_driver vr9_gphy_11g_driver = {
++ .phy_id = 0xd565a408,
++ .phy_id_mask = 0xfffffff0,
++ .name = "Lantiq XWAY VR9 GPHY 11G",
++ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
++ .flags = 0, /*PHY_HAS_INTERRUPT,*/
++ .config_init = vr9_gphy_config_init,
++ .config_aneg = vr9_gphy_config_aneg,
++ .read_status = genphy_read_status,
++ .ack_interrupt = vr9_gphy_ack_interrupt,
++ .did_interrupt = vr9_gphy_did_interrupt,
++ .config_intr = vr9_gphy_config_intr,
++ .driver = { .owner = THIS_MODULE },
++};
++
++static int __init ltq_phy_init(void)
++{
++ int err;
++
++ err = phy_driver_register(&vr9_gphy_11g_driver);
++ if (err)
++ goto err_out;
++
++ return 0;
++
++err_out:
++ return err;
++}
++
++static void __exit ltq_phy_exit(void)
++{
++ phy_driver_unregister(&vr9_gphy_11g_driver);
++}
++
++module_init(ltq_phy_init);
++module_exit(ltq_phy_exit);
++
++MODULE_DESCRIPTION("Lantiq PHY drivers");
++MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>");
++MODULE_LICENSE("GPL");
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0116-NET-MIPS-lantiq-update-etop-driver-for-devicetree.patch b/target/linux/lantiq/patches-3.7/0116-NET-MIPS-lantiq-update-etop-driver-for-devicetree.patch
new file mode 100644
index 0000000000..cf93292e75
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0116-NET-MIPS-lantiq-update-etop-driver-for-devicetree.patch
@@ -0,0 +1,807 @@
+From c7b0e371e1c5e2f6258decfeb948e0dda7109afc Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Wed, 24 Oct 2012 19:50:30 +0200
+Subject: [PATCH 116/123] NET: MIPS: lantiq: update etop driver for devicetree
+
+---
+ drivers/net/ethernet/lantiq_etop.c | 470 +++++++++++++++++++++++++-----------
+ 1 file changed, 333 insertions(+), 137 deletions(-)
+
+diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
+index 003c5bc..dc5457a 100644
+--- a/drivers/net/ethernet/lantiq_etop.c
++++ b/drivers/net/ethernet/lantiq_etop.c
+@@ -12,7 +12,7 @@
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+- * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ * Copyright (C) 2011-12 John Crispin <blogic@openwrt.org>
+ */
+
+ #include <linux/kernel.h>
+@@ -36,6 +36,10 @@
+ #include <linux/io.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/of_net.h>
++#include <linux/of_irq.h>
++#include <linux/of_platform.h>
+
+ #include <asm/checksum.h>
+
+@@ -71,25 +75,56 @@
+ #define ETOP_MII_REVERSE 0xe
+ #define ETOP_PLEN_UNDER 0x40
+ #define ETOP_CGEN 0x800
+-
+-/* use 2 static channels for TX/RX */
+-#define LTQ_ETOP_TX_CHANNEL 1
+-#define LTQ_ETOP_RX_CHANNEL 6
+-#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL)
+-#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL)
+-
++#define ETOP_CFG_MII0 0x01
++
++#define LTQ_GBIT_MDIO_CTL 0xCC
++#define LTQ_GBIT_MDIO_DATA 0xd0
++#define LTQ_GBIT_GCTL0 0x68
++#define LTQ_GBIT_PMAC_HD_CTL 0x8c
++#define LTQ_GBIT_P0_CTL 0x4
++#define LTQ_GBIT_PMAC_RX_IPG 0xa8
++
++#define PMAC_HD_CTL_AS (1 << 19)
++#define PMAC_HD_CTL_RXSH (1 << 22)
++
++/* Switch Enable (0=disable, 1=enable) */
++#define GCTL0_SE 0x80000000
++/* Disable MDIO auto polling (0=disable, 1=enable) */
++#define PX_CTL_DMDIO 0x00400000
++
++/* register information for the gbit's MDIO bus */
++#define MDIO_XR9_REQUEST 0x00008000
++#define MDIO_XR9_READ 0x00000800
++#define MDIO_XR9_WRITE 0x00000400
++#define MDIO_XR9_REG_MASK 0x1f
++#define MDIO_XR9_ADDR_MASK 0x1f
++#define MDIO_XR9_RD_MASK 0xffff
++#define MDIO_XR9_REG_OFFSET 0
++#define MDIO_XR9_ADDR_OFFSET 5
++#define MDIO_XR9_WR_OFFSET 16
++
++#define LTQ_DMA_ETOP ((of_machine_is_compatible("lantiq,ase")) ? \
++ (INT_NUM_IM3_IRL0) : (INT_NUM_IM2_IRL0))
++
++/* the newer xway socks have a embedded 3/7 port gbit multiplexer */
+ #define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x))
+ #define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y))
+ #define ltq_etop_w32_mask(x, y, z) \
+ ltq_w32_mask(x, y, ltq_etop_membase + (z))
+
+-#define DRV_VERSION "1.0"
++#define ltq_gbit_r32(x) ltq_r32(ltq_gbit_membase + (x))
++#define ltq_gbit_w32(x, y) ltq_w32(x, ltq_gbit_membase + (y))
++#define ltq_gbit_w32_mask(x, y, z) \
++ ltq_w32_mask(x, y, ltq_gbit_membase + (z))
++
++#define DRV_VERSION "1.2"
+
+ static void __iomem *ltq_etop_membase;
++static void __iomem *ltq_gbit_membase;
+
+ struct ltq_etop_chan {
+- int idx;
+ int tx_free;
++ int irq;
+ struct net_device *netdev;
+ struct napi_struct napi;
+ struct ltq_dma_channel dma;
+@@ -99,22 +134,35 @@ struct ltq_etop_chan {
+ struct ltq_etop_priv {
+ struct net_device *netdev;
+ struct platform_device *pdev;
+- struct ltq_eth_data *pldata;
+ struct resource *res;
+
+ struct mii_bus *mii_bus;
+ struct phy_device *phydev;
+
+- struct ltq_etop_chan ch[MAX_DMA_CHAN];
+- int tx_free[MAX_DMA_CHAN >> 1];
++ struct ltq_etop_chan txch;
++ struct ltq_etop_chan rxch;
++
++ int tx_irq;
++ int rx_irq;
++
++ const void *mac;
++ int mii_mode;
+
+ spinlock_t lock;
++
++ struct clk *clk_ppe;
++ struct clk *clk_switch;
++ struct clk *clk_ephy;
++ struct clk *clk_ephycgu;
+ };
+
++static int ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr,
++ int phy_reg, u16 phy_data);
++
+ static int
+ ltq_etop_alloc_skb(struct ltq_etop_chan *ch)
+ {
+- ch->skb[ch->dma.desc] = netdev_alloc_skb(ch->netdev, MAX_DMA_DATA_LEN);
++ ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN);
+ if (!ch->skb[ch->dma.desc])
+ return -ENOMEM;
+ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL,
+@@ -149,8 +197,11 @@ ltq_etop_hw_receive(struct ltq_etop_chan *ch)
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ skb_put(skb, len);
++ skb->dev = ch->netdev;
+ skb->protocol = eth_type_trans(skb, ch->netdev);
+ netif_receive_skb(skb);
++ ch->netdev->stats.rx_packets++;
++ ch->netdev->stats.rx_bytes += len;
+ }
+
+ static int
+@@ -158,8 +209,10 @@ ltq_etop_poll_rx(struct napi_struct *napi, int budget)
+ {
+ struct ltq_etop_chan *ch = container_of(napi,
+ struct ltq_etop_chan, napi);
++ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
+ int rx = 0;
+ int complete = 0;
++ unsigned long flags;
+
+ while ((rx < budget) && !complete) {
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+@@ -173,7 +226,9 @@ ltq_etop_poll_rx(struct napi_struct *napi, int budget)
+ }
+ if (complete || !rx) {
+ napi_complete(&ch->napi);
++ spin_lock_irqsave(&priv->lock, flags);
+ ltq_dma_ack_irq(&ch->dma);
++ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ return rx;
+ }
+@@ -185,12 +240,14 @@ ltq_etop_poll_tx(struct napi_struct *napi, int budget)
+ container_of(napi, struct ltq_etop_chan, napi);
+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
+ struct netdev_queue *txq =
+- netdev_get_tx_queue(ch->netdev, ch->idx >> 1);
++ netdev_get_tx_queue(ch->netdev, ch->dma.nr >> 1);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ while ((ch->dma.desc_base[ch->tx_free].ctl &
+ (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
++ ch->netdev->stats.tx_packets++;
++ ch->netdev->stats.tx_bytes += ch->skb[ch->tx_free]->len;
+ dev_kfree_skb_any(ch->skb[ch->tx_free]);
+ ch->skb[ch->tx_free] = NULL;
+ memset(&ch->dma.desc_base[ch->tx_free], 0,
+@@ -203,7 +260,9 @@ ltq_etop_poll_tx(struct napi_struct *napi, int budget)
+ if (netif_tx_queue_stopped(txq))
+ netif_tx_start_queue(txq);
+ napi_complete(&ch->napi);
++ spin_lock_irqsave(&priv->lock, flags);
+ ltq_dma_ack_irq(&ch->dma);
++ spin_unlock_irqrestore(&priv->lock, flags);
+ return 1;
+ }
+
+@@ -211,9 +270,10 @@ static irqreturn_t
+ ltq_etop_dma_irq(int irq, void *_priv)
+ {
+ struct ltq_etop_priv *priv = _priv;
+- int ch = irq - LTQ_DMA_CH0_INT;
+-
+- napi_schedule(&priv->ch[ch].napi);
++ if (irq == priv->txch.dma.irq)
++ napi_schedule(&priv->txch.napi);
++ else
++ napi_schedule(&priv->rxch.napi);
+ return IRQ_HANDLED;
+ }
+
+@@ -225,7 +285,7 @@ ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch)
+ ltq_dma_free(&ch->dma);
+ if (ch->dma.irq)
+ free_irq(ch->dma.irq, priv);
+- if (IS_RX(ch->idx)) {
++ if (ch == &priv->txch) {
+ int desc;
+ for (desc = 0; desc < LTQ_DESC_NUM; desc++)
+ dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+@@ -236,23 +296,55 @@ static void
+ ltq_etop_hw_exit(struct net_device *dev)
+ {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+- int i;
+
+- ltq_pmu_disable(PMU_PPE);
+- for (i = 0; i < MAX_DMA_CHAN; i++)
+- if (IS_TX(i) || IS_RX(i))
+- ltq_etop_free_channel(dev, &priv->ch[i]);
++ clk_disable(priv->clk_ppe);
++
++ if (of_machine_is_compatible("lantiq,ar9"))
++ clk_disable(priv->clk_switch);
++
++ if (of_machine_is_compatible("lantiq,ase")) {
++ clk_disable(priv->clk_ephy);
++ clk_disable(priv->clk_ephycgu);
++ }
++
++ ltq_etop_free_channel(dev, &priv->txch);
++ ltq_etop_free_channel(dev, &priv->rxch);
++}
++
++static void
++ltq_etop_gbit_init(struct net_device *dev)
++{
++ struct ltq_etop_priv *priv = netdev_priv(dev);
++
++ clk_enable(priv->clk_switch);
++
++ ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0);
++ /** Disable MDIO auto polling mode */
++ ltq_gbit_w32_mask(0, PX_CTL_DMDIO, LTQ_GBIT_P0_CTL);
++ /* set 1522 packet size */
++ ltq_gbit_w32_mask(0x300, 0, LTQ_GBIT_GCTL0);
++ /* disable pmac & dmac headers */
++ ltq_gbit_w32_mask(PMAC_HD_CTL_AS | PMAC_HD_CTL_RXSH, 0,
++ LTQ_GBIT_PMAC_HD_CTL);
++ /* Due to traffic halt when burst length 8,
++ replace default IPG value with 0x3B */
++ ltq_gbit_w32(0x3B, LTQ_GBIT_PMAC_RX_IPG);
+ }
+
+ static int
+ ltq_etop_hw_init(struct net_device *dev)
+ {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+- int i;
+
+- ltq_pmu_enable(PMU_PPE);
++ clk_enable(priv->clk_ppe);
+
+- switch (priv->pldata->mii_mode) {
++ if (of_machine_is_compatible("lantiq,ar9")) {
++ ltq_etop_gbit_init(dev);
++ /* force the etops link to the gbit to MII */
++ priv->mii_mode = PHY_INTERFACE_MODE_MII;
++ }
++
++ switch (priv->mii_mode) {
+ case PHY_INTERFACE_MODE_RMII:
+ ltq_etop_w32_mask(ETOP_MII_MASK,
+ ETOP_MII_REVERSE, LTQ_ETOP_CFG);
+@@ -264,39 +356,68 @@ ltq_etop_hw_init(struct net_device *dev)
+ break;
+
+ default:
++ if (of_machine_is_compatible("lantiq,ase")) {
++ clk_enable(priv->clk_ephy);
++ /* disable external MII */
++ ltq_etop_w32_mask(0, ETOP_CFG_MII0, LTQ_ETOP_CFG);
++ /* enable clock for internal PHY */
++ clk_enable(priv->clk_ephycgu);
++ /* we need to write this magic to the internal phy to
++ make it work */
++ ltq_etop_mdio_wr(NULL, 0x8, 0x12, 0xC020);
++ pr_info("Selected EPHY mode\n");
++ break;
++ }
+ netdev_err(dev, "unknown mii mode %d\n",
+- priv->pldata->mii_mode);
++ priv->mii_mode);
+ return -ENOTSUPP;
+ }
+
+ /* enable crc generation */
+ ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG);
+
++ return 0;
++}
++
++static int
++ltq_etop_dma_init(struct net_device *dev)
++{
++ struct ltq_etop_priv *priv = netdev_priv(dev);
++ int tx = priv->tx_irq - LTQ_DMA_ETOP;
++ int rx = priv->rx_irq - LTQ_DMA_ETOP;
++ int err;
++
+ ltq_dma_init_port(DMA_PORT_ETOP);
+
+- for (i = 0; i < MAX_DMA_CHAN; i++) {
+- int irq = LTQ_DMA_CH0_INT + i;
+- struct ltq_etop_chan *ch = &priv->ch[i];
+-
+- ch->idx = ch->dma.nr = i;
+-
+- if (IS_TX(i)) {
+- ltq_dma_alloc_tx(&ch->dma);
+- request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
+- "etop_tx", priv);
+- } else if (IS_RX(i)) {
+- ltq_dma_alloc_rx(&ch->dma);
+- for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
+- ch->dma.desc++)
+- if (ltq_etop_alloc_skb(ch))
+- return -ENOMEM;
+- ch->dma.desc = 0;
+- request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
+- "etop_rx", priv);
++ priv->txch.dma.nr = tx;
++ ltq_dma_alloc_tx(&priv->txch.dma);
++ err = request_irq(priv->tx_irq, ltq_etop_dma_irq, IRQF_DISABLED,
++ "eth_tx", priv);
++ if (err) {
++ netdev_err(dev, "failed to allocate tx irq\n");
++ goto err_out;
++ }
++ priv->txch.dma.irq = priv->tx_irq;
++
++ priv->rxch.dma.nr = rx;
++ ltq_dma_alloc_rx(&priv->rxch.dma);
++ for (priv->rxch.dma.desc = 0; priv->rxch.dma.desc < LTQ_DESC_NUM;
++ priv->rxch.dma.desc++) {
++ if (ltq_etop_alloc_skb(&priv->rxch)) {
++ netdev_err(dev, "failed to allocate skbs\n");
++ err = -ENOMEM;
++ goto err_out;
+ }
+- ch->dma.irq = irq;
+ }
+- return 0;
++ priv->rxch.dma.desc = 0;
++ err = request_irq(priv->rx_irq, ltq_etop_dma_irq, IRQF_DISABLED,
++ "eth_rx", priv);
++ if (err)
++ netdev_err(dev, "failed to allocate rx irq\n");
++ else
++ priv->rxch.dma.irq = priv->rx_irq;
++err_out:
++ return err;
+ }
+
+ static void
+@@ -312,7 +433,10 @@ ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+- return phy_ethtool_gset(priv->phydev, cmd);
++ if (priv->phydev)
++ return phy_ethtool_gset(priv->phydev, cmd);
++ else
++ return 0;
+ }
+
+ static int
+@@ -320,7 +444,10 @@ ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+- return phy_ethtool_sset(priv->phydev, cmd);
++ if (priv->phydev)
++ return phy_ethtool_sset(priv->phydev, cmd);
++ else
++ return 0;
+ }
+
+ static int
+@@ -328,7 +455,10 @@ ltq_etop_nway_reset(struct net_device *dev)
+ {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+- return phy_start_aneg(priv->phydev);
++ if (priv->phydev)
++ return phy_start_aneg(priv->phydev);
++ else
++ return 0;
+ }
+
+ static const struct ethtool_ops ltq_etop_ethtool_ops = {
+@@ -339,6 +469,39 @@ static const struct ethtool_ops ltq_etop_ethtool_ops = {
+ };
+
+ static int
++ltq_etop_mdio_wr_xr9(struct mii_bus *bus, int phy_addr,
++ int phy_reg, u16 phy_data)
++{
++ u32 val = MDIO_XR9_REQUEST | MDIO_XR9_WRITE |
++ (phy_data << MDIO_XR9_WR_OFFSET) |
++ ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) |
++ ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET);
++
++ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
++ ;
++ ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL);
++ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
++ ;
++ return 0;
++}
++
++static int
++ltq_etop_mdio_rd_xr9(struct mii_bus *bus, int phy_addr, int phy_reg)
++{
++ u32 val = MDIO_XR9_REQUEST | MDIO_XR9_READ |
++ ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) |
++ ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET);
++
++ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
++ ;
++ ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL);
++ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
++ ;
++ val = ltq_gbit_r32(LTQ_GBIT_MDIO_DATA) & MDIO_XR9_RD_MASK;
++ return val;
++}
++
++static int
+ ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data)
+ {
+ u32 val = MDIO_REQUEST |
+@@ -379,14 +542,11 @@ ltq_etop_mdio_probe(struct net_device *dev)
+ {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+- int phy_addr;
+
+- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+- if (priv->mii_bus->phy_map[phy_addr]) {
+- phydev = priv->mii_bus->phy_map[phy_addr];
+- break;
+- }
+- }
++ if (of_machine_is_compatible("lantiq,ase"))
++ phydev = priv->mii_bus->phy_map[8];
++ else
++ phydev = priv->mii_bus->phy_map[0];
+
+ if (!phydev) {
+ netdev_err(dev, "no PHY found\n");
+@@ -394,7 +554,7 @@ ltq_etop_mdio_probe(struct net_device *dev)
+ }
+
+ phydev = phy_connect(dev, dev_name(&phydev->dev), &ltq_etop_mdio_link,
+- 0, priv->pldata->mii_mode);
++ 0, priv->mii_mode);
+
+ if (IS_ERR(phydev)) {
+ netdev_err(dev, "Could not attach to PHY\n");
+@@ -408,6 +568,9 @@ ltq_etop_mdio_probe(struct net_device *dev)
+ | SUPPORTED_Autoneg
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
++ if (of_machine_is_compatible("lantiq,ar9"))
++ phydev->supported &= SUPPORTED_1000baseT_Half
++ | SUPPORTED_1000baseT_Full;
+
+ phydev->advertising = phydev->supported;
+ priv->phydev = phydev;
+@@ -433,8 +596,13 @@ ltq_etop_mdio_init(struct net_device *dev)
+ }
+
+ priv->mii_bus->priv = dev;
+- priv->mii_bus->read = ltq_etop_mdio_rd;
+- priv->mii_bus->write = ltq_etop_mdio_wr;
++ if (of_machine_is_compatible("lantiq,ar9")) {
++ priv->mii_bus->read = ltq_etop_mdio_rd_xr9;
++ priv->mii_bus->write = ltq_etop_mdio_wr_xr9;
++ } else {
++ priv->mii_bus->read = ltq_etop_mdio_rd;
++ priv->mii_bus->write = ltq_etop_mdio_wr;
++ }
+ priv->mii_bus->name = "ltq_mii";
+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+ priv->pdev->name, priv->pdev->id);
+@@ -483,17 +651,19 @@ static int
+ ltq_etop_open(struct net_device *dev)
+ {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+- int i;
++ unsigned long flags;
+
+- for (i = 0; i < MAX_DMA_CHAN; i++) {
+- struct ltq_etop_chan *ch = &priv->ch[i];
++ napi_enable(&priv->txch.napi);
++ napi_enable(&priv->rxch.napi);
++
++ spin_lock_irqsave(&priv->lock, flags);
++ ltq_dma_open(&priv->txch.dma);
++ ltq_dma_open(&priv->rxch.dma);
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ if (priv->phydev)
++ phy_start(priv->phydev);
+
+- if (!IS_TX(i) && (!IS_RX(i)))
+- continue;
+- ltq_dma_open(&ch->dma);
+- napi_enable(&ch->napi);
+- }
+- phy_start(priv->phydev);
+ netif_tx_start_all_queues(dev);
+ return 0;
+ }
+@@ -502,18 +672,19 @@ static int
+ ltq_etop_stop(struct net_device *dev)
+ {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+- int i;
++ unsigned long flags;
+
+ netif_tx_stop_all_queues(dev);
+- phy_stop(priv->phydev);
+- for (i = 0; i < MAX_DMA_CHAN; i++) {
+- struct ltq_etop_chan *ch = &priv->ch[i];
++ if (priv->phydev)
++ phy_stop(priv->phydev);
++ napi_disable(&priv->txch.napi);
++ napi_disable(&priv->rxch.napi);
++
++ spin_lock_irqsave(&priv->lock, flags);
++ ltq_dma_close(&priv->txch.dma);
++ ltq_dma_close(&priv->rxch.dma);
++ spin_unlock_irqrestore(&priv->lock, flags);
+
+- if (!IS_RX(i) && !IS_TX(i))
+- continue;
+- napi_disable(&ch->napi);
+- ltq_dma_close(&ch->dma);
+- }
+ return 0;
+ }
+
+@@ -523,16 +694,16 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
+ int queue = skb_get_queue_mapping(skb);
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue);
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+- struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1];
+- struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+- int len;
++ struct ltq_dma_desc *desc =
++ &priv->txch.dma.desc_base[priv->txch.dma.desc];
+ unsigned long flags;
+ u32 byte_offset;
++ int len;
+
+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+
+- if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
+- dev_kfree_skb_any(skb);
++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) ||
++ priv->txch.skb[priv->txch.dma.desc]) {
+ netdev_err(dev, "tx ring full\n");
+ netif_tx_stop_queue(txq);
+ return NETDEV_TX_BUSY;
+@@ -540,7 +711,7 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
+
+ /* dma needs to start on a 16 byte aligned address */
+ byte_offset = CPHYSADDR(skb->data) % 16;
+- ch->skb[ch->dma.desc] = skb;
++ priv->txch.skb[priv->txch.dma.desc] = skb;
+
+ dev->trans_start = jiffies;
+
+@@ -550,11 +721,11 @@ ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
+ wmb();
+ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
+ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
+- ch->dma.desc++;
+- ch->dma.desc %= LTQ_DESC_NUM;
++ priv->txch.dma.desc++;
++ priv->txch.dma.desc %= LTQ_DESC_NUM;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+- if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN)
++ if (priv->txch.dma.desc_base[priv->txch.dma.desc].ctl & LTQ_DMA_OWN)
+ netif_tx_stop_queue(txq);
+
+ return NETDEV_TX_OK;
+@@ -633,34 +804,32 @@ ltq_etop_init(struct net_device *dev)
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct sockaddr mac;
+ int err;
+- bool random_mac = false;
+
+ ether_setup(dev);
+ dev->watchdog_timeo = 10 * HZ;
+ err = ltq_etop_hw_init(dev);
+ if (err)
+ goto err_hw;
++ err = ltq_etop_dma_init(dev);
++ if (err)
++ goto err_hw;
++
+ ltq_etop_change_mtu(dev, 1500);
+
+- memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr));
++ memcpy(&mac.sa_data, priv->mac, ETH_ALEN);
+ if (!is_valid_ether_addr(mac.sa_data)) {
+ pr_warn("etop: invalid MAC, using random\n");
+- eth_random_addr(mac.sa_data);
+- random_mac = true;
++ random_ether_addr(mac.sa_data);
+ }
+
+ err = ltq_etop_set_mac_address(dev, &mac);
+ if (err)
+ goto err_netdev;
+-
+- /* Set addr_assign_type here, ltq_etop_set_mac_address would reset it. */
+- if (random_mac)
+- dev->addr_assign_type |= NET_ADDR_RANDOM;
+-
+ ltq_etop_set_multicast_list(dev);
+- err = ltq_etop_mdio_init(dev);
+- if (err)
+- goto err_netdev;
++ if (!ltq_etop_mdio_init(dev))
++ dev->ethtool_ops = &ltq_etop_ethtool_ops;
++ else
++ pr_warn("etop: mdio probe failed\n");;
+ return 0;
+
+ err_netdev:
+@@ -680,6 +849,9 @@ ltq_etop_tx_timeout(struct net_device *dev)
+ err = ltq_etop_hw_init(dev);
+ if (err)
+ goto err_hw;
++ err = ltq_etop_dma_init(dev);
++ if (err)
++ goto err_hw;
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ return;
+@@ -703,14 +875,19 @@ static const struct net_device_ops ltq_eth_netdev_ops = {
+ .ndo_tx_timeout = ltq_etop_tx_timeout,
+ };
+
+-static int __init
++static int __devinit
+ ltq_etop_probe(struct platform_device *pdev)
+ {
+ struct net_device *dev;
+ struct ltq_etop_priv *priv;
+- struct resource *res;
++ struct resource *res, *gbit_res, irqres[2];
+ int err;
+- int i;
++
++ err = of_irq_to_resource_table(pdev->dev.of_node, irqres, 2);
++ if (err != 2) {
++ dev_err(&pdev->dev, "failed to get etop irqs\n");
++ return -EINVAL;
++ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+@@ -736,30 +913,58 @@ ltq_etop_probe(struct platform_device *pdev)
+ goto err_out;
+ }
+
+- dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
+- if (!dev) {
+- err = -ENOMEM;
+- goto err_out;
++ if (of_machine_is_compatible("lantiq,ar9")) {
++ gbit_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!gbit_res) {
++ dev_err(&pdev->dev, "failed to get gbit resource\n");
++ err = -ENOENT;
++ goto err_out;
++ }
++ ltq_gbit_membase = devm_ioremap_nocache(&pdev->dev,
++ gbit_res->start, resource_size(gbit_res));
++ if (!ltq_gbit_membase) {
++ dev_err(&pdev->dev, "failed to remap gigabit switch %d\n",
++ pdev->id);
++ err = -ENOMEM;
++ goto err_out;
++ }
+ }
++
++ dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
+ strcpy(dev->name, "eth%d");
+ dev->netdev_ops = &ltq_eth_netdev_ops;
+- dev->ethtool_ops = &ltq_etop_ethtool_ops;
+ priv = netdev_priv(dev);
+ priv->res = res;
+ priv->pdev = pdev;
+- priv->pldata = dev_get_platdata(&pdev->dev);
+ priv->netdev = dev;
++ priv->tx_irq = irqres[0].start;
++ priv->rx_irq = irqres[1].start;
++ priv->mii_mode = of_get_phy_mode(pdev->dev.of_node);
++ priv->mac = of_get_mac_address(pdev->dev.of_node);
++
++ priv->clk_ppe = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(priv->clk_ppe))
++ return PTR_ERR(priv->clk_ppe);
++ if (of_machine_is_compatible("lantiq,ar9")) {
++ priv->clk_switch = clk_get(&pdev->dev, "switch");
++ if (IS_ERR(priv->clk_switch))
++ return PTR_ERR(priv->clk_switch);
++ }
++ if (of_machine_is_compatible("lantiq,ase")) {
++ priv->clk_ephy = clk_get(&pdev->dev, "ephy");
++ if (IS_ERR(priv->clk_ephy))
++ return PTR_ERR(priv->clk_ephy);
++ priv->clk_ephycgu = clk_get(&pdev->dev, "ephycgu");
++ if (IS_ERR(priv->clk_ephycgu))
++ return PTR_ERR(priv->clk_ephycgu);
++ }
++
+ spin_lock_init(&priv->lock);
+
+- for (i = 0; i < MAX_DMA_CHAN; i++) {
+- if (IS_TX(i))
+- netif_napi_add(dev, &priv->ch[i].napi,
+- ltq_etop_poll_tx, 8);
+- else if (IS_RX(i))
+- netif_napi_add(dev, &priv->ch[i].napi,
+- ltq_etop_poll_rx, 32);
+- priv->ch[i].netdev = dev;
+- }
++ netif_napi_add(dev, &priv->txch.napi, ltq_etop_poll_tx, 8);
++ netif_napi_add(dev, &priv->rxch.napi, ltq_etop_poll_rx, 32);
++ priv->txch.netdev = dev;
++ priv->rxch.netdev = dev;
+
+ err = register_netdev(dev);
+ if (err)
+@@ -788,32 +993,23 @@ ltq_etop_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++static const struct of_device_id ltq_etop_match[] = {
++ { .compatible = "lantiq,etop-xway" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, ltq_etop_match);
++
+ static struct platform_driver ltq_mii_driver = {
++ .probe = ltq_etop_probe,
+ .remove = __devexit_p(ltq_etop_remove),
+ .driver = {
+ .name = "ltq_etop",
+ .owner = THIS_MODULE,
++ .of_match_table = ltq_etop_match,
+ },
+ };
+
+-int __init
+-init_ltq_etop(void)
+-{
+- int ret = platform_driver_probe(&ltq_mii_driver, ltq_etop_probe);
+-
+- if (ret)
+- pr_err("ltq_etop: Error registering platform driver!");
+- return ret;
+-}
+-
+-static void __exit
+-exit_ltq_etop(void)
+-{
+- platform_driver_unregister(&ltq_mii_driver);
+-}
+-
+-module_init(init_ltq_etop);
+-module_exit(exit_ltq_etop);
++module_platform_driver(ltq_mii_driver);
+
+ MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+ MODULE_DESCRIPTION("Lantiq SoC ETOP");
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0117-NET-MIPS-lantiq-adds-xrx200-net.patch b/target/linux/lantiq/patches-3.7/0117-NET-MIPS-lantiq-adds-xrx200-net.patch
new file mode 100644
index 0000000000..3d3596344c
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0117-NET-MIPS-lantiq-adds-xrx200-net.patch
@@ -0,0 +1,1414 @@
+From a0a6f7f03c914327064364767b7ba688cdbcf611 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 22 Oct 2012 12:22:23 +0200
+Subject: [PATCH 117/123] NET: MIPS: lantiq: adds xrx200-net
+
+---
+ drivers/net/ethernet/Kconfig | 8 +-
+ drivers/net/ethernet/Makefile | 1 +
+ drivers/net/ethernet/lantiq_pce.h | 163 +++++
+ drivers/net/ethernet/lantiq_xrx200.c | 1191 ++++++++++++++++++++++++++++++++++
+ 4 files changed, 1362 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/ethernet/lantiq_pce.h
+ create mode 100644 drivers/net/ethernet/lantiq_xrx200.c
+
+diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
+index e4ff389..35cb7b0 100644
+--- a/drivers/net/ethernet/Kconfig
++++ b/drivers/net/ethernet/Kconfig
+@@ -83,7 +83,13 @@ config LANTIQ_ETOP
+ tristate "Lantiq SoC ETOP driver"
+ depends on SOC_TYPE_XWAY
+ ---help---
+- Support for the MII0 inside the Lantiq SoC
++ Support for the MII0 inside the Lantiq ADSL SoC
++
++config LANTIQ_XRX200
++ tristate "Lantiq SoC XRX200 driver"
++ depends on SOC_TYPE_XWAY
++ ---help---
++ Support for the MII0 inside the Lantiq VDSL SoC
+
+ source "drivers/net/ethernet/marvell/Kconfig"
+ source "drivers/net/ethernet/mellanox/Kconfig"
+diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
+index d447307..4f95100 100644
+--- a/drivers/net/ethernet/Makefile
++++ b/drivers/net/ethernet/Makefile
+@@ -36,6 +36,7 @@ obj-$(CONFIG_IP1000) += icplus/
+ obj-$(CONFIG_JME) += jme.o
+ obj-$(CONFIG_KORINA) += korina.o
+ obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
++obj-$(CONFIG_LANTIQ_XRX200) += lantiq_xrx200.o
+ obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/
+ obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
+ obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
+diff --git a/drivers/net/ethernet/lantiq_pce.h b/drivers/net/ethernet/lantiq_pce.h
+new file mode 100644
+index 0000000..0c38efe
+--- /dev/null
++++ b/drivers/net/ethernet/lantiq_pce.h
+@@ -0,0 +1,163 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
++ *
++ * PCE microcode extracted from UGW5.2 switch api
++ */
++
++/* Switch API Micro Code V0.3 */
++enum {
++ OUT_MAC0 = 0,
++ OUT_MAC1,
++ OUT_MAC2,
++ OUT_MAC3,
++ OUT_MAC4,
++ OUT_MAC5,
++ OUT_ETHTYP,
++ OUT_VTAG0,
++ OUT_VTAG1,
++ OUT_ITAG0,
++ OUT_ITAG1, /*10 */
++ OUT_ITAG2,
++ OUT_ITAG3,
++ OUT_IP0,
++ OUT_IP1,
++ OUT_IP2,
++ OUT_IP3,
++ OUT_SIP0,
++ OUT_SIP1,
++ OUT_SIP2,
++ OUT_SIP3, /*20*/
++ OUT_SIP4,
++ OUT_SIP5,
++ OUT_SIP6,
++ OUT_SIP7,
++ OUT_DIP0,
++ OUT_DIP1,
++ OUT_DIP2,
++ OUT_DIP3,
++ OUT_DIP4,
++ OUT_DIP5, /*30*/
++ OUT_DIP6,
++ OUT_DIP7,
++ OUT_SESID,
++ OUT_PROT,
++ OUT_APP0,
++ OUT_APP1,
++ OUT_IGMP0,
++ OUT_IGMP1,
++ OUT_IPOFF, /*39*/
++ OUT_NONE = 63
++};
++
++/* parser's microcode length type */
++#define INSTR 0
++#define IPV6 1
++#define LENACCU 2
++
++/* parser's microcode flag type */
++enum {
++ FLAG_ITAG = 0,
++ FLAG_VLAN,
++ FLAG_SNAP,
++ FLAG_PPPOE,
++ FLAG_IPV6,
++ FLAG_IPV6FL,
++ FLAG_IPV4,
++ FLAG_IGMP,
++ FLAG_TU,
++ FLAG_HOP,
++ FLAG_NN1, /*10 */
++ FLAG_NN2,
++ FLAG_END,
++ FLAG_NO, /*13*/
++};
++
++/* Micro code version V2_11 (extension for parsing IPv6 in PPPoE) */
++#define MC_ENTRY(val, msk, ns, out, len, type, flags, ipv4_len) \
++ { {val, msk, (ns<<10 | out<<4 | len>>1), (len&1)<<15 | type<<13 | flags<<9 | ipv4_len<<8 }}
++struct pce_microcode {
++ unsigned short val[4];
++/* unsigned short val_2;
++ unsigned short val_1;
++ unsigned short val_0;*/
++} pce_microcode[] = {
++ /* value mask ns fields L type flags ipv4_len */
++ MC_ENTRY(0x88c3, 0xFFFF, 1, OUT_ITAG0, 4, INSTR, FLAG_ITAG, 0),
++ MC_ENTRY(0x8100, 0xFFFF, 2, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0),
++ MC_ENTRY(0x88A8, 0xFFFF, 1, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0),
++ MC_ENTRY(0x8100, 0xFFFF, 1, OUT_VTAG0, 2, INSTR, FLAG_VLAN, 0),
++ MC_ENTRY(0x8864, 0xFFFF, 17, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0800, 0xFFFF, 21, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x86DD, 0xFFFF, 22, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x8863, 0xFFFF, 16, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0xF800, 10, OUT_NONE, 0, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 38, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0600, 0x0600, 38, OUT_ETHTYP, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 12, OUT_NONE, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0xAAAA, 0xFFFF, 14, OUT_NONE, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0300, 0xFF00, 39, OUT_NONE, 0, INSTR, FLAG_SNAP, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_DIP7, 3, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 18, OUT_DIP7, 3, INSTR, FLAG_PPPOE, 0),
++ MC_ENTRY(0x0021, 0xFFFF, 21, OUT_NONE, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0057, 0xFFFF, 22, OUT_NONE, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x4000, 0xF000, 24, OUT_IP0, 4, INSTR, FLAG_IPV4, 1),
++ MC_ENTRY(0x6000, 0xF000, 27, OUT_IP0, 3, INSTR, FLAG_IPV6, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 25, OUT_IP3, 2, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 26, OUT_SIP0, 4, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 38, OUT_NONE, 0, LENACCU, FLAG_NO, 0),
++ MC_ENTRY(0x1100, 0xFF00, 37, OUT_PROT, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0600, 0xFF00, 37, OUT_PROT, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_HOP, 0),
++ MC_ENTRY(0x2B00, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_NN1, 0),
++ MC_ENTRY(0x3C00, 0xFF00, 33, OUT_IP3, 17, INSTR, FLAG_NN2, 0),
++ MC_ENTRY(0x0000, 0x0000, 37, OUT_PROT, 1, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_HOP, 0),
++ MC_ENTRY(0x2B00, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_NN1, 0),
++ MC_ENTRY(0x3C00, 0xFF00, 33, OUT_NONE, 0, IPV6, FLAG_NN2, 0),
++ MC_ENTRY(0x0000, 0x0000, 38, OUT_PROT, 1, IPV6, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 38, OUT_SIP0, 16, INSTR, FLAG_NO, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_APP0, 4, INSTR, FLAG_IGMP, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++ MC_ENTRY(0x0000, 0x0000, 39, OUT_NONE, 0, INSTR, FLAG_END, 0),
++};
+diff --git a/drivers/net/ethernet/lantiq_xrx200.c b/drivers/net/ethernet/lantiq_xrx200.c
+new file mode 100644
+index 0000000..458bc11
+--- /dev/null
++++ b/drivers/net/ethernet/lantiq_xrx200.c
+@@ -0,0 +1,1191 @@
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright (C) 2010 Lantiq Deutschland
++ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/etherdevice.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <asm/delay.h>
++
++#include <linux/of_net.h>
++#include <linux/of_mdio.h>
++
++#include <xway_dma.h>
++#include <lantiq_soc.h>
++
++#include "lantiq_pce.h"
++
++#define SW_POLLING
++#define SW_ROUTING
++#define SW_PORTMAP
++
++#ifdef SW_ROUTING
++ #ifdef SW_PORTMAP
++#define XRX200_MAX_DEV 7
++ #else
++#define XRX200_MAX_DEV 2
++ #endif
++#else
++#define XRX200_MAX_DEV 1
++#endif
++
++#define XRX200_MAX_PORT 7
++#define XRX200_MAX_DMA 8
++
++#define XRX200_HEADROOM 4
++
++#define XRX200_TX_TIMEOUT (10 * HZ)
++
++/* port type */
++#define XRX200_PORT_TYPE_PHY 1
++#define XRX200_PORT_TYPE_MAC 2
++
++/* DMA */
++#define XRX200_DMA_CRC_LEN 0x4
++#define XRX200_DMA_DATA_LEN 0x600
++#define XRX200_DMA_IRQ INT_NUM_IM2_IRL0
++#define XRX200_DMA_RX 0
++#define XRX200_DMA_TX 1
++
++/* fetch / store dma */
++#define FDMA_PCTRL0 0x2A00
++#define FDMA_PCTRLx(x) (FDMA_PCTRL0 + (x * 0x18))
++#define SDMA_PCTRL0 0x2F00
++#define SDMA_PCTRLx(x) (SDMA_PCTRL0 + (x * 0x18))
++
++/* buffer management */
++#define BM_PCFG0 0x200
++#define BM_PCFGx(x) (BM_PCFG0 + (x * 8))
++
++/* MDIO */
++#define MDIO_GLOB 0x0000
++#define MDIO_CTRL 0x0020
++#define MDIO_READ 0x0024
++#define MDIO_WRITE 0x0028
++#define MDIO_PHY0 0x0054
++#define MDIO_PHY(x) (0x0054 - (x * sizeof(unsigned)))
++#define MDIO_CLK_CFG0 0x002C
++#define MDIO_CLK_CFG1 0x0030
++
++#define MDIO_GLOB_ENABLE 0x8000
++#define MDIO_BUSY BIT(12)
++#define MDIO_RD BIT(11)
++#define MDIO_WR BIT(10)
++#define MDIO_MASK 0x1f
++#define MDIO_ADDRSHIFT 5
++#define MDIO1_25MHZ 9
++
++#define MDIO_PHY_LINK_DOWN 0x4000
++#define MDIO_PHY_LINK_UP 0x2000
++
++#define MDIO_PHY_SPEED_M10 0x0000
++#define MDIO_PHY_SPEED_M100 0x0800
++#define MDIO_PHY_SPEED_G1 0x1000
++
++#define MDIO_PHY_FDUP_EN 0x0600
++#define MDIO_PHY_FDUP_DIS 0x0200
++
++#define MDIO_PHY_LINK_MASK 0x6000
++#define MDIO_PHY_SPEED_MASK 0x1800
++#define MDIO_PHY_FDUP_MASK 0x0600
++#define MDIO_PHY_ADDR_MASK 0x001f
++#define MDIO_UPDATE_MASK MDIO_PHY_ADDR_MASK | MDIO_PHY_LINK_MASK | \
++ MDIO_PHY_SPEED_MASK | MDIO_PHY_FDUP_MASK
++
++/* MII */
++#define MII_CFG(p) (p * 8)
++
++#define MII_CFG_EN BIT(14)
++
++#define MII_CFG_MODE_MIIP 0x0
++#define MII_CFG_MODE_MIIM 0x1
++#define MII_CFG_MODE_RMIIP 0x2
++#define MII_CFG_MODE_RMIIM 0x3
++#define MII_CFG_MODE_RGMII 0x4
++#define MII_CFG_MODE_MASK 0xf
++
++#define MII_CFG_RATE_M2P5 0x00
++#define MII_CFG_RATE_M25 0x10
++#define MII_CFG_RATE_M125 0x20
++#define MII_CFG_RATE_M50 0x30
++#define MII_CFG_RATE_AUTO 0x40
++#define MII_CFG_RATE_MASK 0x70
++
++/* cpu port mac */
++#define PMAC_HD_CTL 0x0000
++#define PMAC_RX_IPG 0x0024
++#define PMAC_EWAN 0x002c
++
++#define PMAC_IPG_MASK 0xf
++#define PMAC_HD_CTL_AS 0x0008
++#define PMAC_HD_CTL_AC 0x0004
++#define PMAC_HD_CTL_RXSH 0x0040
++#define PMAC_HD_CTL_AST 0x0080
++#define PMAC_HD_CTL_RST 0x0100
++
++/* PCE */
++#define PCE_TBL_KEY(x) (0x1100 + ((7 - x) * 4))
++#define PCE_TBL_MASK 0x1120
++#define PCE_TBL_VAL(x) (0x1124 + ((4 - x) * 4))
++#define PCE_TBL_ADDR 0x1138
++#define PCE_TBL_CTRL 0x113c
++#define PCE_PMAP1 0x114c
++#define PCE_PMAP2 0x1150
++#define PCE_PMAP3 0x1154
++#define PCE_GCTRL_REG(x) (0x1158 + (x * 4))
++#define PCE_PCTRL_REG(p, x) (0x1200 + (((p * 0xa) + x) * 4))
++
++#define PCE_TBL_BUSY BIT(15)
++#define PCE_TBL_CFG_ADDR_MASK 0x1f
++#define PCE_TBL_CFG_ADWR 0x20
++#define PCE_TBL_CFG_ADWR_MASK 0x60
++#define PCE_INGRESS BIT(11)
++
++/* MAC */
++#define MAC_FLEN_REG (0x2314)
++#define MAC_CTRL_REG(p, x) (0x240c + (((p * 0xc) + x) * 4))
++
++/* buffer management */
++#define BM_PCFG(p) (0x200 + (p * 8))
++
++/* special tag in TX path header */
++#define SPID_SHIFT 24
++#define DPID_SHIFT 16
++#define DPID_ENABLE 1
++#define SPID_CPU_PORT 2
++#define PORT_MAP_SEL BIT(15)
++#define PORT_MAP_EN BIT(14)
++#define PORT_MAP_SHIFT 1
++#define PORT_MAP_MASK 0x3f
++
++#define SPPID_MASK 0x7
++#define SPPID_SHIFT 4
++
++/* MII regs not yet in linux */
++#define MDIO_DEVAD_NONE (-1)
++#define ADVERTIZE_MPD (1 << 10)
++
++struct xrx200_port {
++ u8 num;
++ u8 phy_addr;
++ u16 flags;
++ phy_interface_t phy_if;
++
++ int link;
++
++ struct phy_device *phydev;
++ struct device_node *phy_node;
++};
++
++struct xrx200_chan {
++ int idx;
++ int refcount;
++ int tx_free;
++
++ struct net_device dummy_dev;
++ struct net_device *devs[XRX200_MAX_DEV];
++
++ struct napi_struct napi;
++ struct ltq_dma_channel dma;
++ struct sk_buff *skb[LTQ_DESC_NUM];
++};
++
++struct xrx200_hw {
++ struct clk *clk;
++ struct mii_bus *mii_bus;
++
++ struct xrx200_chan chan[XRX200_MAX_DMA];
++
++ struct net_device *devs[XRX200_MAX_DEV];
++ int num_devs;
++
++ int port_map[XRX200_MAX_PORT];
++ unsigned short wan_map;
++
++ spinlock_t lock;
++};
++
++struct xrx200_priv {
++ struct net_device_stats stats;
++ int id;
++
++ struct xrx200_port port[XRX200_MAX_PORT];
++ int num_port;
++ int wan;
++ unsigned short port_map;
++ const void *mac;
++
++ struct xrx200_hw *hw;
++};
++
++static __iomem void *xrx200_switch_membase;
++static __iomem void *xrx200_mii_membase;
++static __iomem void *xrx200_mdio_membase;
++static __iomem void *xrx200_pmac_membase;
++
++#define ltq_switch_r32(x) ltq_r32(xrx200_switch_membase + (x))
++#define ltq_switch_w32(x, y) ltq_w32(x, xrx200_switch_membase + (y))
++#define ltq_switch_w32_mask(x, y, z) \
++ ltq_w32_mask(x, y, xrx200_switch_membase + (z))
++
++#define ltq_mdio_r32(x) ltq_r32(xrx200_mdio_membase + (x))
++#define ltq_mdio_w32(x, y) ltq_w32(x, xrx200_mdio_membase + (y))
++#define ltq_mdio_w32_mask(x, y, z) \
++ ltq_w32_mask(x, y, xrx200_mdio_membase + (z))
++
++#define ltq_mii_r32(x) ltq_r32(xrx200_mii_membase + (x))
++#define ltq_mii_w32(x, y) ltq_w32(x, xrx200_mii_membase + (y))
++#define ltq_mii_w32_mask(x, y, z) \
++ ltq_w32_mask(x, y, xrx200_mii_membase + (z))
++
++#define ltq_pmac_r32(x) ltq_r32(xrx200_pmac_membase + (x))
++#define ltq_pmac_w32(x, y) ltq_w32(x, xrx200_pmac_membase + (y))
++#define ltq_pmac_w32_mask(x, y, z) \
++ ltq_w32_mask(x, y, xrx200_pmac_membase + (z))
++
++static int xrx200_open(struct net_device *dev)
++{
++ struct xrx200_priv *priv = netdev_priv(dev);
++ unsigned long flags;
++ int i;
++
++ for (i = 0; i < XRX200_MAX_DMA; i++) {
++ if (!priv->hw->chan[i].dma.irq)
++ continue;
++ spin_lock_irqsave(&priv->hw->lock, flags);
++ if (!priv->hw->chan[i].refcount) {
++ napi_enable(&priv->hw->chan[i].napi);
++ ltq_dma_open(&priv->hw->chan[i].dma);
++ }
++ priv->hw->chan[i].refcount++;
++ spin_unlock_irqrestore(&priv->hw->lock, flags);
++ }
++ for (i = 0; i < priv->num_port; i++)
++ if (priv->port[i].phydev)
++ phy_start(priv->port[i].phydev);
++ netif_start_queue(dev);
++
++ return 0;
++}
++
++static int xrx200_close(struct net_device *dev)
++{
++ struct xrx200_priv *priv = netdev_priv(dev);
++ unsigned long flags;
++ int i;
++
++ netif_stop_queue(dev);
++
++ for (i = 0; i < priv->num_port; i++)
++ if (priv->port[i].phydev)
++ phy_stop(priv->port[i].phydev);
++
++ for (i = 0; i < XRX200_MAX_DMA; i++) {
++ if (!priv->hw->chan[i].dma.irq)
++ continue;
++ spin_lock_irqsave(&priv->hw->lock, flags);
++ priv->hw->chan[i].refcount--;
++ if (!priv->hw->chan[i].refcount) {
++ napi_disable(&priv->hw->chan[i].napi);
++ ltq_dma_close(&priv->hw->chan[XRX200_DMA_RX].dma);
++ }
++ spin_unlock_irqrestore(&priv->hw->lock, flags);
++ }
++
++ return 0;
++}
++
++static int xrx200_alloc_skb(struct xrx200_chan *ch)
++{
++#define DMA_PAD (NET_IP_ALIGN + NET_SKB_PAD)
++ ch->skb[ch->dma.desc] = dev_alloc_skb(XRX200_DMA_DATA_LEN + DMA_PAD);
++ if (!ch->skb[ch->dma.desc])
++ return -ENOMEM;
++
++ skb_reserve(ch->skb[ch->dma.desc], NET_SKB_PAD);
++ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL,
++ ch->skb[ch->dma.desc]->data, XRX200_DMA_DATA_LEN,
++ DMA_FROM_DEVICE);
++ ch->dma.desc_base[ch->dma.desc].addr =
++ CPHYSADDR(ch->skb[ch->dma.desc]->data);
++ ch->dma.desc_base[ch->dma.desc].ctl =
++ LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
++ XRX200_DMA_DATA_LEN;
++ skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN);
++
++ return 0;
++}
++
++static void xrx200_hw_receive(struct xrx200_chan *ch, int id)
++{
++ struct net_device *dev = ch->devs[id];
++ struct xrx200_priv *priv = netdev_priv(dev);
++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
++ struct sk_buff *skb = ch->skb[ch->dma.desc];
++ int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - XRX200_DMA_CRC_LEN;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->hw->lock, flags);
++ if (xrx200_alloc_skb(ch)) {
++ netdev_err(dev,
++ "failed to allocate new rx buffer, stopping DMA\n");
++ ltq_dma_close(&ch->dma);
++ }
++
++ ch->dma.desc++;
++ ch->dma.desc %= LTQ_DESC_NUM;
++ spin_unlock_irqrestore(&priv->hw->lock, flags);
++
++ skb_put(skb, len);
++#ifdef SW_ROUTING
++ skb_pull(skb, 8);
++#endif
++ skb->dev = dev;
++ skb->protocol = eth_type_trans(skb, dev);
++ netif_receive_skb(skb);
++ priv->stats.rx_packets++;
++ priv->stats.rx_bytes+=len;
++}
++
++static int xrx200_poll_rx(struct napi_struct *napi, int budget)
++{
++ struct xrx200_chan *ch = container_of(napi,
++ struct xrx200_chan, napi);
++ struct xrx200_priv *priv = netdev_priv(ch->devs[0]);
++ int rx = 0;
++ int complete = 0;
++ unsigned long flags;
++
++ while ((rx < budget) && !complete) {
++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
++#ifdef SW_ROUTING
++ struct sk_buff *skb = ch->skb[ch->dma.desc];
++ u32 *special_tag = (u32*)skb->data;
++ int port = (special_tag[1] >> SPPID_SHIFT) & SPPID_MASK;
++ xrx200_hw_receive(ch, priv->hw->port_map[port]);
++#else
++ xrx200_hw_receive(ch, 0);
++#endif
++ rx++;
++ } else {
++ complete = 1;
++ }
++ }
++ if (complete || !rx) {
++ napi_complete(&ch->napi);
++ spin_lock_irqsave(&priv->hw->lock, flags);
++ ltq_dma_ack_irq(&ch->dma);
++ spin_unlock_irqrestore(&priv->hw->lock, flags);
++ }
++ return rx;
++}
++
++static int xrx200_poll_tx(struct napi_struct *napi, int budget)
++{
++ struct xrx200_chan *ch =
++ container_of(napi, struct xrx200_chan, napi);
++ struct xrx200_priv *priv = netdev_priv(ch->devs[0]);
++ unsigned long flags;
++ int i;
++
++ spin_lock_irqsave(&priv->hw->lock, flags);
++ while ((ch->dma.desc_base[ch->tx_free].ctl &
++ (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
++ dev_kfree_skb_any(ch->skb[ch->tx_free]);
++ ch->skb[ch->tx_free] = NULL;
++ memset(&ch->dma.desc_base[ch->tx_free], 0,
++ sizeof(struct ltq_dma_desc));
++ ch->tx_free++;
++ ch->tx_free %= LTQ_DESC_NUM;
++ }
++ spin_unlock_irqrestore(&priv->hw->lock, flags);
++
++ for (i = 0; i < XRX200_MAX_DEV && ch->devs[i]; i++) {
++ struct netdev_queue *txq =
++ netdev_get_tx_queue(ch->devs[i], 0);
++ if (netif_tx_queue_stopped(txq))
++ netif_tx_start_queue(txq);
++ }
++ napi_complete(&ch->napi);
++ spin_lock_irqsave(&priv->hw->lock, flags);
++ ltq_dma_ack_irq(&ch->dma);
++ spin_unlock_irqrestore(&priv->hw->lock, flags);
++
++ return 1;
++}
++
++static struct net_device_stats *xrx200_get_stats (struct net_device *dev)
++{
++ struct xrx200_priv *priv = netdev_priv(dev);
++
++ return &priv->stats;
++}
++
++static void xrx200_tx_timeout(struct net_device *dev)
++{
++ struct xrx200_priv *priv = netdev_priv(dev);
++
++ printk(KERN_ERR "%s: transmit timed out, disable the dma channel irq\n", dev->name);
++
++ priv->stats.tx_errors++;
++ netif_wake_queue(dev);
++}
++
++static int xrx200_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ int queue = skb_get_queue_mapping(skb);
++ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue);
++ struct xrx200_priv *priv = netdev_priv(dev);
++ struct xrx200_chan *ch = &priv->hw->chan[XRX200_DMA_TX];
++ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
++ unsigned long flags;
++ u32 byte_offset;
++ int len;
++#ifdef SW_ROUTING
++ #ifdef SW_PORTMAP
++ u32 special_tag = (SPID_CPU_PORT << SPID_SHIFT) | PORT_MAP_SEL | PORT_MAP_EN | DPID_ENABLE;
++ #else
++ u32 special_tag = (SPID_CPU_PORT << SPID_SHIFT) | DPID_ENABLE;
++ #endif
++#endif
++
++ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
++
++ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
++ netdev_err(dev, "tx ring full\n");
++ netif_tx_stop_queue(txq);
++ return NETDEV_TX_BUSY;
++ }
++#ifdef SW_ROUTING
++ #ifdef SW_PORTMAP
++ special_tag |= priv->port_map << PORT_MAP_SHIFT;
++ #else
++ if(priv->id)
++ special_tag |= (1 << DPID_SHIFT);
++ #endif
++ if(skb_headroom(skb) < 4) {
++ struct sk_buff *tmp = skb_realloc_headroom(skb, 4);
++ dev_kfree_skb_any(skb);
++ skb = tmp;
++ }
++ skb_push(skb, 4);
++ memcpy(skb->data, &special_tag, sizeof(u32));
++ len += 4;
++#endif
++
++ /* dma needs to start on a 16 byte aligned address */
++ byte_offset = CPHYSADDR(skb->data) % 16;
++ ch->skb[ch->dma.desc] = skb;
++
++ dev->trans_start = jiffies;
++
++ spin_lock_irqsave(&priv->hw->lock, flags);
++ desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len,
++ DMA_TO_DEVICE)) - byte_offset;
++ wmb();
++ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
++ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
++ ch->dma.desc++;
++ ch->dma.desc %= LTQ_DESC_NUM;
++ spin_unlock_irqrestore(&priv->hw->lock, flags);
++
++ if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN)
++ netif_tx_stop_queue(txq);
++
++ priv->stats.tx_packets++;
++ priv->stats.tx_bytes+=len;
++
++ return NETDEV_TX_OK;
++}
++
++static irqreturn_t xrx200_dma_irq(int irq, void *priv)
++{
++ struct xrx200_hw *hw = priv;
++ int ch = irq - XRX200_DMA_IRQ;
++
++ napi_schedule(&hw->chan[ch].napi);
++
++ return IRQ_HANDLED;
++}
++
++static int xrx200_dma_init(struct xrx200_hw *hw)
++{
++ int i, err = 0;
++
++ ltq_dma_init_port(DMA_PORT_ETOP);
++
++ for (i = 0; i < 8 && !err; i++) {
++ int irq = XRX200_DMA_IRQ + i;
++ struct xrx200_chan *ch = &hw->chan[i];
++
++ ch->idx = ch->dma.nr = i;
++
++ if (i == XRX200_DMA_TX) {
++ ltq_dma_alloc_tx(&ch->dma);
++ err = request_irq(irq, xrx200_dma_irq, 0, "vrx200_tx", hw);
++ } else if (i == XRX200_DMA_RX) {
++ ltq_dma_alloc_rx(&ch->dma);
++ for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
++ ch->dma.desc++)
++ if (xrx200_alloc_skb(ch))
++ err = -ENOMEM;
++ ch->dma.desc = 0;
++ err = request_irq(irq, xrx200_dma_irq, 0, "vrx200_rx", hw);
++ } else
++ continue;
++
++ if (!err)
++ ch->dma.irq = irq;
++ }
++
++ return err;
++}
++
++#ifdef SW_POLLING
++static void xrx200_gmac_update(struct xrx200_port *port)
++{
++ u16 phyaddr = port->phydev->addr & MDIO_PHY_ADDR_MASK;
++ u16 miimode = ltq_mii_r32(MII_CFG(port->num)) & MII_CFG_MODE_MASK;
++ u16 miirate = 0;
++
++ switch (port->phydev->speed) {
++ case SPEED_1000:
++ phyaddr |= MDIO_PHY_SPEED_G1;
++ miirate = MII_CFG_RATE_M125;
++ break;
++
++ case SPEED_100:
++ phyaddr |= MDIO_PHY_SPEED_M100;
++ switch (miimode) {
++ case MII_CFG_MODE_RMIIM:
++ case MII_CFG_MODE_RMIIP:
++ miirate = MII_CFG_RATE_M50;
++ break;
++ default:
++ miirate = MII_CFG_RATE_M25;
++ break;
++ }
++ break;
++
++ default:
++ phyaddr |= MDIO_PHY_SPEED_M10;
++ miirate = MII_CFG_RATE_M2P5;
++ break;
++ }
++
++ if (port->phydev->link)
++ phyaddr |= MDIO_PHY_LINK_UP;
++ else
++ phyaddr |= MDIO_PHY_LINK_DOWN;
++
++ if (port->phydev->duplex == DUPLEX_FULL)
++ phyaddr |= MDIO_PHY_FDUP_EN;
++ else
++ phyaddr |= MDIO_PHY_FDUP_DIS;
++
++ ltq_mdio_w32_mask(MDIO_UPDATE_MASK, phyaddr, MDIO_PHY(port->num));
++ ltq_mii_w32_mask(MII_CFG_RATE_MASK, miirate, MII_CFG(port->num));
++ udelay(1);
++}
++#else
++static void xrx200_gmac_update(struct xrx200_port *port)
++{
++
++}
++#endif
++
++static void xrx200_mdio_link(struct net_device *dev)
++{
++ struct xrx200_priv *priv = netdev_priv(dev);
++ int i;
++
++ for (i = 0; i < priv->num_port; i++) {
++ if (!priv->port[i].phydev)
++ continue;
++
++ if (priv->port[i].link != priv->port[i].phydev->link) {
++ xrx200_gmac_update(&priv->port[i]);
++ priv->port[i].link = priv->port[i].phydev->link;
++ netdev_info(dev, "port %d %s link\n",
++ priv->port[i].num,
++ (priv->port[i].link)?("got"):("lost"));
++ }
++ }
++}
++
++static inline int xrx200_mdio_poll(struct mii_bus *bus)
++{
++ unsigned cnt = 10000;
++
++ while (likely(cnt--)) {
++ unsigned ctrl = ltq_mdio_r32(MDIO_CTRL);
++ if ((ctrl & MDIO_BUSY) == 0)
++ return 0;
++ }
++
++ return 1;
++}
++
++static int xrx200_mdio_wr(struct mii_bus *bus, int addr, int reg, u16 val)
++{
++ if (xrx200_mdio_poll(bus))
++ return 1;
++
++ ltq_mdio_w32(val, MDIO_WRITE);
++ ltq_mdio_w32(MDIO_BUSY | MDIO_WR |
++ ((addr & MDIO_MASK) << MDIO_ADDRSHIFT) |
++ (reg & MDIO_MASK),
++ MDIO_CTRL);
++
++ return 0;
++}
++
++static int xrx200_mdio_rd(struct mii_bus *bus, int addr, int reg)
++{
++ if (xrx200_mdio_poll(bus))
++ return -1;
++
++ ltq_mdio_w32(MDIO_BUSY | MDIO_RD |
++ ((addr & MDIO_MASK) << MDIO_ADDRSHIFT) |
++ (reg & MDIO_MASK),
++ MDIO_CTRL);
++
++ if (xrx200_mdio_poll(bus))
++ return -1;
++
++ return ltq_mdio_r32(MDIO_READ);
++}
++
++static int xrx200_mdio_probe(struct net_device *dev, struct xrx200_port *port)
++{
++ struct xrx200_priv *priv = netdev_priv(dev);
++ struct phy_device *phydev = NULL;
++ unsigned val;
++
++ phydev = priv->hw->mii_bus->phy_map[port->phy_addr];
++
++ if (!phydev) {
++ netdev_err(dev, "no PHY found\n");
++ return -ENODEV;
++ }
++
++ phydev = phy_connect(dev, dev_name(&phydev->dev), &xrx200_mdio_link,
++ 0, port->phy_if);
++
++ if (IS_ERR(phydev)) {
++ netdev_err(dev, "Could not attach to PHY\n");
++ return PTR_ERR(phydev);
++ }
++
++ phydev->supported &= (SUPPORTED_10baseT_Half
++ | SUPPORTED_10baseT_Full
++ | SUPPORTED_100baseT_Half
++ | SUPPORTED_100baseT_Full
++ | SUPPORTED_1000baseT_Half
++ | SUPPORTED_1000baseT_Full
++ | SUPPORTED_Autoneg
++ | SUPPORTED_MII
++ | SUPPORTED_TP);
++ phydev->advertising = phydev->supported;
++ port->phydev = phydev;
++
++ pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n",
++ dev->name, phydev->drv->name,
++ dev_name(&phydev->dev), phydev->irq);
++
++#ifdef SW_POLLING
++ phy_read_status(phydev);
++
++ val = xrx200_mdio_rd(priv->hw->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000);
++ val |= ADVERTIZE_MPD;
++ xrx200_mdio_wr(priv->hw->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000, val);
++ xrx200_mdio_wr(priv->hw->mii_bus, 0, 0, 0x1040);
++
++ phy_start_aneg(phydev);
++#endif
++ return 0;
++}
++
++static void xrx200_port_config(struct xrx200_priv *priv,
++ const struct xrx200_port *port)
++{
++ u16 miimode = 0;
++
++ switch (port->num) {
++ case 0: /* xMII0 */
++ case 1: /* xMII1 */
++ switch (port->phy_if) {
++ case PHY_INTERFACE_MODE_MII:
++ if (port->flags & XRX200_PORT_TYPE_PHY)
++ /* MII MAC mode, connected to external PHY */
++ miimode = MII_CFG_MODE_MIIM;
++ else
++ /* MII PHY mode, connected to external MAC */
++ miimode = MII_CFG_MODE_MIIP;
++ break;
++ case PHY_INTERFACE_MODE_RMII:
++ if (port->flags & XRX200_PORT_TYPE_PHY)
++ /* RMII MAC mode, connected to external PHY */
++ miimode = MII_CFG_MODE_RMIIM;
++ else
++ /* RMII PHY mode, connected to external MAC */
++ miimode = MII_CFG_MODE_RMIIP;
++ break;
++ case PHY_INTERFACE_MODE_RGMII:
++ /* RGMII MAC mode, connected to external PHY */
++ miimode = MII_CFG_MODE_RGMII;
++ break;
++ default:
++ break;
++ }
++ break;
++ case 2: /* internal GPHY0 */
++ case 3: /* internal GPHY0 */
++ case 4: /* internal GPHY1 */
++ switch (port->phy_if) {
++ case PHY_INTERFACE_MODE_MII:
++ case PHY_INTERFACE_MODE_GMII:
++ /* MII MAC mode, connected to internal GPHY */
++ miimode = MII_CFG_MODE_MIIM;
++ break;
++ default:
++ break;
++ }
++ break;
++ case 5: /* internal GPHY1 or xMII2 */
++ switch (port->phy_if) {
++ case PHY_INTERFACE_MODE_MII:
++ /* MII MAC mode, connected to internal GPHY */
++ miimode = MII_CFG_MODE_MIIM;
++ break;
++ case PHY_INTERFACE_MODE_RGMII:
++ /* RGMII MAC mode, connected to external PHY */
++ miimode = MII_CFG_MODE_RGMII;
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++
++ ltq_mii_w32_mask(MII_CFG_MODE_MASK, miimode | MII_CFG_EN,
++ MII_CFG(port->num));
++}
++
++static int xrx200_init(struct net_device *dev)
++{
++ struct xrx200_priv *priv = netdev_priv(dev);
++ struct sockaddr mac;
++ int err, i;
++
++#ifndef SW_POLLING
++ unsigned int reg = 0;
++
++ /* enable auto polling */
++ for (i = 0; i < priv->num_port; i++)
++ reg |= BIT(priv->port[i].num);
++ ltq_mdio_w32(reg, MDIO_CLK_CFG0);
++ ltq_mdio_w32(MDIO1_25MHZ, MDIO_CLK_CFG1);
++#endif
++
++ /* setup each port */
++ for (i = 0; i < priv->num_port; i++)
++ xrx200_port_config(priv, &priv->port[i]);
++
++ memcpy(&mac.sa_data, priv->mac, ETH_ALEN);
++ if (!is_valid_ether_addr(mac.sa_data)) {
++ pr_warn("net-xrx200: invalid MAC, using random\n");
++ eth_random_addr(mac.sa_data);
++ dev->addr_assign_type |= NET_ADDR_RANDOM;
++ }
++
++ err = eth_mac_addr(dev, &mac);
++ if (err)
++ goto err_netdev;
++
++ for (i = 0; i < priv->num_port; i++)
++ if (xrx200_mdio_probe(dev, &priv->port[i]))
++ pr_warn("xrx200-mdio: probing phy of port %d failed\n",
++ priv->port[i].num);
++
++ return 0;
++
++err_netdev:
++ unregister_netdev(dev);
++ free_netdev(dev);
++ return err;
++}
++
++static void xrx200_pci_microcode(void)
++{
++ int i;
++
++ ltq_switch_w32_mask(PCE_TBL_CFG_ADDR_MASK | PCE_TBL_CFG_ADWR_MASK,
++ PCE_TBL_CFG_ADWR, PCE_TBL_CTRL);
++ ltq_switch_w32(0, PCE_TBL_MASK);
++
++ for (i = 0; i < ARRAY_SIZE(pce_microcode); i++) {
++ ltq_switch_w32(i, PCE_TBL_ADDR);
++ ltq_switch_w32(pce_microcode[i].val[3], PCE_TBL_VAL(0));
++ ltq_switch_w32(pce_microcode[i].val[2], PCE_TBL_VAL(1));
++ ltq_switch_w32(pce_microcode[i].val[1], PCE_TBL_VAL(2));
++ ltq_switch_w32(pce_microcode[i].val[0], PCE_TBL_VAL(3));
++
++ // start the table access:
++ ltq_switch_w32_mask(0, PCE_TBL_BUSY, PCE_TBL_CTRL);
++ while (ltq_switch_r32(PCE_TBL_CTRL) & PCE_TBL_BUSY);
++ }
++
++ /* tell the switch that the microcode is loaded */
++ ltq_switch_w32_mask(0, BIT(3), PCE_GCTRL_REG(0));
++}
++
++static void xrx200_hw_init(struct xrx200_hw *hw)
++{
++ int i;
++
++ /* enable clock gate */
++ clk_enable(hw->clk);
++
++ ltq_switch_w32(1, 0);
++ mdelay(100);
++ ltq_switch_w32(0, 0);
++ /*
++ * TODO: we should really disbale all phys/miis here and explicitly
++ * enable them in the device secific init function
++ */
++
++ /* disable port fetch/store dma */
++ for (i = 0; i < 7; i++ ) {
++ ltq_switch_w32(0, FDMA_PCTRLx(i));
++ ltq_switch_w32(0, SDMA_PCTRLx(i));
++ }
++
++ /* enable Switch */
++ ltq_mdio_w32_mask(0, MDIO_GLOB_ENABLE, MDIO_GLOB);
++
++ /* load the pce microcode */
++ xrx200_pci_microcode();
++
++ /* Default unknown Broadcat/Multicast/Unicast port maps */
++ ltq_switch_w32(0x7f, PCE_PMAP1);
++ ltq_switch_w32(0x7f, PCE_PMAP2);
++ ltq_switch_w32(0x7f, PCE_PMAP3);
++
++ /* RMON Counter Enable for all physical ports */
++ for (i = 0; i < 7; i++)
++ ltq_switch_w32(0x1, BM_PCFG(i));
++
++ /* disable auto polling */
++ ltq_mdio_w32(0x0, MDIO_CLK_CFG0);
++
++ /* enable port statistic counters */
++ for (i = 0; i < 7; i++)
++ ltq_switch_w32(0x1, BM_PCFGx(i));
++
++ /* set IPG to 12 */
++ ltq_pmac_w32_mask(PMAC_IPG_MASK, 0xb, PMAC_RX_IPG);
++
++#ifdef SW_ROUTING
++ /* enable status header, enable CRC */
++ ltq_pmac_w32_mask(0,
++ PMAC_HD_CTL_RST | PMAC_HD_CTL_AST | PMAC_HD_CTL_RXSH | PMAC_HD_CTL_AS | PMAC_HD_CTL_AC,
++ PMAC_HD_CTL);
++#else
++ /* disable status header, enable CRC */
++ ltq_pmac_w32_mask(PMAC_HD_CTL_AST | PMAC_HD_CTL_RXSH | PMAC_HD_CTL_AS,
++ PMAC_HD_CTL_AC,
++ PMAC_HD_CTL);
++#endif
++
++ /* enable port fetch/store dma */
++ for (i = 0; i < 7; i++ ) {
++ ltq_switch_w32_mask(0, 0x01, FDMA_PCTRLx(i));
++ ltq_switch_w32_mask(0, 0x01, SDMA_PCTRLx(i));
++ ltq_switch_w32_mask(0, PCE_INGRESS, PCE_PCTRL_REG(i, 0));
++ }
++
++ /* enable special tag insertion on cpu port */
++ ltq_switch_w32_mask(0, 0x02, FDMA_PCTRLx(6));
++ ltq_switch_w32_mask(0, PCE_INGRESS, PCE_PCTRL_REG(6, 0));
++ ltq_switch_w32_mask(0, BIT(3), MAC_CTRL_REG(6, 2));
++ ltq_switch_w32(1518 + 8 + 4 * 2, MAC_FLEN_REG);
++}
++
++static void xrx200_hw_cleanup(struct xrx200_hw *hw)
++{
++ int i;
++
++ /* disable the switch */
++ ltq_mdio_w32_mask(MDIO_GLOB_ENABLE, 0, MDIO_GLOB);
++
++ /* free the channels and IRQs */
++ for (i = 0; i < 2; i++) {
++ ltq_dma_free(&hw->chan[i].dma);
++ if (hw->chan[i].dma.irq)
++ free_irq(hw->chan[i].dma.irq, hw);
++ }
++
++ /* free the allocated RX ring */
++ for (i = 0; i < LTQ_DESC_NUM; i++)
++ dev_kfree_skb_any(hw->chan[XRX200_DMA_RX].skb[i]);
++
++ /* clear the mdio bus */
++ mdiobus_unregister(hw->mii_bus);
++ mdiobus_free(hw->mii_bus);
++
++ /* release the clock */
++ clk_disable(hw->clk);
++ clk_put(hw->clk);
++}
++
++static int xrx200_of_mdio(struct xrx200_hw *hw, struct device_node *np)
++{
++ hw->mii_bus = mdiobus_alloc();
++ if (!hw->mii_bus)
++ return -ENOMEM;
++
++ hw->mii_bus->read = xrx200_mdio_rd;
++ hw->mii_bus->write = xrx200_mdio_wr;
++ hw->mii_bus->name = "lantiq,xrx200-mdio";
++ snprintf(hw->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
++
++ if (of_mdiobus_register(hw->mii_bus, np)) {
++ mdiobus_free(hw->mii_bus);
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++static void xrx200_of_port(struct xrx200_priv *priv, struct device_node *port)
++{
++ const __be32 *addr, *id = of_get_property(port, "reg", NULL);
++ struct xrx200_port *p = &priv->port[priv->num_port];
++
++ if (!id)
++ return;
++
++ memset(p, 0, sizeof(struct xrx200_port));
++ p->phy_node = of_parse_phandle(port, "phy-handle", 0);
++ addr = of_get_property(p->phy_node, "reg", NULL);
++ if (!addr)
++ return;
++
++ p->num = *id;
++ p->phy_addr = *addr;
++ p->phy_if = of_get_phy_mode(port);
++ if (p->phy_addr > 0x10)
++ p->flags = XRX200_PORT_TYPE_MAC;
++ else
++ p->flags = XRX200_PORT_TYPE_PHY;
++ priv->num_port++;
++
++ /* is this port a wan port ? */
++ if (priv->wan)
++ priv->hw->wan_map |= BIT(p->num);
++
++ priv->port_map |= BIT(p->num);
++
++ /* store the port id in the hw struct so we can map ports -> devices */
++ priv->hw->port_map[p->num] = priv->hw->num_devs;
++}
++
++static const struct net_device_ops xrx200_netdev_ops = {
++ .ndo_init = xrx200_init,
++ .ndo_open = xrx200_open,
++ .ndo_stop = xrx200_close,
++ .ndo_start_xmit = xrx200_start_xmit,
++ .ndo_set_mac_address = eth_mac_addr,
++ .ndo_validate_addr = eth_validate_addr,
++ .ndo_change_mtu = eth_change_mtu,
++ .ndo_get_stats = xrx200_get_stats,
++ .ndo_tx_timeout = xrx200_tx_timeout,
++};
++
++static void xrx200_of_iface(struct xrx200_hw *hw, struct device_node *iface)
++{
++ struct xrx200_priv *priv;
++ struct device_node *port;
++ const __be32 *wan;
++
++ /* alloc the network device */
++ hw->devs[hw->num_devs] = alloc_etherdev(sizeof(struct xrx200_priv));
++ if (!hw->devs[hw->num_devs])
++ return;
++
++ /* setup the network device */
++ strcpy(hw->devs[hw->num_devs]->name, "eth%d");
++ hw->devs[hw->num_devs]->netdev_ops = &xrx200_netdev_ops;
++ hw->devs[hw->num_devs]->watchdog_timeo = XRX200_TX_TIMEOUT;
++ hw->devs[hw->num_devs]->needed_headroom = XRX200_HEADROOM;
++
++ /* setup our private data */
++ priv = netdev_priv(hw->devs[hw->num_devs]);
++ priv->hw = hw;
++ priv->mac = of_get_mac_address(iface);
++ priv->id = hw->num_devs;
++
++ /* is this the wan interface ? */
++ wan = of_get_property(iface, "lantiq,wan", NULL);
++ if (wan && (*wan == 1))
++ priv->wan = 1;
++
++ /* load the ports that are part of the interface */
++ for_each_child_of_node(iface, port)
++ if (of_device_is_compatible(port, "lantiq,xrx200-pdi-port"))
++ xrx200_of_port(priv, port);
++
++ /* register the actual device */
++ if (!register_netdev(hw->devs[hw->num_devs]))
++ hw->num_devs++;
++}
++
++static struct xrx200_hw xrx200_hw;
++
++static int __devinit xrx200_probe(struct platform_device *pdev)
++{
++ struct resource *res[4];
++ struct device_node *mdio_np, *iface_np;
++ int i;
++
++ /* load the memory ranges */
++ for (i = 0; i < 4; i++) {
++ res[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
++ if (!res[i]) {
++ dev_err(&pdev->dev, "failed to get resources\n");
++ return -ENOENT;
++ }
++ }
++ xrx200_switch_membase = devm_request_and_ioremap(&pdev->dev, res[0]);
++ xrx200_mdio_membase = devm_request_and_ioremap(&pdev->dev, res[1]);
++ xrx200_mii_membase = devm_request_and_ioremap(&pdev->dev, res[2]);
++ xrx200_pmac_membase = devm_request_and_ioremap(&pdev->dev, res[3]);
++ if (!xrx200_switch_membase || !xrx200_mdio_membase ||
++ !xrx200_mii_membase || !xrx200_pmac_membase) {
++ dev_err(&pdev->dev, "failed to request and remap io ranges \n");
++ return -ENOMEM;
++ }
++
++ /* get the clock */
++ xrx200_hw.clk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(xrx200_hw.clk)) {
++ dev_err(&pdev->dev, "failed to get clock\n");
++ return PTR_ERR(xrx200_hw.clk);
++ }
++
++ /* bring up the dma engine and IP core */
++ spin_lock_init(&xrx200_hw.lock);
++ xrx200_dma_init(&xrx200_hw);
++ xrx200_hw_init(&xrx200_hw);
++
++ /* bring up the mdio bus */
++ mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL,
++ "lantiq,xrx200-mdio");
++ if (mdio_np)
++ if (xrx200_of_mdio(&xrx200_hw, mdio_np))
++ dev_err(&pdev->dev, "mdio probe failed\n");
++
++ /* load the interfaces */
++ for_each_child_of_node(pdev->dev.of_node, iface_np)
++ if (of_device_is_compatible(iface_np, "lantiq,xrx200-pdi")) {
++ if (xrx200_hw.num_devs < XRX200_MAX_DEV)
++ xrx200_of_iface(&xrx200_hw, iface_np);
++ else
++ dev_err(&pdev->dev,
++ "only %d interfaces allowed\n",
++ XRX200_MAX_DEV);
++ }
++
++ if (!xrx200_hw.num_devs) {
++ xrx200_hw_cleanup(&xrx200_hw);
++ dev_err(&pdev->dev, "failed to load interfaces\n");
++ return -ENOENT;
++ }
++
++ /* set wan port mask */
++ ltq_pmac_w32(xrx200_hw.wan_map, PMAC_EWAN);
++
++ for (i = 0; i < xrx200_hw.num_devs; i++) {
++ xrx200_hw.chan[XRX200_DMA_RX].devs[i] = xrx200_hw.devs[i];
++ xrx200_hw.chan[XRX200_DMA_TX].devs[i] = xrx200_hw.devs[i];
++ }
++
++ /* setup NAPI */
++ init_dummy_netdev(&xrx200_hw.chan[XRX200_DMA_RX].dummy_dev);
++ init_dummy_netdev(&xrx200_hw.chan[XRX200_DMA_TX].dummy_dev);
++ netif_napi_add(&xrx200_hw.chan[XRX200_DMA_RX].dummy_dev,
++ &xrx200_hw.chan[XRX200_DMA_RX].napi, xrx200_poll_rx, 32);
++ netif_napi_add(&xrx200_hw.chan[XRX200_DMA_TX].dummy_dev,
++ &xrx200_hw.chan[XRX200_DMA_TX].napi, xrx200_poll_tx, 8);
++
++ platform_set_drvdata(pdev, &xrx200_hw);
++
++ return 0;
++}
++
++static int __devexit xrx200_remove(struct platform_device *pdev)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++ struct xrx200_priv *priv;
++
++ if (!dev)
++ return 0;
++
++ priv = netdev_priv(dev);
++
++ /* free stack related instances */
++ netif_stop_queue(dev);
++ netif_napi_del(&xrx200_hw.chan[XRX200_DMA_RX].napi);
++ netif_napi_del(&xrx200_hw.chan[XRX200_DMA_TX].napi);
++
++ /* shut down hardware */
++ xrx200_hw_cleanup(&xrx200_hw);
++
++ /* remove the actual device */
++ unregister_netdev(dev);
++ free_netdev(dev);
++
++ return 0;
++}
++
++static const struct of_device_id xrx200_match[] = {
++ { .compatible = "lantiq,xrx200-net" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, xrx200_match);
++
++static struct platform_driver xrx200_driver = {
++ .probe = xrx200_probe,
++ .remove = __devexit_p(xrx200_remove),
++ .driver = {
++ .name = "lantiq,xrx200-net",
++ .of_match_table = xrx200_match,
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(xrx200_driver);
++
++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
++MODULE_DESCRIPTION("Lantiq SoC XRX200 ethernet");
++MODULE_LICENSE("GPL");
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0118-owrt-adds-PHY11G-firmware-blobs.patch b/target/linux/lantiq/patches-3.7/0118-owrt-adds-PHY11G-firmware-blobs.patch
new file mode 100644
index 0000000000..32e583b327
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0118-owrt-adds-PHY11G-firmware-blobs.patch
@@ -0,0 +1,2221 @@
+From 870dad40d334e9e8342f28dbcad1410cad12a945 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 22 Oct 2012 09:26:24 +0200
+Subject: [PATCH 118/123] owrt: adds PHY11G firmware blobs
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ firmware/Makefile | 1 +
+ firmware/lantiq/COPYING | 286 ++++++++++++++++++++++++++++++++++++
+ firmware/lantiq/README | 45 ++++++
+ firmware/lantiq/vr9_phy11g_a1x.bin | Bin 0 -> 65536 bytes
+ firmware/lantiq/vr9_phy11g_a2x.bin | Bin 0 -> 65536 bytes
+ firmware/lantiq/vr9_phy22f_a1x.bin | Bin 0 -> 65536 bytes
+ firmware/lantiq/vr9_phy22f_a2x.bin | Bin 0 -> 65536 bytes
+ 7 files changed, 332 insertions(+)
+ create mode 100644 firmware/lantiq/COPYING
+ create mode 100644 firmware/lantiq/README
+ create mode 100644 firmware/lantiq/vr9_phy11g_a1x.bin
+ create mode 100644 firmware/lantiq/vr9_phy11g_a2x.bin
+ create mode 100644 firmware/lantiq/vr9_phy22f_a1x.bin
+ create mode 100644 firmware/lantiq/vr9_phy22f_a2x.bin
+
+diff --git a/firmware/Makefile b/firmware/Makefile
+index eeb1403..4259bed 100644
+--- a/firmware/Makefile
++++ b/firmware/Makefile
+@@ -135,6 +135,7 @@ fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda/keyspan_pda.fw
+ fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw
+ fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw
+ fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
++fw-shipped-$(CONFIG_SOC_TYPE_XWAY) += lantiq/vr9_phy11g_a2x.bin
+ fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
+
+ fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
+diff --git a/firmware/lantiq/COPYING b/firmware/lantiq/COPYING
+new file mode 100644
+index 0000000..5ec70b2
+--- /dev/null
++++ b/firmware/lantiq/COPYING
+@@ -0,0 +1,286 @@
++All firmware files are copyrighted by Lantiq Deutschland GmbH.
++The files have been extracted from header files found in Lantiq BSPs.
++If not stated otherwise all files are licensed under GPL.
++
++=======================================================================
++
++ GNU GENERAL PUBLIC LICENSE
++ Version 2, June 1991
++
++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
++ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ Everyone is permitted to copy and distribute verbatim copies
++ of this license document, but changing it is not allowed.
++
++ Preamble
++
++ The licenses for most software are designed to take away your
++freedom to share and change it. By contrast, the GNU General Public
++License is intended to guarantee your freedom to share and change free
++software--to make sure the software is free for all its users. This
++General Public License applies to most of the Free Software
++Foundation's software and to any other program whose authors commit to
++using it. (Some other Free Software Foundation software is covered by
++the GNU Library General Public License instead.) You can apply it to
++your programs, too.
++
++ When we speak of free software, we are referring to freedom, not
++price. Our General Public Licenses are designed to make sure that you
++have the freedom to distribute copies of free software (and charge for
++this service if you wish), that you receive source code or can get it
++if you want it, that you can change the software or use pieces of it
++in new free programs; and that you know you can do these things.
++
++ To protect your rights, we need to make restrictions that forbid
++anyone to deny you these rights or to ask you to surrender the rights.
++These restrictions translate to certain responsibilities for you if you
++distribute copies of the software, or if you modify it.
++
++ For example, if you distribute copies of such a program, whether
++gratis or for a fee, you must give the recipients all the rights that
++you have. You must make sure that they, too, receive or can get the
++source code. And you must show them these terms so they know their
++rights.
++
++ We protect your rights with two steps: (1) copyright the software, and
++(2) offer you this license which gives you legal permission to copy,
++distribute and/or modify the software.
++
++ Also, for each author's protection and ours, we want to make certain
++that everyone understands that there is no warranty for this free
++software. If the software is modified by someone else and passed on, we
++want its recipients to know that what they have is not the original, so
++that any problems introduced by others will not reflect on the original
++authors' reputations.
++
++ Finally, any free program is threatened constantly by software
++patents. We wish to avoid the danger that redistributors of a free
++program will individually obtain patent licenses, in effect making the
++program proprietary. To prevent this, we have made it clear that any
++patent must be licensed for everyone's free use or not licensed at all.
++
++ The precise terms and conditions for copying, distribution and
++modification follow.
++
++ GNU GENERAL PUBLIC LICENSE
++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
++
++ 0. This License applies to any program or other work which contains
++a notice placed by the copyright holder saying it may be distributed
++under the terms of this General Public License. The "Program", below,
++refers to any such program or work, and a "work based on the Program"
++means either the Program or any derivative work under copyright law:
++that is to say, a work containing the Program or a portion of it,
++either verbatim or with modifications and/or translated into another
++language. (Hereinafter, translation is included without limitation in
++the term "modification".) Each licensee is addressed as "you".
++
++Activities other than copying, distribution and modification are not
++covered by this License; they are outside its scope. The act of
++running the Program is not restricted, and the output from the Program
++is covered only if its contents constitute a work based on the
++Program (independent of having been made by running the Program).
++Whether that is true depends on what the Program does.
++
++ 1. You may copy and distribute verbatim copies of the Program's
++source code as you receive it, in any medium, provided that you
++conspicuously and appropriately publish on each copy an appropriate
++copyright notice and disclaimer of warranty; keep intact all the
++notices that refer to this License and to the absence of any warranty;
++and give any other recipients of the Program a copy of this License
++along with the Program.
++
++You may charge a fee for the physical act of transferring a copy, and
++you may at your option offer warranty protection in exchange for a fee.
++
++ 2. You may modify your copy or copies of the Program or any portion
++of it, thus forming a work based on the Program, and copy and
++distribute such modifications or work under the terms of Section 1
++above, provided that you also meet all of these conditions:
++
++ a) You must cause the modified files to carry prominent notices
++ stating that you changed the files and the date of any change.
++
++ b) You must cause any work that you distribute or publish, that in
++ whole or in part contains or is derived from the Program or any
++ part thereof, to be licensed as a whole at no charge to all third
++ parties under the terms of this License.
++
++ c) If the modified program normally reads commands interactively
++ when run, you must cause it, when started running for such
++ interactive use in the most ordinary way, to print or display an
++ announcement including an appropriate copyright notice and a
++ notice that there is no warranty (or else, saying that you provide
++ a warranty) and that users may redistribute the program under
++ these conditions, and telling the user how to view a copy of this
++ License. (Exception: if the Program itself is interactive but
++ does not normally print such an announcement, your work based on
++ the Program is not required to print an announcement.)
++
++These requirements apply to the modified work as a whole. If
++identifiable sections of that work are not derived from the Program,
++and can be reasonably considered independent and separate works in
++themselves, then this License, and its terms, do not apply to those
++sections when you distribute them as separate works. But when you
++distribute the same sections as part of a whole which is a work based
++on the Program, the distribution of the whole must be on the terms of
++this License, whose permissions for other licensees extend to the
++entire whole, and thus to each and every part regardless of who wrote it.
++
++Thus, it is not the intent of this section to claim rights or contest
++your rights to work written entirely by you; rather, the intent is to
++exercise the right to control the distribution of derivative or
++collective works based on the Program.
++
++In addition, mere aggregation of another work not based on the Program
++with the Program (or with a work based on the Program) on a volume of
++a storage or distribution medium does not bring the other work under
++the scope of this License.
++
++ 3. You may copy and distribute the Program (or a work based on it,
++under Section 2) in object code or executable form under the terms of
++Sections 1 and 2 above provided that you also do one of the following:
++
++ a) Accompany it with the complete corresponding machine-readable
++ source code, which must be distributed under the terms of Sections
++ 1 and 2 above on a medium customarily used for software interchange; or,
++
++ b) Accompany it with a written offer, valid for at least three
++ years, to give any third party, for a charge no more than your
++ cost of physically performing source distribution, a complete
++ machine-readable copy of the corresponding source code, to be
++ distributed under the terms of Sections 1 and 2 above on a medium
++ customarily used for software interchange; or,
++
++ c) Accompany it with the information you received as to the offer
++ to distribute corresponding source code. (This alternative is
++ allowed only for noncommercial distribution and only if you
++ received the program in object code or executable form with such
++ an offer, in accord with Subsection b above.)
++
++The source code for a work means the preferred form of the work for
++making modifications to it. For an executable work, complete source
++code means all the source code for all modules it contains, plus any
++associated interface definition files, plus the scripts used to
++control compilation and installation of the executable. However, as a
++special exception, the source code distributed need not include
++anything that is normally distributed (in either source or binary
++form) with the major components (compiler, kernel, and so on) of the
++operating system on which the executable runs, unless that component
++itself accompanies the executable.
++
++If distribution of executable or object code is made by offering
++access to copy from a designated place, then offering equivalent
++access to copy the source code from the same place counts as
++distribution of the source code, even though third parties are not
++compelled to copy the source along with the object code.
++
++ 4. You may not copy, modify, sublicense, or distribute the Program
++except as expressly provided under this License. Any attempt
++otherwise to copy, modify, sublicense or distribute the Program is
++void, and will automatically terminate your rights under this License.
++However, parties who have received copies, or rights, from you under
++this License will not have their licenses terminated so long as such
++parties remain in full compliance.
++
++ 5. You are not required to accept this License, since you have not
++signed it. However, nothing else grants you permission to modify or
++distribute the Program or its derivative works. These actions are
++prohibited by law if you do not accept this License. Therefore, by
++modifying or distributing the Program (or any work based on the
++Program), you indicate your acceptance of this License to do so, and
++all its terms and conditions for copying, distributing or modifying
++the Program or works based on it.
++
++ 6. Each time you redistribute the Program (or any work based on the
++Program), the recipient automatically receives a license from the
++original licensor to copy, distribute or modify the Program subject to
++these terms and conditions. You may not impose any further
++restrictions on the recipients' exercise of the rights granted herein.
++You are not responsible for enforcing compliance by third parties to
++this License.
++
++ 7. If, as a consequence of a court judgment or allegation of patent
++infringement or for any other reason (not limited to patent issues),
++conditions are imposed on you (whether by court order, agreement or
++otherwise) that contradict the conditions of this License, they do not
++excuse you from the conditions of this License. If you cannot
++distribute so as to satisfy simultaneously your obligations under this
++License and any other pertinent obligations, then as a consequence you
++may not distribute the Program at all. For example, if a patent
++license would not permit royalty-free redistribution of the Program by
++all those who receive copies directly or indirectly through you, then
++the only way you could satisfy both it and this License would be to
++refrain entirely from distribution of the Program.
++
++If any portion of this section is held invalid or unenforceable under
++any particular circumstance, the balance of the section is intended to
++apply and the section as a whole is intended to apply in other
++circumstances.
++
++It is not the purpose of this section to induce you to infringe any
++patents or other property right claims or to contest validity of any
++such claims; this section has the sole purpose of protecting the
++integrity of the free software distribution system, which is
++implemented by public license practices. Many people have made
++generous contributions to the wide range of software distributed
++through that system in reliance on consistent application of that
++system; it is up to the author/donor to decide if he or she is willing
++to distribute software through any other system and a licensee cannot
++impose that choice.
++
++This section is intended to make thoroughly clear what is believed to
++be a consequence of the rest of this License.
++
++ 8. If the distribution and/or use of the Program is restricted in
++certain countries either by patents or by copyrighted interfaces, the
++original copyright holder who places the Program under this License
++may add an explicit geographical distribution limitation excluding
++those countries, so that distribution is permitted only in or among
++countries not thus excluded. In such case, this License incorporates
++the limitation as if written in the body of this License.
++
++ 9. The Free Software Foundation may publish revised and/or new versions
++of the General Public License from time to time. Such new versions will
++be similar in spirit to the present version, but may differ in detail to
++address new problems or concerns.
++
++Each version is given a distinguishing version number. If the Program
++specifies a version number of this License which applies to it and "any
++later version", you have the option of following the terms and conditions
++either of that version or of any later version published by the Free
++Software Foundation. If the Program does not specify a version number of
++this License, you may choose any version ever published by the Free Software
++Foundation.
++
++ 10. If you wish to incorporate parts of the Program into other free
++programs whose distribution conditions are different, write to the author
++to ask for permission. For software which is copyrighted by the Free
++Software Foundation, write to the Free Software Foundation; we sometimes
++make exceptions for this. Our decision will be guided by the two goals
++of preserving the free status of all derivatives of our free software and
++of promoting the sharing and reuse of software generally.
++
++ NO WARRANTY
++
++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
++REPAIR OR CORRECTION.
++
++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
++POSSIBILITY OF SUCH DAMAGES.
++
++ END OF TERMS AND CONDITIONS
+diff --git a/firmware/lantiq/README b/firmware/lantiq/README
+new file mode 100644
+index 0000000..cb1a10a
+--- /dev/null
++++ b/firmware/lantiq/README
+@@ -0,0 +1,45 @@
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++# MA 02111-1307 USA
++#
++# (C) Copyright 2007 - 2012
++# Lantiq Deutschland GmbH
++#
++# (C) Copyright 2012
++# Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
++#
++
++#
++# How to use
++#
++Configure kernel with:
++CONFIG_FW_LOADER=y
++CONFIG_EXTRA_FIRMWARE_DIR="FIRMWARE_DIR"
++CONFIG_EXTRA_FIRMWARE="FIRMWARE_FILES"
++
++where FIRMWARE_DIR should point to this git tree and FIRMWARE_FILES is a list
++of space separated files from list below.
++
++#
++# Firmware files
++#
++
++# GPHY core on Lantiq XWAY VR9 v1.1
++lantiq/vr9_phy11g_a1x.bin
++lantiq/vr9_phy22f_a1x.bin
++
++# GPHY core on Lantiq XWAY VR9 v1.1
++lantiq/vr9_phy11g_a2x.bin
++lantiq/vr9_phy22f_a2x.bin
+diff --git a/firmware/lantiq/vr9_phy11g_a1x.bin b/firmware/lantiq/vr9_phy11g_a1x.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..cdf3d3063405c1239d15bae873e11f4ad8644e0f
+GIT binary patch
+literal 65536
+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
+
+literal 0
+HcmV?d00001
+
+diff --git a/firmware/lantiq/vr9_phy11g_a2x.bin b/firmware/lantiq/vr9_phy11g_a2x.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..44fc39ef06458bd554034cbc9a90e7df2f132414
+GIT binary patch
+literal 65536
+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
+
+literal 0
+HcmV?d00001
+
+diff --git a/firmware/lantiq/vr9_phy22f_a1x.bin b/firmware/lantiq/vr9_phy22f_a1x.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..02b88a078b85fbf73a4e0540ada7d49ea6287cd3
+GIT binary patch
+literal 65536
+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
+TC6JatS^{Yaq$TiwrUd>s+;lNd
+
+literal 0
+HcmV?d00001
+
+diff --git a/firmware/lantiq/vr9_phy22f_a2x.bin b/firmware/lantiq/vr9_phy22f_a2x.bin
+new file mode 100644
+index 0000000000000000000000000000000000000000..1fed6ad65e2b6895f21e1ad81b1ef26b13edabff
+GIT binary patch
+literal 65536
+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
+
+literal 0
+HcmV?d00001
+
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0119-owrt-ATM-adds-lantiq-specific-hacks.patch b/target/linux/lantiq/patches-3.7/0119-owrt-ATM-adds-lantiq-specific-hacks.patch
new file mode 100644
index 0000000000..6dbbb21ec1
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0119-owrt-ATM-adds-lantiq-specific-hacks.patch
@@ -0,0 +1,508 @@
+From 8d2a7d1fb561c9cb098c2b13ded34fe0f49dcca5 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 3 Aug 2012 10:27:25 +0200
+Subject: [PATCH 20/25] owrt atm
+
+---
+ arch/mips/lantiq/irq.c | 2 ++
+ arch/mips/mm/cache.c | 2 ++
+ net/atm/common.c | 6 ++++++
+ net/atm/proc.c | 2 +-
+ 4 files changed, 11 insertions(+), 1 deletions(-)
+
+Index: linux-3.7-rc6/arch/mips/lantiq/irq.c
+===================================================================
+--- linux-3.7-rc6.orig/arch/mips/lantiq/irq.c 2012-12-06 21:02:42.000000000 +0100
++++ linux-3.7-rc6/arch/mips/lantiq/irq.c 2012-12-06 21:03:13.850060387 +0100
+@@ -14,6 +14,7 @@
+ #include <linux/of_platform.h>
+ #include <linux/of_address.h>
+ #include <linux/of_irq.h>
++#include <linux/module.h>
+
+ #include <asm/bootinfo.h>
+ #include <asm/irq_cpu.h>
+@@ -99,6 +100,7 @@
+ ltq_icu_w32(im, ltq_icu_r32(im, ier) & ~BIT(offset), ier);
+ ltq_icu_w32(im, BIT(offset), isr);
+ }
++EXPORT_SYMBOL(ltq_mask_and_ack_irq);
+
+ static void ltq_ack_irq(struct irq_data *d)
+ {
+Index: linux-3.7-rc6/arch/mips/mm/cache.c
+===================================================================
+--- linux-3.7-rc6.orig/arch/mips/mm/cache.c 2012-12-06 21:02:40.000000000 +0100
++++ linux-3.7-rc6/arch/mips/mm/cache.c 2012-12-06 21:03:13.850060387 +0100
+@@ -58,6 +58,8 @@
+ void (*_dma_cache_inv)(unsigned long start, unsigned long size);
+
+ EXPORT_SYMBOL(_dma_cache_wback_inv);
++EXPORT_SYMBOL(_dma_cache_wback);
++EXPORT_SYMBOL(_dma_cache_inv);
+
+ #endif /* CONFIG_DMA_NONCOHERENT */
+
+Index: linux-3.7-rc6/net/atm/common.c
+===================================================================
+--- linux-3.7-rc6.orig/net/atm/common.c 2012-11-17 02:42:40.000000000 +0100
++++ linux-3.7-rc6/net/atm/common.c 2012-12-06 21:03:13.850060387 +0100
+@@ -62,11 +62,17 @@
+ write_unlock_irq(&vcc_sklist_lock);
+ }
+
++struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int) = NULL;
++EXPORT_SYMBOL(ifx_atm_alloc_tx);
++
+ static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
+ {
+ struct sk_buff *skb;
+ struct sock *sk = sk_atm(vcc);
+
++ if (ifx_atm_alloc_tx != NULL)
++ return ifx_atm_alloc_tx(vcc, size);
++
+ if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
+ pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
+ sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);
+Index: linux-3.7-rc6/net/atm/proc.c
+===================================================================
+--- linux-3.7-rc6.orig/net/atm/proc.c 2012-11-17 02:42:40.000000000 +0100
++++ linux-3.7-rc6/net/atm/proc.c 2012-12-06 21:03:13.850060387 +0100
+@@ -154,7 +154,7 @@
+ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
+ {
+ static const char *const class_name[] = {
+- "off", "UBR", "CBR", "VBR", "ABR"};
++ "off","UBR","CBR","NTR-VBR","ABR","ANY","RT-VBR","UBR+","GFR"};
+ static const char *const aal_name[] = {
+ "---", "1", "2", "3/4", /* 0- 3 */
+ "???", "5", "???", "???", /* 4- 7 */
+Index: linux-3.7-rc6/arch/mips/include/asm/mach-lantiq/lantiq_atm.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.7-rc6/arch/mips/include/asm/mach-lantiq/lantiq_atm.h 2012-12-06 21:03:13.850060387 +0100
+@@ -0,0 +1,196 @@
++/******************************************************************************
++**
++** FILE NAME : ifx_atm.h
++** PROJECT : UEIP
++** MODULES : ATM
++**
++** DATE : 17 Jun 2009
++** AUTHOR : Xu Liang
++** DESCRIPTION : Global ATM driver header file
++** COPYRIGHT : Copyright (c) 2006
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** HISTORY
++** $Date $Author $Comment
++** 07 JUL 2009 Xu Liang Init Version
++*******************************************************************************/
++
++#ifndef IFX_ATM_H
++#define IFX_ATM_H
++
++
++
++/*!
++ \defgroup IFX_ATM UEIP Project - ATM driver module
++ \brief UEIP Project - ATM driver module, support Danube, Amazon-SE, AR9, VR9.
++ */
++
++/*!
++ \defgroup IFX_ATM_IOCTL IOCTL Commands
++ \ingroup IFX_ATM
++ \brief IOCTL Commands used by user application.
++ */
++
++/*!
++ \defgroup IFX_ATM_STRUCT Structures
++ \ingroup IFX_ATM
++ \brief Structures used by user application.
++ */
++
++/*!
++ \file ifx_atm.h
++ \ingroup IFX_ATM
++ \brief ATM driver header file
++ */
++
++
++
++/*
++ * ####################################
++ * Definition
++ * ####################################
++ */
++
++/*!
++ \addtogroup IFX_ATM_STRUCT
++ */
++/*@{*/
++
++/*
++ * ATM MIB
++ */
++
++/*!
++ \struct atm_cell_ifEntry_t
++ \brief Structure used for Cell Level MIB Counters.
++
++ User application use this structure to call IOCTL command "PPE_ATM_MIB_CELL".
++ */
++typedef struct {
++ __u32 ifHCInOctets_h; /*!< byte counter of ingress cells (upper 32 bits, total 64 bits) */
++ __u32 ifHCInOctets_l; /*!< byte counter of ingress cells (lower 32 bits, total 64 bits) */
++ __u32 ifHCOutOctets_h; /*!< byte counter of egress cells (upper 32 bits, total 64 bits) */
++ __u32 ifHCOutOctets_l; /*!< byte counter of egress cells (lower 32 bits, total 64 bits) */
++ __u32 ifInErrors; /*!< counter of error ingress cells */
++ __u32 ifInUnknownProtos; /*!< counter of unknown ingress cells */
++ __u32 ifOutErrors; /*!< counter of error egress cells */
++} atm_cell_ifEntry_t;
++
++/*!
++ \struct atm_aal5_ifEntry_t
++ \brief Structure used for AAL5 Frame Level MIB Counters.
++
++ User application use this structure to call IOCTL command "PPE_ATM_MIB_AAL5".
++ */
++typedef struct {
++ __u32 ifHCInOctets_h; /*!< byte counter of ingress packets (upper 32 bits, total 64 bits) */
++ __u32 ifHCInOctets_l; /*!< byte counter of ingress packets (lower 32 bits, total 64 bits) */
++ __u32 ifHCOutOctets_h; /*!< byte counter of egress packets (upper 32 bits, total 64 bits) */
++ __u32 ifHCOutOctets_l; /*!< byte counter of egress packets (lower 32 bits, total 64 bits) */
++ __u32 ifInUcastPkts; /*!< counter of ingress packets */
++ __u32 ifOutUcastPkts; /*!< counter of egress packets */
++ __u32 ifInErrors; /*!< counter of error ingress packets */
++ __u32 ifInDiscards; /*!< counter of dropped ingress packets */
++ __u32 ifOutErros; /*!< counter of error egress packets */
++ __u32 ifOutDiscards; /*!< counter of dropped egress packets */
++} atm_aal5_ifEntry_t;
++
++/*!
++ \struct atm_aal5_vcc_t
++ \brief Structure used for per PVC AAL5 Frame Level MIB Counters.
++
++ This structure is a part of structure "atm_aal5_vcc_x_t".
++ */
++typedef struct {
++ __u32 aal5VccCrcErrors; /*!< counter of ingress packets with CRC error */
++ __u32 aal5VccSarTimeOuts; /*!< counter of ingress packets with Re-assemble timeout */ //no timer support yet
++ __u32 aal5VccOverSizedSDUs; /*!< counter of oversized ingress packets */
++} atm_aal5_vcc_t;
++
++/*!
++ \struct atm_aal5_vcc_x_t
++ \brief Structure used for per PVC AAL5 Frame Level MIB Counters.
++
++ User application use this structure to call IOCTL command "PPE_ATM_MIB_VCC".
++ */
++typedef struct {
++ int vpi; /*!< VPI of the VCC to get MIB counters */
++ int vci; /*!< VCI of the VCC to get MIB counters */
++ atm_aal5_vcc_t mib_vcc; /*!< structure to get MIB counters */
++} atm_aal5_vcc_x_t;
++
++/*@}*/
++
++
++
++/*
++ * ####################################
++ * IOCTL
++ * ####################################
++ */
++
++/*!
++ \addtogroup IFX_ATM_IOCTL
++ */
++/*@{*/
++
++/*
++ * ioctl Command
++ */
++/*!
++ \brief ATM IOCTL Magic Number
++ */
++#define PPE_ATM_IOC_MAGIC 'o'
++/*!
++ \brief ATM IOCTL Command - Get Cell Level MIB Counters
++
++ This command is obsolete. User can get cell level MIB from DSL API.
++ This command uses structure "atm_cell_ifEntry_t" as parameter for output of MIB counters.
++ */
++#define PPE_ATM_MIB_CELL _IOW(PPE_ATM_IOC_MAGIC, 0, atm_cell_ifEntry_t)
++/*!
++ \brief ATM IOCTL Command - Get AAL5 Level MIB Counters
++
++ Get AAL5 packet counters.
++ This command uses structure "atm_aal5_ifEntry_t" as parameter for output of MIB counters.
++ */
++#define PPE_ATM_MIB_AAL5 _IOW(PPE_ATM_IOC_MAGIC, 1, atm_aal5_ifEntry_t)
++/*!
++ \brief ATM IOCTL Command - Get Per PVC MIB Counters
++
++ Get AAL5 packet counters for each PVC.
++ This command uses structure "atm_aal5_vcc_x_t" as parameter for input of VPI/VCI information and output of MIB counters.
++ */
++#define PPE_ATM_MIB_VCC _IOWR(PPE_ATM_IOC_MAGIC, 2, atm_aal5_vcc_x_t)
++/*!
++ \brief Total Number of ATM IOCTL Commands
++ */
++#define PPE_ATM_IOC_MAXNR 3
++
++/*@}*/
++
++
++
++/*
++ * ####################################
++ * API
++ * ####################################
++ */
++
++#ifdef __KERNEL__
++struct port_cell_info {
++ unsigned int port_num;
++ unsigned int tx_link_rate[2];
++};
++#endif
++
++
++
++#endif // IFX_ATM_H
++
+Index: linux-3.7-rc6/arch/mips/include/asm/mach-lantiq/lantiq_ptm.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.7-rc6/arch/mips/include/asm/mach-lantiq/lantiq_ptm.h 2012-12-06 21:03:13.854060387 +0100
+@@ -0,0 +1,203 @@
++/******************************************************************************
++**
++** FILE NAME : ifx_ptm.h
++** PROJECT : UEIP
++** MODULES : PTM
++**
++** DATE : 17 Jun 2009
++** AUTHOR : Xu Liang
++** DESCRIPTION : Global PTM driver header file
++** COPYRIGHT : Copyright (c) 2006
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** HISTORY
++** $Date $Author $Comment
++** 07 JUL 2009 Xu Liang Init Version
++*******************************************************************************/
++
++#ifndef IFX_PTM_H
++#define IFX_PTM_H
++
++
++
++/*!
++ \defgroup IFX_PTM UEIP Project - PTM driver module
++ \brief UEIP Project - PTM driver module, support Danube, Amazon-SE, AR9, VR9.
++ */
++
++/*!
++ \defgroup IFX_PTM_IOCTL IOCTL Commands
++ \ingroup IFX_PTM
++ \brief IOCTL Commands used by user application.
++ */
++
++/*!
++ \defgroup IFX_PTM_STRUCT Structures
++ \ingroup IFX_PTM
++ \brief Structures used by user application.
++ */
++
++/*!
++ \file ifx_ptm.h
++ \ingroup IFX_PTM
++ \brief PTM driver header file
++ */
++
++
++
++/*
++ * ####################################
++ * Definition
++ * ####################################
++ */
++
++
++
++/*
++ * ####################################
++ * IOCTL
++ * ####################################
++ */
++
++/*!
++ \addtogroup IFX_PTM_IOCTL
++ */
++/*@{*/
++
++/*
++ * ioctl Command
++ */
++/*!
++ \brief PTM IOCTL Command - Get codeword MIB counters.
++
++ This command uses structure "PTM_CW_IF_ENTRY_T" to get codeword level MIB counters.
++ */
++#define IFX_PTM_MIB_CW_GET SIOCDEVPRIVATE + 1
++/*!
++ \brief PTM IOCTL Command - Get packet MIB counters.
++
++ This command uses structure "PTM_FRAME_MIB_T" to get packet level MIB counters.
++ */
++#define IFX_PTM_MIB_FRAME_GET SIOCDEVPRIVATE + 2
++/*!
++ \brief PTM IOCTL Command - Get firmware configuration (CRC).
++
++ This command uses structure "IFX_PTM_CFG_T" to get firmware configuration (CRC).
++ */
++#define IFX_PTM_CFG_GET SIOCDEVPRIVATE + 3
++/*!
++ \brief PTM IOCTL Command - Set firmware configuration (CRC).
++
++ This command uses structure "IFX_PTM_CFG_T" to set firmware configuration (CRC).
++ */
++#define IFX_PTM_CFG_SET SIOCDEVPRIVATE + 4
++/*!
++ \brief PTM IOCTL Command - Program priority value to TX queue mapping.
++
++ This command uses structure "IFX_PTM_PRIO_Q_MAP_T" to program priority value to TX queue mapping.
++ */
++#define IFX_PTM_MAP_PKT_PRIO_TO_Q SIOCDEVPRIVATE + 14
++
++/*@}*/
++
++
++/*!
++ \addtogroup IFX_PTM_STRUCT
++ */
++/*@{*/
++
++/*
++ * ioctl Data Type
++ */
++
++/*!
++ \typedef PTM_CW_IF_ENTRY_T
++ \brief Wrapping of structure "ptm_cw_ifEntry_t".
++ */
++/*!
++ \struct ptm_cw_ifEntry_t
++ \brief Structure used for CodeWord level MIB counters.
++ */
++typedef struct ptm_cw_ifEntry_t {
++ uint32_t ifRxNoIdleCodewords; /*!< output, number of ingress user codeword */
++ uint32_t ifRxIdleCodewords; /*!< output, number of ingress idle codeword */
++ uint32_t ifRxCodingViolation; /*!< output, number of error ingress codeword */
++ uint32_t ifTxNoIdleCodewords; /*!< output, number of egress user codeword */
++ uint32_t ifTxIdleCodewords; /*!< output, number of egress idle codeword */
++} PTM_CW_IF_ENTRY_T;
++
++/*!
++ \typedef PTM_FRAME_MIB_T
++ \brief Wrapping of structure "ptm_frame_mib_t".
++ */
++/*!
++ \struct ptm_frame_mib_t
++ \brief Structure used for packet level MIB counters.
++ */
++typedef struct ptm_frame_mib_t {
++ uint32_t RxCorrect; /*!< output, number of ingress packet */
++ uint32_t TC_CrcError; /*!< output, number of egress packet with CRC error */
++ uint32_t RxDropped; /*!< output, number of dropped ingress packet */
++ uint32_t TxSend; /*!< output, number of egress packet */
++} PTM_FRAME_MIB_T;
++
++/*!
++ \typedef IFX_PTM_CFG_T
++ \brief Wrapping of structure "ptm_cfg_t".
++ */
++/*!
++ \struct ptm_cfg_t
++ \brief Structure used for ETH/TC CRC configuration.
++ */
++typedef struct ptm_cfg_t {
++ uint32_t RxEthCrcPresent; /*!< input/output, ingress packet has ETH CRC */
++ uint32_t RxEthCrcCheck; /*!< input/output, check ETH CRC of ingress packet */
++ uint32_t RxTcCrcCheck; /*!< input/output, check TC CRC of ingress codeword */
++ uint32_t RxTcCrcLen; /*!< input/output, length of TC CRC of ingress codeword */
++ uint32_t TxEthCrcGen; /*!< input/output, generate ETH CRC for egress packet */
++ uint32_t TxTcCrcGen; /*!< input/output, generate TC CRC for egress codeword */
++ uint32_t TxTcCrcLen; /*!< input/output, length of TC CRC of egress codeword */
++} IFX_PTM_CFG_T;
++
++/*!
++ \typedef IFX_PTM_PRIO_Q_MAP_T
++ \brief Wrapping of structure "ppe_prio_q_map".
++ */
++/*!
++ \struct ppe_prio_q_map
++ \brief Structure used for Priority Value to TX Queue mapping.
++ */
++typedef struct ppe_prio_q_map {
++ int pkt_prio;
++ int qid;
++ int vpi; // ignored in eth interface
++ int vci; // ignored in eth interface
++} IFX_PTM_PRIO_Q_MAP_T;
++
++/*@}*/
++
++
++
++/*
++ * ####################################
++ * API
++ * ####################################
++ */
++
++#ifdef __KERNEL__
++struct port_cell_info {
++ unsigned int port_num;
++ unsigned int tx_link_rate[2];
++};
++#endif
++
++
++
++#endif // IFX_PTM_H
++
+Index: linux-3.7-rc6/include/uapi/linux/atm.h
+===================================================================
+--- linux-3.7-rc6.orig/include/uapi/linux/atm.h 2012-12-06 21:02:41.458059575 +0100
++++ linux-3.7-rc6/include/uapi/linux/atm.h 2012-12-06 21:04:21.282062078 +0100
+@@ -130,8 +130,14 @@
+ #define ATM_ABR 4
+ #define ATM_ANYCLASS 5 /* compatible with everything */
+
++#define ATM_VBR_NRT ATM_VBR
++#define ATM_VBR_RT 6
++#define ATM_UBR_PLUS 7
++#define ATM_GFR 8
++
+ #define ATM_MAX_PCR -1 /* maximum available PCR */
+
++
+ struct atm_trafprm {
+ unsigned char traffic_class; /* traffic class (ATM_UBR, ...) */
+ int max_pcr; /* maximum PCR in cells per second */
diff --git a/target/linux/lantiq/patches-3.7/0120-owrt-generic-dtb-image-hack.patch b/target/linux/lantiq/patches-3.7/0120-owrt-generic-dtb-image-hack.patch
new file mode 100644
index 0000000000..aed0009136
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0120-owrt-generic-dtb-image-hack.patch
@@ -0,0 +1,26 @@
+From ac676d9516d9d14b98eef3dec05badae1d1a331a Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 2 Nov 2012 15:40:08 +0100
+Subject: [PATCH 120/123] owrt: generic dtb image hack
+
+---
+ arch/mips/kernel/head.S | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
+index ea695d9..be87456 100644
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -141,6 +141,9 @@ FEXPORT(__kernel_entry)
+ j kernel_entry
+ #endif
+
++ .ascii "OWRTDTB:"
++ EXPORT(__image_dtb)
++ .fill 0x4000
+ __REF
+
+ NESTED(kernel_entry, 16, sp) # kernel entry point
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0121-owrt-lantiq-dtb-image-hack.patch b/target/linux/lantiq/patches-3.7/0121-owrt-lantiq-dtb-image-hack.patch
new file mode 100644
index 0000000000..eef7da47b4
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0121-owrt-lantiq-dtb-image-hack.patch
@@ -0,0 +1,44 @@
+From d8f83a608bc854dbbe6b2ea5436e9b34516af8e4 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 6 Dec 2012 16:09:08 +0100
+Subject: [PATCH 121/123] owrt: lantiq dtb image hack
+
+---
+ arch/mips/lantiq/prom.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+Index: linux-3.7-rc8/arch/mips/lantiq/prom.c
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/lantiq/prom.c 2012-12-14 23:08:36.451576994 +0100
++++ linux-3.7-rc8/arch/mips/lantiq/prom.c 2012-12-14 23:08:36.607576999 +0100
+@@ -72,6 +72,8 @@
+ return 0;
+ }
+
++extern struct boot_param_header __image_dtb;
++
+ void __init plat_mem_setup(void)
+ {
+ ioport_resource.start = IOPORT_RESOURCE_START;
+@@ -85,7 +87,7 @@
+ * Load the builtin devicetree. This causes the chosen node to be
+ * parsed resulting in our memory appearing
+ */
+- __dt_setup_arch(&__dtb_start);
++ __dt_setup_arch(&__image_dtb);
+
+ of_scan_flat_dt(early_init_dt_scan_model, NULL);
+ }
+Index: linux-3.7-rc8/arch/mips/lantiq/Makefile
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/lantiq/Makefile 2012-12-14 23:08:36.459576996 +0100
++++ linux-3.7-rc8/arch/mips/lantiq/Makefile 2012-12-15 01:40:16.519805129 +0100
+@@ -6,8 +6,6 @@
+
+ obj-y := irq.o clk.o prom.o
+
+-obj-y += dts/
+-
+ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+ obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
diff --git a/target/linux/lantiq/patches-3.7/0122-MIPS-lantiq-adds-pcie-driver.patch b/target/linux/lantiq/patches-3.7/0122-MIPS-lantiq-adds-pcie-driver.patch
new file mode 100644
index 0000000000..9319858f5e
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0122-MIPS-lantiq-adds-pcie-driver.patch
@@ -0,0 +1,4786 @@
+From b0b68cd5b5da72950863af882c368f28f65690e8 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 6 Dec 2012 11:43:53 +0100
+Subject: [PATCH 122/123] MIPS: lantiq: adds pcie driver
+
+---
+ arch/mips/lantiq/Kconfig | 10 +
+ arch/mips/lantiq/xway/sysctrl.c | 2 +
+ arch/mips/pci/Makefile | 2 +
+ arch/mips/pci/fixup-lantiq-pcie.c | 82 ++
+ arch/mips/pci/fixup-lantiq.c | 3 +
+ arch/mips/pci/ifxmips_pci_common.h | 57 ++
+ arch/mips/pci/ifxmips_pcie.c | 1607 ++++++++++++++++++++++++++++++++++++
+ arch/mips/pci/ifxmips_pcie.h | 135 +++
+ arch/mips/pci/ifxmips_pcie_ar10.h | 290 +++++++
+ arch/mips/pci/ifxmips_pcie_msi.c | 392 +++++++++
+ arch/mips/pci/ifxmips_pcie_phy.c | 478 +++++++++++
+ arch/mips/pci/ifxmips_pcie_pm.c | 176 ++++
+ arch/mips/pci/ifxmips_pcie_pm.h | 36 +
+ arch/mips/pci/ifxmips_pcie_reg.h | 1001 ++++++++++++++++++++++
+ arch/mips/pci/ifxmips_pcie_vr9.h | 271 ++++++
+ arch/mips/pci/pci.c | 25 +
+ drivers/pci/pcie/aer/Kconfig | 2 +-
+ include/linux/pci.h | 2 +
+ include/linux/pci_ids.h | 6 +
+ 19 files changed, 4576 insertions(+), 1 deletion(-)
+ create mode 100644 arch/mips/pci/fixup-lantiq-pcie.c
+ create mode 100755 arch/mips/pci/ifxmips_pci_common.h
+ create mode 100644 arch/mips/pci/ifxmips_pcie.c
+ create mode 100644 arch/mips/pci/ifxmips_pcie.h
+ create mode 100644 arch/mips/pci/ifxmips_pcie_ar10.h
+ create mode 100644 arch/mips/pci/ifxmips_pcie_msi.c
+ create mode 100644 arch/mips/pci/ifxmips_pcie_phy.c
+ create mode 100644 arch/mips/pci/ifxmips_pcie_pm.c
+ create mode 100644 arch/mips/pci/ifxmips_pcie_pm.h
+ create mode 100644 arch/mips/pci/ifxmips_pcie_reg.h
+ create mode 100644 arch/mips/pci/ifxmips_pcie_vr9.h
+
+diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
+index edeb58c..116765a 100644
+--- a/arch/mips/lantiq/Kconfig
++++ b/arch/mips/lantiq/Kconfig
+@@ -17,6 +17,7 @@ config SOC_XWAY
+ bool "XWAY"
+ select SOC_TYPE_XWAY
+ select HW_HAS_PCI
++ select ARCH_SUPPORTS_MSI
+
+ config SOC_FALCON
+ bool "FALCON"
+@@ -40,6 +41,15 @@ config PCI_LANTIQ
+ bool "PCI Support"
+ depends on SOC_XWAY && PCI
+
++config PCIE_LANTIQ
++ bool "PCIE Support"
++ depends on SOC_XWAY && PCI
++
++config PCIE_LANTIQ_MSI
++ bool
++ depends on PCIE_LANTIQ && PCI_MSI
++ default y
++
+ config XRX200_PHY_FW
+ bool "XRX200 PHY firmware loader"
+ depends on SOC_XWAY
+diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
+index 75e1b7d..b077d49 100644
+--- a/arch/mips/lantiq/xway/sysctrl.c
++++ b/arch/mips/lantiq/xway/sysctrl.c
+@@ -377,6 +377,8 @@ void __init ltq_soc_init(void)
+ PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
+ PMU_PPE_QSB | PMU_PPE_TOP);
+ clkdev_add_pmu("1f203000.rcu", "gphy", 0, PMU_GPHY);
++ pmu_w32(~0, PMU_PWDSR1);
++ pmu_w32(pmu_r32(PMU_PWDSR) & ~PMU_PCIE_CLK, PMU_PWDSR);
+ } else if (of_machine_is_compatible("lantiq,ar9")) {
+ clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
+ ltq_ar9_fpi_hz(), CLOCK_250M);
+diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
+index e13a71c..46d7096 100644
+--- a/arch/mips/pci/Makefile
++++ b/arch/mips/pci/Makefile
+@@ -44,6 +44,8 @@ obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o
+ 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_PCIE_LANTIQ) += ifxmips_pcie_phy.o ifxmips_pcie.o fixup-lantiq-pcie.o
++obj-$(CONFIG_PCIE_LANTIQ_MSI) += pcie-lantiq-msi.o
+ obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
+ obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
+ obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
+diff --git a/arch/mips/pci/fixup-lantiq-pcie.c b/arch/mips/pci/fixup-lantiq-pcie.c
+new file mode 100644
+index 0000000..50a1c3b
+--- /dev/null
++++ b/arch/mips/pci/fixup-lantiq-pcie.c
+@@ -0,0 +1,82 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_fixup_pcie.c
++** PROJECT : IFX UEIP for VRX200
++** MODULES : PCIe
++**
++** DATE : 02 Mar 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIe Root Complex Driver
++** COPYRIGHT : Copyright (c) 2009
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++** HISTORY
++** $Version $Date $Author $Comment
++** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version
++*******************************************************************************/
++/*!
++ \file ifxmips_fixup_pcie.c
++ \ingroup IFX_PCIE
++ \brief PCIe Fixup functions source file
++*/
++#include <linux/pci.h>
++#include <linux/pci_regs.h>
++#include <linux/pci_ids.h>
++
++#include <lantiq_soc.h>
++
++#include "pcie-lantiq.h"
++
++#define PCI_VENDOR_ID_INFINEON 0x15D1
++#define PCI_DEVICE_ID_INFINEON_DANUBE 0x000F
++#define PCI_DEVICE_ID_INFINEON_PCIE 0x0011
++#define PCI_VENDOR_ID_LANTIQ 0x1BEF
++#define PCI_DEVICE_ID_LANTIQ_PCIE 0x0011
++
++
++
++static void __devinit
++ifx_pcie_fixup_resource(struct pci_dev *dev)
++{
++ u32 reg;
++
++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev));
++
++ printk("%s: fixup host controller %s (%04x:%04x)\n",
++ __func__, pci_name(dev), dev->vendor, dev->device);
++
++ /* Setup COMMAND register */
++ reg = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER /* |
++ PCI_COMMAND_INTX_DISABLE */| PCI_COMMAND_SERR;
++ pci_write_config_word(dev, PCI_COMMAND, reg);
++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev));
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE, ifx_pcie_fixup_resource);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_VENDOR_ID_LANTIQ, ifx_pcie_fixup_resource);
++
++static void __devinit
++ifx_pcie_rc_class_early_fixup(struct pci_dev *dev)
++{
++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: enter\n", __func__, pci_name(dev));
++
++ if (dev->devfn == PCI_DEVFN(0, 0) &&
++ (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) {
++
++ dev->class = (PCI_CLASS_BRIDGE_PCI << 8) | (dev->class & 0xff);
++
++ printk(KERN_INFO "%s: fixed pcie host bridge to pci-pci bridge\n", __func__);
++ }
++ IFX_PCIE_PRINT(PCIE_MSG_FIXUP, "%s dev %s: exit\n", __func__, pci_name(dev));
++ mdelay(10);
++}
++
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INFINEON, PCI_DEVICE_ID_INFINEON_PCIE,
++ ifx_pcie_rc_class_early_fixup);
++
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LANTIQ, PCI_DEVICE_ID_LANTIQ_PCIE,
++ ifx_pcie_rc_class_early_fixup);
+diff --git a/arch/mips/pci/fixup-lantiq.c b/arch/mips/pci/fixup-lantiq.c
+index 6c829df..cf5c4e0 100644
+--- a/arch/mips/pci/fixup-lantiq.c
++++ b/arch/mips/pci/fixup-lantiq.c
+@@ -11,6 +11,7 @@
+
+ int (*ltq_pci_plat_arch_init)(struct pci_dev *dev) = NULL;
+ int (*ltq_pci_plat_dev_init)(struct pci_dev *dev) = NULL;
++int (*ltq_pci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
+
+ int pcibios_plat_dev_init(struct pci_dev *dev)
+ {
+@@ -28,6 +29,8 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+ struct of_irq dev_irq;
+ int irq;
+
++ if (ltq_pci_map_irq)
++ return ltq_pci_map_irq(dev, slot, pin);
+ if (of_irq_map_pci(dev, &dev_irq)) {
+ dev_err(&dev->dev, "trying to map irq for unknown slot:%d pin:%d\n",
+ slot, pin);
+diff --git a/arch/mips/pci/ifxmips_pci_common.h b/arch/mips/pci/ifxmips_pci_common.h
+new file mode 100755
+index 0000000..5f6ab83
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pci_common.h
+@@ -0,0 +1,57 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_pci_common.h
++** PROJECT : IFX UEIP
++** MODULES : PCI subsystem
++**
++** DATE : 30 June 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIe Root Complex Driver
++** COPYRIGHT : Copyright (c) 2009
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++** HISTORY
++** $Version $Date $Author $Comment
++** 0.0.1 30 June,2009 Lei Chuanhua Initial version
++*******************************************************************************/
++
++#ifndef IFXMIPS_PCI_COMMON_H
++#define IFXMIPS_PCI_COMMON_H
++#include <linux/version.h>
++/*!
++ \defgroup IFX_PCI_COM IFX PCI/PCIe common parts for OS integration
++ \brief PCI/PCIe common parts
++*/
++
++/*!
++ \defgroup IFX_PCI_COM_OS OS APIs
++ \ingroup IFX_PCI_COM
++ \brief PCI/PCIe bus driver OS interface functions
++*/
++/*!
++ \file ifxmips_pci_common.h
++ \ingroup IFX_PCI_COM
++ \brief PCI/PCIe bus driver common OS header file
++*/
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++#define IFX_PCI_CONST
++#else
++#define IFX_PCI_CONST const
++#endif
++#ifdef CONFIG_IFX_PCI
++extern int ifx_pci_bios_map_irq(IFX_PCI_CONST struct pci_dev *dev, u8 slot, u8 pin);
++extern int ifx_pci_bios_plat_dev_init(struct pci_dev *dev);
++#endif /* COFNIG_IFX_PCI */
++
++#ifdef CONFIG_IFX_PCIE
++extern int ifx_pcie_bios_map_irq(IFX_PCI_CONST struct pci_dev *dev, u8 slot, u8 pin);
++extern int ifx_pcie_bios_plat_dev_init(struct pci_dev *dev);
++#endif
++
++#endif /* IFXMIPS_PCI_COMMON_H */
++
+diff --git a/arch/mips/pci/ifxmips_pcie.c b/arch/mips/pci/ifxmips_pcie.c
+new file mode 100644
+index 0000000..de6e2fa
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie.c
+@@ -0,0 +1,1607 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_pcie.c
++** PROJECT : IFX UEIP for VRX200
++** MODULES : PCI MSI sub module
++**
++** DATE : 02 Mar 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIe Root Complex Driver
++** COPYRIGHT : Copyright (c) 2009
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++** HISTORY
++** $Version $Date $Author $Comment
++** 0.0.1 02 Mar,2009 Lei Chuanhua Initial version
++*******************************************************************************/
++ /*!
++ \file ifxmips_pcie.c
++ \ingroup IFX_PCIE
++ \brief PCI express bus driver source file
++*/
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/mm.h>
++#include <asm/paccess.h>
++#include <linux/pci.h>
++#include <linux/pci_regs.h>
++#include <linux/module.h>
++
++#include "ifxmips_pcie.h"
++#include "ifxmips_pcie_reg.h"
++
++#define IFX_PCIE_VER_MAJOR 1
++#define IFX_PCIE_VER_MID 5
++#define IFX_PCIE_VER_MINOR 3
++
++/* Enable 32bit io due to its mem mapped io nature */
++#define IFX_PCIE_ERROR_INT
++#define CONFIG_IFX_PCIE_1ST_CORE
++#define IFX_PCIE_IO_32BIT
++
++#define IFX_PCIE_IR (INT_NUM_IM4_IRL0 + 25)
++#define IFX_PCIE_INTA (INT_NUM_IM4_IRL0 + 8)
++#define IFX_PCIE_INTB (INT_NUM_IM4_IRL0 + 9)
++#define IFX_PCIE_INTC (INT_NUM_IM4_IRL0 + 10)
++#define IFX_PCIE_INTD (INT_NUM_IM4_IRL0 + 11)
++#define MS(_v, _f) (((_v) & (_f)) >> _f##_S)
++#define SM(_v, _f) (((_v) << _f##_S) & (_f))
++#define IFX_REG_SET_BIT(_f, _r) \
++ IFX_REG_W32((IFX_REG_R32((_r)) &~ (_f)) | (_f), (_r))
++
++static DEFINE_SPINLOCK(ifx_pcie_lock);
++
++u32 g_pcie_debug_flag = PCIE_MSG_ANY & (~PCIE_MSG_CFG);
++
++static ifx_pcie_irq_t pcie_irqs[IFX_PCIE_CORE_NR] = {
++ {
++ .ir_irq = {
++ .irq = IFX_PCIE_IR,
++ .name = "ifx_pcie_rc0",
++ },
++
++ .legacy_irq = {
++ {
++ .irq_bit = PCIE_IRN_INTA,
++ .irq = IFX_PCIE_INTA,
++ },
++ {
++ .irq_bit = PCIE_IRN_INTB,
++ .irq = IFX_PCIE_INTB,
++ },
++ {
++ .irq_bit = PCIE_IRN_INTC,
++ .irq = IFX_PCIE_INTC,
++ },
++ {
++ .irq_bit = PCIE_IRN_INTD,
++ .irq = IFX_PCIE_INTD,
++ },
++ },
++ },
++
++#ifdef CONFIG_IFX_PCIE_2ND_CORE
++ {
++ .ir_irq = {
++ .irq = IFX_PCIE1_IR,
++ .name = "ifx_pcie_rc1",
++ },
++
++ .legacy_irq = {
++ {
++ .irq_bit = PCIE_IRN_INTA,
++ .irq = IFX_PCIE1_INTA,
++ },
++ {
++ .irq_bit = PCIE_IRN_INTB,
++ .irq = IFX_PCIE1_INTB,
++ },
++ {
++ .irq_bit = PCIE_IRN_INTC,
++ .irq = IFX_PCIE1_INTC,
++ },
++ {
++ .irq_bit = PCIE_IRN_INTD,
++ .irq = IFX_PCIE1_INTD,
++ },
++ },
++
++ },
++#endif /* CONFIG_IFX_PCIE_2ND_CORE */
++};
++
++void
++ifx_pcie_debug(const char *fmt, ...)
++{
++ static char buf[256] = {0}; /* XXX */
++ va_list ap;
++
++ va_start(ap, fmt);
++ vsnprintf(buf, sizeof(buf), fmt, ap);
++ va_end(ap);
++
++ printk("%s", buf);
++}
++
++#ifdef IFX_PCI_PHY_DBG
++/* Generate hot reset, XXX must catpure to verify */
++static INLINE void
++pcie_secondary_bus_reset(int pcie_port)
++{
++ int i;
++ u32 reg;
++#define IFX_PCIE_RESET_TIME 20
++
++ /* Assert Secondary Bus Reset */
++ reg = IFX_REG_R32(PCIE_INTRBCTRL(pcie_port));
++ reg |= PCIE_INTRBCTRL_RST_SECONDARY_BUS;
++ IFX_REG_W32(reg, PCIE_INTRBCTRL(pcie_port));
++
++ /* De-assert Secondary Bus Reset */
++ reg &= ~PCIE_INTRBCTRL_RST_SECONDARY_BUS;
++ IFX_REG_W32(reg, PCIE_INTRBCTRL(pcie_port));
++
++ /* XXX, wait at least 100 ms, then restore again */
++ for (i = 0; i < IFX_PCIE_RESET_TIME; i++) {
++ mdelay(10);
++ }
++#undef IFX_PCIE_RESET_TIME
++}
++
++/* Error or L0s to L0 */
++static INLINE int
++pcie_retrain_link(int pcie_port)
++{
++ int i;
++ u32 reg;
++#define IFX_PCIE_RETRAIN_TIME 1000
++
++ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port));
++ reg |= PCIE_LCTLSTS_RETRIAN_LINK;
++ IFX_REG_W32(reg, PCIE_LCTLSTS(pcie_port));
++
++ /* Wait for the link to come up */
++ for (i = 0; i < IFX_PCIE_RETRAIN_TIME; i++) {
++ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_RETRAIN_PENDING)) {
++ break;
++ }
++ udelay(100);
++ }
++ if (i >= IFX_PCIE_RETRAIN_TIME) {
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s retrain timeout\n", __func__);
++ return -1;
++ }
++ return 0;
++#undef IFX_PCIE_RETRAIN_TIME
++}
++
++static INLINE void
++pcie_disable_scrambling(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(PCIE_PLCR(pcie_port));
++ reg |= PCIE_PLCR_SCRAMBLE_DISABLE;
++ IFX_REG_W32(reg, PCIE_PLCR(pcie_port));
++}
++#endif /* IFX_PCI_PHY_DBG */
++
++static INLINE int
++pcie_ltssm_enable(int pcie_port)
++{
++ int i;
++#define IFX_PCIE_LTSSM_ENABLE_TIMEOUT 10
++
++ IFX_REG_W32(PCIE_RC_CCR_LTSSM_ENABLE, PCIE_RC_CCR(pcie_port)); /* Enable LTSSM */
++
++ /* Wait for the link to come up */
++ for (i = 0; i < IFX_PCIE_LTSSM_ENABLE_TIMEOUT; i++) {
++ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_RETRAIN_PENDING)) {
++ break;
++ }
++ udelay(10);
++ }
++ if (i >= IFX_PCIE_LTSSM_ENABLE_TIMEOUT) {
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s link timeout!!!!!\n", __func__);
++ return -1;
++ }
++ return 0;
++#undef IFX_PCIE_LTSSM_ENABLE_TIMEOUT
++}
++
++static INLINE void
++pcie_ltssm_disable(int pcie_port)
++{
++ IFX_REG_W32(0, PCIE_RC_CCR(pcie_port)); /* Disable LTSSM */
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_RC_CCR 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_RC_CCR(pcie_port)));
++}
++
++static INLINE void
++pcie_ahb_bus_error_suppress(int pcie_port)
++{
++ IFX_REG_W32(PCIE_AHB_CTRL_BUS_ERROR_SUPPRESS, PCIE_AHB_CTRL(pcie_port));
++}
++
++static INLINE void
++pcie_status_register_clear(int pcie_port)
++{
++ /* Clear the status register, XXX, seperate function */
++ IFX_REG_W32(0, PCIE_RC_DR(pcie_port));
++ IFX_REG_W32(0, PCIE_PCICMDSTS(pcie_port));
++ IFX_REG_W32(0, PCIE_DCTLSTS(pcie_port));
++ IFX_REG_W32(0, PCIE_LCTLSTS(pcie_port));
++ IFX_REG_W32(0, PCIE_SLCTLSTS(pcie_port));
++ IFX_REG_W32(0, PCIE_RSTS(pcie_port));
++ IFX_REG_W32(0, PCIE_UES_R(pcie_port));
++ IFX_REG_W32(0, PCIE_UEMR(pcie_port));
++ IFX_REG_W32(0, PCIE_UESR(pcie_port));
++ IFX_REG_W32(0, PCIE_CESR(pcie_port));
++ IFX_REG_W32(0, PCIE_CEMR(pcie_port));
++ IFX_REG_W32(0, PCIE_RESR(pcie_port));
++ IFX_REG_W32(0, PCIE_PVCCRSR(pcie_port));
++ IFX_REG_W32(0, PCIE_VC0_RSR0(pcie_port));
++ IFX_REG_W32(0, PCIE_TPFCS(pcie_port));
++ IFX_REG_W32(0, PCIE_TNPFCS(pcie_port));
++ IFX_REG_W32(0, PCIE_TCFCS(pcie_port));
++ IFX_REG_W32(0, PCIE_QSR(pcie_port));
++ IFX_REG_W32(0, PCIE_IOBLSECS(pcie_port));
++}
++
++static inline int
++ifx_pcie_link_up(int pcie_port)
++{
++ return (IFX_REG_R32(PCIE_PHY_SR(pcie_port)) & PCIE_PHY_SR_PHY_LINK_UP) ? 1 : 0;
++}
++
++#ifdef IFX_PCIE_DBG
++static void
++pcie_status_registers_dump(int pcie_port)
++{
++ printk(KERN_INFO "PCIe_PCICMDSTS: 0x%08x\n", IFX_REG_R32(PCIE_PCICMDSTS(pcie_port)));
++ printk(KERN_INFO "PCIe_RC_DR: 0x%08x\n", IFX_REG_R32(PCIE_RC_DR(pcie_port)));
++ printk(KERN_INFO "PCIe_DCTLSTS: 0x%08x\n", IFX_REG_R32(PCIE_DCTLSTS(pcie_port)));
++ printk(KERN_INFO "PCIe_LCTLSTS: 0x%08x\n", IFX_REG_R32(PCIE_LCTLSTS(pcie_port)));
++ printk(KERN_INFO "PCIe_SLCTLSTS: 0x%08x\n", IFX_REG_R32(PCIE_SLCTLSTS(pcie_port)));
++ printk(KERN_INFO "PCIe_RSTS: 0x%08x\n", IFX_REG_R32(PCIE_RSTS(pcie_port)));
++ printk(KERN_INFO "PCIe_UES_R: 0x%08x\n", IFX_REG_R32(PCIE_UES_R(pcie_port)));
++ printk(KERN_INFO "PCIe_UEMR: 0x%08x\n", IFX_REG_R32(PCIE_UEMR(pcie_port)));
++ printk(KERN_INFO "PCIe_UESR: 0x%08x\n", IFX_REG_R32(PCIE_UESR(pcie_port)));
++ printk(KERN_INFO "PCIe_CESR: 0x%08x\n", IFX_REG_R32(PCIE_CESR(pcie_port)));
++ printk(KERN_INFO "PCIe_CEMR: 0x%08x\n", IFX_REG_R32(PCIE_CEMR(pcie_port)));
++ printk(KERN_INFO "PCIe_RESR: 0x%08x\n", IFX_REG_R32(PCIE_RESR(pcie_port)));
++ printk(KERN_INFO "PCIe_ESIR: 0x%08x\n", IFX_REG_R32(PCIE_ESIR(pcie_port)));
++ printk(KERN_INFO "PCIe_PVCCRSR: 0x%08x\n", IFX_REG_R32(PCIE_PVCCRSR(pcie_port)));
++ printk(KERN_INFO "PCIe_VC0_RSR0: 0x%08x\n", IFX_REG_R32(PCIE_VC0_RSR0(pcie_port)));
++ printk(KERN_INFO "PCIe_TPFCS: 0x%08x\n", IFX_REG_R32(PCIE_TPFCS(pcie_port)));
++ printk(KERN_INFO "PCIe_TNPFCS: 0x%08x\n", IFX_REG_R32(PCIE_TNPFCS(pcie_port)));
++ printk(KERN_INFO "PCIe_TCFCS: 0x%08x\n", IFX_REG_R32(PCIE_TCFCS(pcie_port)));
++ printk(KERN_INFO "PCIe_QSR: 0x%08x\n", IFX_REG_R32(PCIE_QSR(pcie_port)));
++ printk(KERN_INFO "PCIe_VCTAR1: 0x%08x\n", IFX_REG_R32(PCIE_VCTAR1(pcie_port)));
++ printk(KERN_INFO "PCIe_VCTAR2: 0x%08x\n", IFX_REG_R32(PCIE_VCTAR2(pcie_port)));
++ printk(KERN_INFO "PCIe_IOBLSECS: 0x%08x\n", IFX_REG_R32(PCIE_IOBLSECS(pcie_port)));
++ printk(KERN_INFO "PCIe_ALTRT: 0x%08x\n", IFX_REG_R32(PCIE_ALTRT(pcie_port)));
++ printk(KERN_INFO "PCIe_SNR: 0x%08x\n", IFX_REG_R32(PCIE_SNR(pcie_port)));
++ printk(KERN_INFO "PCIe_DBR0: 0x%08x\n", IFX_REG_R32(PCIE_DBR0(pcie_port)));
++ printk(KERN_INFO "PCIe_DBR1: 0x%08x\n", IFX_REG_R32(PCIE_DBR1(pcie_port)));
++}
++
++static void
++pcie_post_dump(int pcie_port)
++{
++ printk(KERN_INFO "PCIe_PCICMDSTS: 0x%08x\n", IFX_REG_R32(PCIE_PCICMDSTS(pcie_port)));
++ printk(KERN_INFO "PCIe_MBML: 0x%08x\n", IFX_REG_R32(PCIE_MBML(pcie_port)));
++ printk(KERN_INFO "PCIe_PBML: 0x%08x\n", IFX_REG_R32(PCIE_PMBL(pcie_port)));
++ printk(KERN_INFO "PCIe_IOBLSECS: 0x%08x\n", IFX_REG_R32(PCIE_IOBLSECS(pcie_port)));
++ printk(KERN_INFO "PCIe_IO_BANDL: 0x%08x\n", IFX_REG_R32(PCIE_IO_BANDL(pcie_port)));
++ printk(KERN_INFO "PCIe_INTRBCTRL: 0x%08x\n", IFX_REG_R32(PCIE_INTRBCTRL(pcie_port)));
++ printk(KERN_INFO "Power State: D%1d\n", IFX_REG_R32(PCIE_PM_CSR(pcie_port)) & PCIE_PM_CSR_POWER_STATE);
++ printk(KERN_INFO "Negotiated Link Width: %d\n", MS(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)), PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH));
++ printk(KERN_INFO "Number of VCs: %d\n", IFX_REG_R32(PCIE_PVC1(pcie_port)) & PCIE_PVC1_EXT_VC_CNT);
++ printk(KERN_INFO "Low-priority VCs: %d\n", MS(IFX_REG_R32(PCIE_PVC1(pcie_port)), PCIE_PVC1_LOW_PRI_EXT_VC_CNT));
++ printk(KERN_INFO "VC Arbitration: 0x%08x\n", IFX_REG_R32(PCIE_PVC2(pcie_port)) & PCIE_PVC2_VC_ARB_WRR);
++ printk(KERN_INFO "Port Arbitration: 0x%08x\n", IFX_REG_R32(PCIE_VC0_RC(pcie_port)) & PCIE_VC0_RC_PORT_ARB);
++
++ if (ifx_pcie_link_up(pcie_port)) {
++ printk(KERN_INFO "PCIe PHY Link is UP\n");
++ }
++ else {
++ printk(KERN_INFO "PCIe PHY Link is DOWN!\n");
++ }
++ if ((IFX_REG_R32(PCIE_RC_DR(pcie_port)) & PCIE_RC_DR_DLL_UP)) {
++ printk(KERN_INFO "PCIe DLL is UP\n");
++ }
++ else {
++ printk(KERN_INFO "PCIe DLL is DOWN!\n");
++ }
++
++ if ((IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_DLL_ACTIVE)) {
++ printk(KERN_INFO "PCIE_LCTLSTS in DL_Active state!\n");
++ }
++ else {
++ printk(KERN_INFO "PCIE_LCTLSTS NOT in DL_Active state!\n");
++ }
++ }
++#endif /* IFX_PCIE_DBG */
++
++/* XXX, this function is not needed in fact */
++static INLINE void
++pcie_mem_io_setup(int pcie_port)
++{
++ u32 reg;
++ /*
++ * BAR[0:1] readonly register
++ * RC contains only minimal BARs for packets mapped to this device
++ * Mem/IO filters defines a range of memory occupied by memory mapped IO devices that
++ * reside on the downstream side fo the bridge.
++ */
++ reg = SM((PCIE_MEM_PHY_PORT_TO_END(pcie_port) >> 20), PCIE_MBML_MEM_LIMIT_ADDR)
++ | SM((PCIE_MEM_PHY_PORT_TO_BASE(pcie_port) >> 20), PCIE_MBML_MEM_BASE_ADDR);
++
++ IFX_REG_W32(reg, PCIE_MBML(pcie_port));
++
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_MBML: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_MBML(pcie_port)));
++
++#ifdef IFX_PCIE_PREFETCH_MEM_64BIT
++ reg = SM((PCIE_MEM_PHY_PORT_TO_END(pcie_port) >> 20), PCIE_PMBL_END_ADDR)
++ | SM((PCIE_MEM_PHY_PORT_TO_BASE(pcie_port) >> 20), PCIE_PMBL_UPPER_12BIT)
++ | PCIE_PMBL_64BIT_ADDR;
++ IFX_REG_W32(reg, PCIE_PMBL(pcie_port));
++
++ /* Must configure upper 32bit */
++ IFX_REG_W32(0, PCIE_PMBU32(pcie_port));
++ IFX_REG_W32(0, PCIE_PMLU32(pcie_port));
++#else
++ /* PCIe_PBML, same as MBML */
++ IFX_REG_W32(IFX_REG_R32(PCIE_MBML(pcie_port)), PCIE_PMBL(pcie_port));
++#endif
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_PMBL: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_PMBL(pcie_port)));
++
++ /* IO Address Range */
++ reg = SM((PCIE_IO_PHY_PORT_TO_END(pcie_port) >> 12), PCIE_IOBLSECS_IO_LIMIT_ADDR)
++ | SM((PCIE_IO_PHY_PORT_TO_BASE(pcie_port) >> 12), PCIE_IOBLSECS_IO_BASE_ADDR);
++#ifdef IFX_PCIE_IO_32BIT
++ reg |= PCIE_IOBLSECS_32BIT_IO_ADDR;
++#endif /* IFX_PCIE_IO_32BIT */
++ IFX_REG_W32(reg, PCIE_IOBLSECS(pcie_port));
++
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_IOBLSECS: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_IOBLSECS(pcie_port)));
++#ifdef IFX_PCIE_IO_32BIT
++ reg = SM((PCIE_IO_PHY_PORT_TO_END(pcie_port) >> 16), PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT)
++ | SM((PCIE_IO_PHY_PORT_TO_BASE(pcie_port) >> 16), PCIE_IO_BANDL_UPPER_16BIT_IO_BASE);
++ IFX_REG_W32(reg, PCIE_IO_BANDL(pcie_port));
++
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_IO_BANDL: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_IO_BANDL(pcie_port)));
++#endif /* IFX_PCIE_IO_32BIT */
++}
++
++static INLINE void
++pcie_msi_setup(int pcie_port)
++{
++ u32 reg;
++
++ /* XXX, MSI stuff should only apply to EP */
++ /* MSI Capability: Only enable 32-bit addresses */
++ reg = IFX_REG_R32(PCIE_MCAPR(pcie_port));
++ reg &= ~PCIE_MCAPR_ADDR64_CAP;
++
++ reg |= PCIE_MCAPR_MSI_ENABLE;
++
++ /* Disable multiple message */
++ reg &= ~(PCIE_MCAPR_MULTI_MSG_CAP | PCIE_MCAPR_MULTI_MSG_ENABLE);
++ IFX_REG_W32(reg, PCIE_MCAPR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_MCAPR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_MCAPR(pcie_port)));
++}
++
++static INLINE void
++pcie_pm_setup(int pcie_port)
++{
++ u32 reg;
++
++ /* Enable PME, Soft reset enabled */
++ reg = IFX_REG_R32(PCIE_PM_CSR(pcie_port));
++ reg |= PCIE_PM_CSR_PME_ENABLE | PCIE_PM_CSR_SW_RST;
++ IFX_REG_W32(reg, PCIE_PM_CSR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_PM_CSR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_PM_CSR(pcie_port)));
++}
++
++static INLINE void
++pcie_bus_setup(int pcie_port)
++{
++ u32 reg;
++
++ reg = SM(0, PCIE_BNR_PRIMARY_BUS_NUM) | SM(1, PCIE_PNR_SECONDARY_BUS_NUM) | SM(0xFF, PCIE_PNR_SUB_BUS_NUM);
++ IFX_REG_W32(reg, PCIE_BNR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_BNR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_BNR(pcie_port)));
++}
++
++static INLINE void
++pcie_device_setup(int pcie_port)
++{
++ u32 reg;
++
++ /* Device capability register, set up Maximum payload size */
++ reg = IFX_REG_R32(PCIE_DCAP(pcie_port));
++ reg |= PCIE_DCAP_ROLE_BASE_ERR_REPORT;
++ reg |= SM(PCIE_MAX_PAYLOAD_128, PCIE_DCAP_MAX_PAYLOAD_SIZE);
++
++ /* Only available for EP */
++ reg &= ~(PCIE_DCAP_EP_L0S_LATENCY | PCIE_DCAP_EP_L1_LATENCY);
++ IFX_REG_W32(reg, PCIE_DCAP(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_DCAP: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_DCAP(pcie_port)));
++
++ /* Device control and status register */
++ /* Set Maximum Read Request size for the device as a Requestor */
++ reg = IFX_REG_R32(PCIE_DCTLSTS(pcie_port));
++
++ /*
++ * Request size can be larger than the MPS used, but the completions returned
++ * for the read will be bounded by the MPS size.
++ * In our system, Max request size depends on AHB burst size. It is 64 bytes.
++ * but we set it as 128 as minimum one.
++ */
++ reg |= SM(PCIE_MAX_PAYLOAD_128, PCIE_DCTLSTS_MAX_READ_SIZE)
++ | SM(PCIE_MAX_PAYLOAD_128, PCIE_DCTLSTS_MAX_PAYLOAD_SIZE);
++
++ /* Enable relaxed ordering, no snoop, and all kinds of errors */
++ reg |= PCIE_DCTLSTS_RELAXED_ORDERING_EN | PCIE_DCTLSTS_ERR_EN | PCIE_DCTLSTS_NO_SNOOP_EN;
++
++ IFX_REG_W32(reg, PCIE_DCTLSTS(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_DCTLSTS: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_DCTLSTS(pcie_port)));
++}
++
++static INLINE void
++pcie_link_setup(int pcie_port)
++{
++ u32 reg;
++
++ /*
++ * XXX, Link capability register, bit 18 for EP CLKREQ# dynamic clock management for L1, L2/3 CPM
++ * L0s is reported during link training via TS1 order set by N_FTS
++ */
++ reg = IFX_REG_R32(PCIE_LCAP(pcie_port));
++ reg &= ~PCIE_LCAP_L0S_EIXT_LATENCY;
++ reg |= SM(3, PCIE_LCAP_L0S_EIXT_LATENCY);
++ IFX_REG_W32(reg, PCIE_LCAP(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_LCAP: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_LCAP(pcie_port)));
++
++ /* Link control and status register */
++ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port));
++
++ /* Link Enable, ASPM enabled */
++ reg &= ~PCIE_LCTLSTS_LINK_DISABLE;
++
++#ifdef CONFIG_PCIEASPM
++ /*
++ * We use the same physical reference clock that the platform provides on the connector
++ * It paved the way for ASPM to calculate the new exit Latency
++ */
++ reg |= PCIE_LCTLSTS_SLOT_CLK_CFG;
++ reg |= PCIE_LCTLSTS_COM_CLK_CFG;
++ /*
++ * We should disable ASPM by default except that we have dedicated power management support
++ * Enable ASPM will cause the system hangup/instability, performance degration
++ */
++ reg |= PCIE_LCTLSTS_ASPM_ENABLE;
++#else
++ reg &= ~PCIE_LCTLSTS_ASPM_ENABLE;
++#endif /* CONFIG_PCIEASPM */
++
++ /*
++ * The maximum size of any completion with data packet is bounded by the MPS setting
++ * in device control register
++ */
++
++ /* RCB may cause multiple split transactions, two options available, we use 64 byte RCB */
++ reg &= ~ PCIE_LCTLSTS_RCB128;
++
++ IFX_REG_W32(reg, PCIE_LCTLSTS(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_LCTLSTS: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_LCTLSTS(pcie_port)));
++}
++
++static INLINE void
++pcie_error_setup(int pcie_port)
++{
++ u32 reg;
++
++ /*
++ * Forward ERR_COR, ERR_NONFATAL, ERR_FATAL to the backbone
++ * Poisoned write TLPs and completions indicating poisoned TLPs will set the PCIe_PCICMDSTS.MDPE
++ */
++ reg = IFX_REG_R32(PCIE_INTRBCTRL(pcie_port));
++ reg |= PCIE_INTRBCTRL_SERR_ENABLE | PCIE_INTRBCTRL_PARITY_ERR_RESP_ENABLE;
++
++ IFX_REG_W32(reg, PCIE_INTRBCTRL(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_INTRBCTRL: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_INTRBCTRL(pcie_port)));
++
++ /* Uncorrectable Error Mask Register, Unmask <enable> all bits in PCIE_UESR */
++ reg = IFX_REG_R32(PCIE_UEMR(pcie_port));
++ reg &= ~PCIE_ALL_UNCORRECTABLE_ERR;
++ IFX_REG_W32(reg, PCIE_UEMR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_UEMR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_UEMR(pcie_port)));
++
++ /* Uncorrectable Error Severity Register, ALL errors are FATAL */
++ IFX_REG_W32(PCIE_ALL_UNCORRECTABLE_ERR, PCIE_UESR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_UESR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_UESR(pcie_port)));
++
++ /* Correctable Error Mask Register, unmask <enable> all bits */
++ reg = IFX_REG_R32(PCIE_CEMR(pcie_port));
++ reg &= ~PCIE_CORRECTABLE_ERR;
++ IFX_REG_W32(reg, PCIE_CEMR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_CEMR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_CEMR(pcie_port)));
++
++ /* Advanced Error Capabilities and Control Registr */
++ reg = IFX_REG_R32(PCIE_AECCR(pcie_port));
++ reg |= PCIE_AECCR_ECRC_CHECK_EN | PCIE_AECCR_ECRC_GEN_EN;
++ IFX_REG_W32(reg, PCIE_AECCR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_AECCR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_AECCR(pcie_port)));
++
++ /* Root Error Command Register, Report all types of errors */
++ reg = IFX_REG_R32(PCIE_RECR(pcie_port));
++ reg |= PCIE_RECR_ERR_REPORT_EN;
++ IFX_REG_W32(reg, PCIE_RECR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_RECR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_RECR(pcie_port)));
++
++ /* Clear the Root status register */
++ reg = IFX_REG_R32(PCIE_RESR(pcie_port));
++ IFX_REG_W32(reg, PCIE_RESR(pcie_port));
++}
++
++static INLINE void
++pcie_root_setup(int pcie_port)
++{
++ u32 reg;
++
++ /* Root control and capabilities register */
++ reg = IFX_REG_R32(PCIE_RCTLCAP(pcie_port));
++ reg |= PCIE_RCTLCAP_SERR_ENABLE | PCIE_RCTLCAP_PME_INT_EN;
++ IFX_REG_W32(reg, PCIE_RCTLCAP(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_RCTLCAP: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_RCTLCAP(pcie_port)));
++}
++
++static INLINE void
++pcie_vc_setup(int pcie_port)
++{
++ u32 reg;
++
++ /* Port VC Capability Register 2 */
++ reg = IFX_REG_R32(PCIE_PVC2(pcie_port));
++ reg &= ~PCIE_PVC2_VC_ARB_WRR;
++ reg |= PCIE_PVC2_VC_ARB_16P_FIXED_WRR;
++ IFX_REG_W32(reg, PCIE_PVC2(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_PVC2: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_PVC2(pcie_port)));
++
++ /* VC0 Resource Capability Register */
++ reg = IFX_REG_R32(PCIE_VC0_RC(pcie_port));
++ reg &= ~PCIE_VC0_RC_REJECT_SNOOP;
++ IFX_REG_W32(reg, PCIE_VC0_RC(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_VC0_RC: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_VC0_RC(pcie_port)));
++}
++
++static INLINE void
++pcie_port_logic_setup(int pcie_port)
++{
++ u32 reg;
++
++ /* FTS number, default 12, increase to 63, may increase time from/to L0s to L0 */
++ reg = IFX_REG_R32(PCIE_AFR(pcie_port));
++ reg &= ~(PCIE_AFR_FTS_NUM | PCIE_AFR_COM_FTS_NUM);
++ reg |= SM(PCIE_AFR_FTS_NUM_DEFAULT, PCIE_AFR_FTS_NUM)
++ | SM(PCIE_AFR_FTS_NUM_DEFAULT, PCIE_AFR_COM_FTS_NUM);
++ /* L0s and L1 entry latency */
++ reg &= ~(PCIE_AFR_L0S_ENTRY_LATENCY | PCIE_AFR_L1_ENTRY_LATENCY);
++ reg |= SM(PCIE_AFR_L0S_ENTRY_LATENCY_DEFAULT, PCIE_AFR_L0S_ENTRY_LATENCY)
++ | SM(PCIE_AFR_L1_ENTRY_LATENCY_DEFAULT, PCIE_AFR_L1_ENTRY_LATENCY);
++ IFX_REG_W32(reg, PCIE_AFR(pcie_port));
++
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_AFR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_AFR(pcie_port)));
++
++ /* Port Link Control Register */
++ reg = IFX_REG_R32(PCIE_PLCR(pcie_port));
++ reg |= PCIE_PLCR_DLL_LINK_EN; /* Enable the DLL link */
++ IFX_REG_W32(reg, PCIE_PLCR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_PLCR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_PLCR(pcie_port)));
++
++ /* Lane Skew Register */
++ reg = IFX_REG_R32(PCIE_LSR(pcie_port));
++ /* Enable ACK/NACK and FC */
++ reg &= ~(PCIE_LSR_ACKNAK_DISABLE | PCIE_LSR_FC_DISABLE);
++ IFX_REG_W32(reg, PCIE_LSR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_LSR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_LSR(pcie_port)));
++
++ /* Symbol Timer Register and Filter Mask Register 1 */
++ reg = IFX_REG_R32(PCIE_STRFMR(pcie_port));
++
++ /* Default SKP interval is very accurate already, 5us */
++ /* Enable IO/CFG transaction */
++ reg |= PCIE_STRFMR_RX_CFG_TRANS_ENABLE | PCIE_STRFMR_RX_IO_TRANS_ENABLE;
++ /* Disable FC WDT */
++ reg &= ~PCIE_STRFMR_FC_WDT_DISABLE;
++ IFX_REG_W32(reg, PCIE_STRFMR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_STRFMR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_STRFMR(pcie_port)));
++
++ /* Filter Masker Register 2 */
++ reg = IFX_REG_R32(PCIE_FMR2(pcie_port));
++ reg |= PCIE_FMR2_VENDOR_MSG1_PASSED_TO_TRGT1 | PCIE_FMR2_VENDOR_MSG0_PASSED_TO_TRGT1;
++ IFX_REG_W32(reg, PCIE_FMR2(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_FMR2: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_FMR2(pcie_port)));
++
++ /* VC0 Completion Receive Queue Control Register */
++ reg = IFX_REG_R32(PCIE_VC0_CRQCR(pcie_port));
++ reg &= ~PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE;
++ reg |= SM(PCIE_VC0_TLP_QUEUE_MODE_BYPASS, PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE);
++ IFX_REG_W32(reg, PCIE_VC0_CRQCR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_VC0_CRQCR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_VC0_CRQCR(pcie_port)));
++}
++
++static INLINE void
++pcie_rc_cfg_reg_setup(int pcie_port)
++{
++ pcie_ltssm_disable(pcie_port);
++ pcie_mem_io_setup(pcie_port);
++ pcie_msi_setup(pcie_port);
++ pcie_pm_setup(pcie_port);
++ pcie_bus_setup(pcie_port);
++ pcie_device_setup(pcie_port);
++ pcie_link_setup(pcie_port);
++ pcie_error_setup(pcie_port);
++ pcie_root_setup(pcie_port);
++ pcie_vc_setup(pcie_port);
++ pcie_port_logic_setup(pcie_port);
++}
++
++static int
++ifx_pcie_wait_phy_link_up(int pcie_port)
++{
++#define IFX_PCIE_PHY_LINK_UP_TIMEOUT 1000 /* XXX, tunable */
++ int i;
++
++ /* Wait for PHY link is up */
++ for (i = 0; i < IFX_PCIE_PHY_LINK_UP_TIMEOUT; i++) {
++ if (ifx_pcie_link_up(pcie_port)) {
++ break;
++ }
++ udelay(100);
++ }
++ if (i >= IFX_PCIE_PHY_LINK_UP_TIMEOUT) {
++ printk(KERN_ERR "%s timeout\n", __func__);
++ return -1;
++ }
++
++ /* Check data link up or not */
++ if (!(IFX_REG_R32(PCIE_RC_DR(pcie_port)) & PCIE_RC_DR_DLL_UP)) {
++ printk(KERN_ERR "%s DLL link is still down\n", __func__);
++ return -1;
++ }
++
++ /* Check Data link active or not */
++ if (!(IFX_REG_R32(PCIE_LCTLSTS(pcie_port)) & PCIE_LCTLSTS_DLL_ACTIVE)) {
++ printk(KERN_ERR "%s DLL is not active\n", __func__);
++ return -1;
++ }
++ return 0;
++#undef IFX_PCIE_PHY_LINK_UP_TIMEOUT
++}
++
++static INLINE int
++pcie_app_loigc_setup(int pcie_port)
++{
++#ifdef IFX_PCIE_PHY_DBG
++ pcie_disable_scrambling(pcie_port);
++#endif /* IFX_PCIE_PHY_DBG */
++ pcie_ahb_bus_error_suppress(pcie_port);
++
++ /* Pull PCIe EP out of reset */
++ pcie_device_rst_deassert(pcie_port);
++
++ /* Start LTSSM training between RC and EP */
++ pcie_ltssm_enable(pcie_port);
++
++ /* Check PHY status after enabling LTSSM */
++ if (ifx_pcie_wait_phy_link_up(pcie_port) != 0) {
++ return -1;
++ }
++ return 0;
++}
++
++/*
++ * Must be done after ltssm due to based on negotiated link
++ * width and payload size
++ * Update the Replay Time Limit. Empirically, some PCIe
++ * devices take a little longer to respond than expected under
++ * load. As a workaround for this we configure the Replay Time
++ * Limit to the value expected for a 512 byte MPS instead of
++ * our actual 128 byte MPS. The numbers below are directly
++ * from the PCIe spec table 3-4/5.
++ */
++static INLINE void
++pcie_replay_time_update(int pcie_port)
++{
++ u32 reg;
++ int nlw;
++ int rtl;
++
++ reg = IFX_REG_R32(PCIE_LCTLSTS(pcie_port));
++
++ nlw = MS(reg, PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH);
++ switch (nlw) {
++ case PCIE_MAX_LENGTH_WIDTH_X1:
++ rtl = 1677;
++ break;
++ case PCIE_MAX_LENGTH_WIDTH_X2:
++ rtl = 867;
++ break;
++ case PCIE_MAX_LENGTH_WIDTH_X4:
++ rtl = 462;
++ break;
++ case PCIE_MAX_LENGTH_WIDTH_X8:
++ rtl = 258;
++ break;
++ default:
++ rtl = 1677;
++ break;
++ }
++ reg = IFX_REG_R32(PCIE_ALTRT(pcie_port));
++ reg &= ~PCIE_ALTRT_REPLAY_TIME_LIMIT;
++ reg |= SM(rtl, PCIE_ALTRT_REPLAY_TIME_LIMIT);
++ IFX_REG_W32(reg, PCIE_ALTRT(pcie_port));
++
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_ALTRT 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_ALTRT(pcie_port)));
++}
++
++/*
++ * Table 359 Enhanced Configuration Address Mapping1)
++ * 1) This table is defined in Table 7-1, page 341, PCI Express Base Specification v1.1
++ * Memory Address PCI Express Configuration Space
++ * A[(20+n-1):20] Bus Number 1 < n < 8
++ * A[19:15] Device Number
++ * A[14:12] Function Number
++ * A[11:8] Extended Register Number
++ * A[7:2] Register Number
++ * A[1:0] Along with size of the access, used to generate Byte Enables
++ * For VR9, only the address bits [22:0] are mapped to the configuration space:
++ * . Address bits [22:20] select the target bus (1-of-8)1)
++ * . Address bits [19:15] select the target device (1-of-32) on the bus
++ * . Address bits [14:12] select the target function (1-of-8) within the device.
++ * . Address bits [11:2] selects the target dword (1-of-1024) within the selected function.s configuration space
++ * . Address bits [1:0] define the start byte location within the selected dword.
++ */
++static inline u32
++pcie_bus_addr(u8 bus_num, u16 devfn, int where)
++{
++ u32 addr;
++ u8 bus;
++
++ if (!bus_num) {
++ /* type 0 */
++ addr = ((PCI_SLOT(devfn) & 0x1F) << 15) | ((PCI_FUNC(devfn) & 0x7) << 12) | ((where & 0xFFF)& ~3);
++ }
++ else {
++ bus = bus_num;
++ /* type 1, only support 8 buses */
++ addr = ((bus & 0x7) << 20) | ((PCI_SLOT(devfn) & 0x1F) << 15) |
++ ((PCI_FUNC(devfn) & 0x7) << 12) | ((where & 0xFFF) & ~3);
++ }
++ IFX_PCIE_PRINT(PCIE_MSG_CFG, "%s: bus addr : %02x:%02x.%01x/%02x, addr=%08x\n",
++ __func__, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), where, addr);
++ return addr;
++}
++
++static int
++pcie_valid_config(int pcie_port, int bus, int dev)
++{
++ /* RC itself */
++ if ((bus == 0) && (dev == 0)) {
++ return 1;
++ }
++
++ /* No physical link */
++ if (!ifx_pcie_link_up(pcie_port)) {
++ return 0;
++ }
++
++ /* Bus zero only has RC itself
++ * XXX, check if EP will be integrated
++ */
++ if ((bus == 0) && (dev != 0)) {
++ return 0;
++ }
++
++ /* Maximum 8 buses supported for VRX */
++ if (bus > 9) {
++ return 0;
++ }
++
++ /*
++ * PCIe is PtP link, one bus only supports only one device
++ * except bus zero and PCIe switch which is virtual bus device
++ * The following two conditions really depends on the system design
++ * and attached the device.
++ * XXX, how about more new switch
++ */
++ if ((bus == 1) && (dev != 0)) {
++ return 0;
++ }
++
++ if ((bus >= 3) && (dev != 0)) {
++ return 0;
++ }
++ return 1;
++}
++
++static INLINE u32
++ifx_pcie_cfg_rd(int pcie_port, u32 reg)
++{
++ return IFX_REG_R32((volatile u32 *)(PCIE_CFG_PORT_TO_BASE(pcie_port) + reg));
++}
++
++static INLINE void
++ifx_pcie_cfg_wr(int pcie_port, unsigned int reg, u32 val)
++{
++ IFX_REG_W32( val, (volatile u32 *)(PCIE_CFG_PORT_TO_BASE(pcie_port) + reg));
++}
++
++static INLINE u32
++ifx_pcie_rc_cfg_rd(int pcie_port, u32 reg)
++{
++ return IFX_REG_R32((volatile u32 *)(PCIE_RC_PORT_TO_BASE(pcie_port) + reg));
++}
++
++static INLINE void
++ifx_pcie_rc_cfg_wr(int pcie_port, unsigned int reg, u32 val)
++{
++ IFX_REG_W32(val, (volatile u32 *)(PCIE_RC_PORT_TO_BASE(pcie_port) + reg));
++}
++
++u32
++ifx_pcie_bus_enum_read_hack(int where, u32 value)
++{
++ u32 tvalue = value;
++
++ if (where == PCI_PRIMARY_BUS) {
++ u8 primary, secondary, subordinate;
++
++ primary = tvalue & 0xFF;
++ secondary = (tvalue >> 8) & 0xFF;
++ subordinate = (tvalue >> 16) & 0xFF;
++ primary += pcibios_1st_host_bus_nr();
++ secondary += pcibios_1st_host_bus_nr();
++ subordinate += pcibios_1st_host_bus_nr();
++ tvalue = (tvalue & 0xFF000000) | (u32)primary | (u32)(secondary << 8) | (u32)(subordinate << 16);
++ }
++ return tvalue;
++}
++
++u32
++ifx_pcie_bus_enum_write_hack(int where, u32 value)
++{
++ u32 tvalue = value;
++
++ if (where == PCI_PRIMARY_BUS) {
++ u8 primary, secondary, subordinate;
++
++ primary = tvalue & 0xFF;
++ secondary = (tvalue >> 8) & 0xFF;
++ subordinate = (tvalue >> 16) & 0xFF;
++ if (primary > 0 && primary != 0xFF) {
++ primary -= pcibios_1st_host_bus_nr();
++ }
++
++ if (secondary > 0 && secondary != 0xFF) {
++ secondary -= pcibios_1st_host_bus_nr();
++ }
++ if (subordinate > 0 && subordinate != 0xFF) {
++ subordinate -= pcibios_1st_host_bus_nr();
++ }
++ tvalue = (tvalue & 0xFF000000) | (u32)primary | (u32)(secondary << 8) | (u32)(subordinate << 16);
++ }
++ else if (where == PCI_SUBORDINATE_BUS) {
++ u8 subordinate = tvalue & 0xFF;
++
++ subordinate = subordinate > 0 ? subordinate - pcibios_1st_host_bus_nr() : 0;
++ tvalue = subordinate;
++ }
++ return tvalue;
++}
++
++/**
++ * \fn static int ifx_pcie_read_config(struct pci_bus *bus, u32 devfn,
++ * int where, int size, u32 *value)
++ * \brief Read a value from configuration space
++ *
++ * \param[in] bus Pointer to pci bus
++ * \param[in] devfn PCI device function number
++ * \param[in] where PCI register number
++ * \param[in] size Register read size
++ * \param[out] value Pointer to return value
++ * \return PCIBIOS_BAD_REGISTER_NUMBER Invalid register number
++ * \return PCIBIOS_FUNC_NOT_SUPPORTED PCI function not supported
++ * \return PCIBIOS_DEVICE_NOT_FOUND PCI device not found
++ * \return PCIBIOS_SUCCESSFUL OK
++ * \ingroup IFX_PCIE_OS
++ */
++static int
++ifx_pcie_read_config(struct pci_bus *bus, u32 devfn,
++ int where, int size, u32 *value)
++{
++ u32 data = 0;
++ int bus_number = bus->number;
++ static const u32 mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0};
++ int ret = PCIBIOS_SUCCESSFUL;
++ struct ifx_pci_controller *ctrl = bus->sysdata;
++ int pcie_port = ctrl->port;
++
++ if (unlikely(size != 1 && size != 2 && size != 4)){
++ ret = PCIBIOS_BAD_REGISTER_NUMBER;
++ goto out;
++ }
++
++ /* Make sure the address is aligned to natural boundary */
++ if (unlikely(((size - 1) & where))) {
++ ret = PCIBIOS_BAD_REGISTER_NUMBER;
++ goto out;
++ }
++
++ /*
++ * If we are second controller, we have to cheat OS so that it assume
++ * its bus number starts from 0 in host controller
++ */
++ bus_number = ifx_pcie_bus_nr_deduct(bus_number, pcie_port);
++
++ /*
++ * We need to force the bus number to be zero on the root
++ * bus. Linux numbers the 2nd root bus to start after all
++ * busses on root 0.
++ */
++ if (bus->parent == NULL) {
++ bus_number = 0;
++ }
++
++ /*
++ * PCIe only has a single device connected to it. It is
++ * always device ID 0. Don't bother doing reads for other
++ * device IDs on the first segment.
++ */
++ if ((bus_number == 0) && (PCI_SLOT(devfn) != 0)) {
++ ret = PCIBIOS_FUNC_NOT_SUPPORTED;
++ goto out;
++ }
++
++ if (pcie_valid_config(pcie_port, bus_number, PCI_SLOT(devfn)) == 0) {
++ *value = 0xffffffff;
++ ret = PCIBIOS_DEVICE_NOT_FOUND;
++ goto out;
++ }
++
++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: %02x:%02x.%01x/%02x:%01d\n", __func__, bus_number,
++ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size);
++
++ PCIE_IRQ_LOCK(ifx_pcie_lock);
++ if (bus_number == 0) { /* RC itself */
++ u32 t;
++
++ t = (where & ~3);
++ data = ifx_pcie_rc_cfg_rd(pcie_port, t);
++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: rd local cfg, offset:%08x, data:%08x\n",
++ __func__, t, data);
++ }
++ else {
++ u32 addr = pcie_bus_addr(bus_number, devfn, where);
++
++ data = ifx_pcie_cfg_rd(pcie_port, addr);
++ if (pcie_port == IFX_PCIE_PORT0) {
++ #ifdef CONFIG_IFX_PCIE_HW_SWAP
++ data = le32_to_cpu(data);
++ #endif /* CONFIG_IFX_PCIE_HW_SWAP */
++ }
++ else {
++ #ifdef CONFIG_IFX_PCIE1_HW_SWAP
++ data = le32_to_cpu(data);
++ #endif /* CONFIG_IFX_PCIE_HW_SWAP */
++ }
++ }
++ /* To get a correct PCI topology, we have to restore the bus number to OS */
++ data = ifx_pcie_bus_enum_hack(bus, devfn, where, data, pcie_port, 1);
++
++ PCIE_IRQ_UNLOCK(ifx_pcie_lock);
++ IFX_PCIE_PRINT(PCIE_MSG_READ_CFG, "%s: read config: data=%08x raw=%08x\n",
++ __func__, (data >> (8 * (where & 3))) & mask[size & 7], data);
++
++ *value = (data >> (8 * (where & 3))) & mask[size & 7];
++out:
++ return ret;
++}
++
++static u32
++ifx_pcie_size_to_value(int where, int size, u32 data, u32 value)
++{
++ u32 shift;
++ u32 tdata = data;
++
++ switch (size) {
++ case 1:
++ shift = (where & 0x3) << 3;
++ tdata &= ~(0xffU << shift);
++ tdata |= ((value & 0xffU) << shift);
++ break;
++ case 2:
++ shift = (where & 3) << 3;
++ tdata &= ~(0xffffU << shift);
++ tdata |= ((value & 0xffffU) << shift);
++ break;
++ case 4:
++ tdata = value;
++ break;
++ }
++ return tdata;
++}
++
++/**
++ * \fn static static int ifx_pcie_write_config(struct pci_bus *bus, u32 devfn,
++ * int where, int size, u32 value)
++ * \brief Write a value to PCI configuration space
++ *
++ * \param[in] bus Pointer to pci bus
++ * \param[in] devfn PCI device function number
++ * \param[in] where PCI register number
++ * \param[in] size The register size to be written
++ * \param[in] value The valule to be written
++ * \return PCIBIOS_BAD_REGISTER_NUMBER Invalid register number
++ * \return PCIBIOS_DEVICE_NOT_FOUND PCI device not found
++ * \return PCIBIOS_SUCCESSFUL OK
++ * \ingroup IFX_PCIE_OS
++ */
++static int
++ifx_pcie_write_config(struct pci_bus *bus, u32 devfn,
++ int where, int size, u32 value)
++{
++ int bus_number = bus->number;
++ int ret = PCIBIOS_SUCCESSFUL;
++ struct ifx_pci_controller *ctrl = bus->sysdata;
++ int pcie_port = ctrl->port;
++ u32 tvalue = value;
++ u32 data;
++
++ /* Make sure the address is aligned to natural boundary */
++ if (unlikely(((size - 1) & where))) {
++ ret = PCIBIOS_BAD_REGISTER_NUMBER;
++ goto out;
++ }
++ /*
++ * If we are second controller, we have to cheat OS so that it assume
++ * its bus number starts from 0 in host controller
++ */
++ bus_number = ifx_pcie_bus_nr_deduct(bus_number, pcie_port);
++
++ /*
++ * We need to force the bus number to be zero on the root
++ * bus. Linux numbers the 2nd root bus to start after all
++ * busses on root 0.
++ */
++ if (bus->parent == NULL) {
++ bus_number = 0;
++ }
++
++ if (pcie_valid_config(pcie_port, bus_number, PCI_SLOT(devfn)) == 0) {
++ ret = PCIBIOS_DEVICE_NOT_FOUND;
++ goto out;
++ }
++
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: %02x:%02x.%01x/%02x:%01d value=%08x\n", __func__,
++ bus_number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value);
++
++ /* XXX, some PCIe device may need some delay */
++ PCIE_IRQ_LOCK(ifx_pcie_lock);
++
++ /*
++ * To configure the correct bus topology using native way, we have to cheat Os so that
++ * it can configure the PCIe hardware correctly.
++ */
++ tvalue = ifx_pcie_bus_enum_hack(bus, devfn, where, value, pcie_port, 0);
++
++ if (bus_number == 0) { /* RC itself */
++ u32 t;
++
++ t = (where & ~3);
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr local cfg, offset:%08x, fill:%08x\n", __func__, t, value);
++ data = ifx_pcie_rc_cfg_rd(pcie_port, t);
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd local cfg, offset:%08x, data:%08x\n", __func__, t, data);
++
++ data = ifx_pcie_size_to_value(where, size, data, tvalue);
++
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr local cfg, offset:%08x, value:%08x\n", __func__, t, data);
++ ifx_pcie_rc_cfg_wr(pcie_port, t, data);
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd local cfg, offset:%08x, value:%08x\n",
++ __func__, t, ifx_pcie_rc_cfg_rd(pcie_port, t));
++ }
++ else {
++ u32 addr = pcie_bus_addr(bus_number, devfn, where);
++
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: wr cfg, offset:%08x, fill:%08x\n", __func__, addr, value);
++ data = ifx_pcie_cfg_rd(pcie_port, addr);
++ if (pcie_port == IFX_PCIE_PORT0) {
++ #ifdef CONFIG_IFX_PCIE_HW_SWAP
++ data = le32_to_cpu(data);
++ #endif /* CONFIG_IFX_PCIE_HW_SWAP */
++ }
++ else {
++ #ifdef CONFIG_IFX_PCIE1_HW_SWAP
++ data = le32_to_cpu(data);
++ #endif /* CONFIG_IFX_PCIE_HW_SWAP */
++ }
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG,"%s: rd cfg, offset:%08x, data:%08x\n", __func__, addr, data);
++
++ data = ifx_pcie_size_to_value(where, size, data, tvalue);
++ if (pcie_port == IFX_PCIE_PORT0) {
++ #ifdef CONFIG_IFX_PCIE_HW_SWAP
++ data = cpu_to_le32(data);
++ #endif /* CONFIG_IFX_PCIE_HW_SWAP */
++ }
++ else {
++ #ifdef CONFIG_IFX_PCIE1_HW_SWAP
++ data = cpu_to_le32(data);
++ #endif /* CONFIG_IFX_PCIE_HW_SWAP */
++ }
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: wr cfg, offset:%08x, value:%08x\n", __func__, addr, data);
++ ifx_pcie_cfg_wr(pcie_port, addr, data);
++ IFX_PCIE_PRINT(PCIE_MSG_WRITE_CFG, "%s: rd cfg, offset:%08x, value:%08x\n",
++ __func__, addr, ifx_pcie_cfg_rd(pcie_port, addr));
++ }
++ PCIE_IRQ_UNLOCK(ifx_pcie_lock);
++out:
++ return ret;
++}
++
++static struct resource ifx_pcie_io_resource = {
++ .name = "PCIe0 I/O space",
++ .start = PCIE_IO_PHY_BASE,
++ .end = PCIE_IO_PHY_END,
++ .flags = IORESOURCE_IO,
++};
++
++static struct resource ifx_pcie_mem_resource = {
++ .name = "PCIe0 Memory space",
++ .start = PCIE_MEM_PHY_BASE,
++ .end = PCIE_MEM_PHY_END,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct pci_ops ifx_pcie_ops = {
++ .read = ifx_pcie_read_config,
++ .write = ifx_pcie_write_config,
++};
++
++#ifdef CONFIG_IFX_PCIE_2ND_CORE
++static struct resource ifx_pcie1_io_resource = {
++ .name = "PCIe1 I/O space",
++ .start = PCIE1_IO_PHY_BASE,
++ .end = PCIE1_IO_PHY_END,
++ .flags = IORESOURCE_IO,
++};
++
++static struct resource ifx_pcie1_mem_resource = {
++ .name = "PCIe1 Memory space",
++ .start = PCIE1_MEM_PHY_BASE,
++ .end = PCIE1_MEM_PHY_END,
++ .flags = IORESOURCE_MEM,
++};
++#endif /* CONFIG_IFX_PCIE_2ND_CORE */
++
++static struct ifx_pci_controller ifx_pcie_controller[IFX_PCIE_CORE_NR] = {
++ {
++ .pcic = {
++ .pci_ops = &ifx_pcie_ops,
++ .mem_resource = &ifx_pcie_mem_resource,
++ .io_resource = &ifx_pcie_io_resource,
++ },
++ .port = IFX_PCIE_PORT0,
++ },
++#ifdef CONFIG_IFX_PCIE_2ND_CORE
++ {
++ .pcic = {
++ .pci_ops = &ifx_pcie_ops,
++ .mem_resource = &ifx_pcie1_mem_resource,
++ .io_resource = &ifx_pcie1_io_resource,
++ },
++ .port = IFX_PCIE_PORT1,
++ },
++#endif /* CONFIG_IFX_PCIE_2ND_CORE */
++};
++
++#ifdef IFX_PCIE_ERROR_INT
++static INLINE void
++pcie_core_int_clear_all(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(PCIE_IRNCR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_ISR, "%s PCIE_IRNCR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_IRNCR(pcie_port)));
++ reg &= PCIE_RC_CORE_COMBINED_INT;
++ IFX_REG_W32(reg, PCIE_IRNCR(pcie_port));
++}
++
++static irqreturn_t
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
++pcie_rc_core_isr(int irq, void *dev_id)
++#else
++pcie_rc_core_isr(int irq, void *dev_id, struct pt_regs *regs)
++#endif
++{
++ struct ifx_pci_controller *ctrl = (struct ifx_pci_controller *)dev_id;
++ int pcie_port = ctrl->port;
++
++ IFX_PCIE_PRINT(PCIE_MSG_ISR, "PCIe RC error intr %d\n", irq);
++ pcie_core_int_clear_all(pcie_port);
++ return IRQ_HANDLED;
++}
++
++static int
++pcie_rc_core_int_init(int pcie_port)
++{
++ int ret;
++
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s enter \n", __func__);
++
++ /* Enable core interrupt */
++ IFX_REG_SET_BIT(PCIE_RC_CORE_COMBINED_INT, PCIE_IRNEN(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_IRNEN: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_IRNEN(pcie_port)));
++
++ /* Clear it first */
++ IFX_REG_SET_BIT(PCIE_RC_CORE_COMBINED_INT, PCIE_IRNCR(pcie_port));
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s PCIE_IRNCR: 0x%08x\n",
++ __func__, IFX_REG_R32(PCIE_IRNCR(pcie_port)));
++ ret = request_irq(pcie_irqs[pcie_port].ir_irq.irq, pcie_rc_core_isr, IRQF_DISABLED,
++ pcie_irqs[pcie_port].ir_irq.name, &ifx_pcie_controller[pcie_port]);
++ if (ret) {
++ printk(KERN_ERR "%s request irq %d failed\n", __func__, IFX_PCIE_IR);
++ }
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s exit \n", __func__);
++
++ return ret;
++}
++#endif /* IFX_PCIE_ERROR_INT */
++
++/**
++ * \fn int ifx_pcie_bios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++ * \brief Map a PCI device to the appropriate interrupt line
++ *
++ * \param[in] dev The Linux PCI device structure for the device to map
++ * \param[in] slot The slot number for this device on __BUS 0__. Linux
++ * enumerates through all the bridges and figures out the
++ * slot on Bus 0 where this device eventually hooks to.
++ * \param[in] pin The PCI interrupt pin read from the device, then swizzled
++ * as it goes through each bridge.
++ * \return Interrupt number for the device
++ * \ingroup IFX_PCIE_OS
++ */
++int
++ifx_pcie_bios_map_irq(IFX_PCI_CONST struct pci_dev *dev, u8 slot, u8 pin)
++{
++ u32 irq_bit = 0;
++ int irq = 0;
++ struct ifx_pci_controller *ctrl = dev->bus->sysdata;
++ int pcie_port = ctrl->port;
++
++ printk("%s port %d dev %s slot %d pin %d \n", __func__, pcie_port, pci_name(dev), slot, pin);
++
++ if ((pin == PCIE_LEGACY_DISABLE) || (pin > PCIE_LEGACY_INT_MAX)) {
++ printk(KERN_WARNING "WARNING: dev %s: invalid interrupt pin %d\n", pci_name(dev), pin);
++ return -1;
++ }
++ /* Pin index so minus one */
++ irq_bit = pcie_irqs[pcie_port].legacy_irq[pin - 1].irq_bit;
++ irq = pcie_irqs[pcie_port].legacy_irq[pin - 1].irq;
++ IFX_REG_SET_BIT(irq_bit, PCIE_IRNEN(pcie_port));
++// printk("%s PCIE_IRNEN: 0x%08x\n", __func__, IFX_REG_R32(PCIE_IRNEN(pcie_port)));
++ IFX_REG_SET_BIT(irq_bit, PCIE_IRNCR(pcie_port));
++ // printk("%s PCIE_IRNCR: 0x%08x\n", __func__, IFX_REG_R32(PCIE_IRNCR(pcie_port)));
++ printk("%s dev %s irq %d assigned\n", __func__, pci_name(dev), irq);
++// printk("%s dev %s: exit\n", __func__, pci_name(dev));
++ return irq;
++}
++
++/**
++ * \fn int ifx_pcie_bios_plat_dev_init(struct pci_dev *dev)
++ * \brief Called to perform platform specific PCI setup
++ *
++ * \param[in] dev The Linux PCI device structure for the device to map
++ * \return OK
++ * \ingroup IFX_PCIE_OS
++ */
++int
++ifx_pcie_bios_plat_dev_init(struct pci_dev *dev)
++{
++ u16 config;
++#ifdef IFX_PCIE_ERROR_INT
++ u32 dconfig;
++ int pos;
++#endif /* IFX_PCIE_ERROR_INT */
++
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s enter \n", __func__);
++ /* Enable reporting System errors and parity errors on all devices */
++ /* Enable parity checking and error reporting */
++ pci_read_config_word(dev, PCI_COMMAND, &config);
++ config |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR /*| PCI_COMMAND_INVALIDATE |
++ PCI_COMMAND_FAST_BACK*/;
++ pci_write_config_word(dev, PCI_COMMAND, config);
++
++ if (dev->subordinate) {
++ /* Set latency timers on sub bridges */
++ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); /* XXX, */
++ /* More bridge error detection */
++ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &config);
++ config |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
++ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, config);
++ }
++#ifdef IFX_PCIE_ERROR_INT
++ /* Enable the PCIe normal error reporting */
++ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
++ if (pos) {
++
++ /* Disable system error generation in response to error messages */
++ pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &config);
++ config &= ~(PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | PCI_EXP_RTCTL_SEFEE);
++ pci_write_config_word(dev, pos + PCI_EXP_RTCTL, config);
++
++ /* Clear PCIE Capability's Device Status */
++ pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &config);
++ pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, config);
++
++ /* Update Device Control */
++ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &config);
++ /* Correctable Error Reporting */
++ config |= PCI_EXP_DEVCTL_CERE;
++ /* Non-Fatal Error Reporting */
++ config |= PCI_EXP_DEVCTL_NFERE;
++ /* Fatal Error Reporting */
++ config |= PCI_EXP_DEVCTL_FERE;
++ /* Unsupported Request */
++ config |= PCI_EXP_DEVCTL_URRE;
++ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, config);
++ }
++
++ /* Find the Advanced Error Reporting capability */
++ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
++ if (pos) {
++ /* Clear Uncorrectable Error Status */
++ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &dconfig);
++ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, dconfig);
++ /* Enable reporting of all uncorrectable errors */
++ /* Uncorrectable Error Mask - turned on bits disable errors */
++ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, 0);
++ /*
++ * Leave severity at HW default. This only controls if
++ * errors are reported as uncorrectable or
++ * correctable, not if the error is reported.
++ */
++ /* PCI_ERR_UNCOR_SEVER - Uncorrectable Error Severity */
++ /* Clear Correctable Error Status */
++ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &dconfig);
++ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, dconfig);
++ /* Enable reporting of all correctable errors */
++ /* Correctable Error Mask - turned on bits disable errors */
++ pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, 0);
++ /* Advanced Error Capabilities */
++ pci_read_config_dword(dev, pos + PCI_ERR_CAP, &dconfig);
++ /* ECRC Generation Enable */
++ if (dconfig & PCI_ERR_CAP_ECRC_GENC) {
++ dconfig |= PCI_ERR_CAP_ECRC_GENE;
++ }
++ /* ECRC Check Enable */
++ if (dconfig & PCI_ERR_CAP_ECRC_CHKC) {
++ dconfig |= PCI_ERR_CAP_ECRC_CHKE;
++ }
++ pci_write_config_dword(dev, pos + PCI_ERR_CAP, dconfig);
++
++ /* PCI_ERR_HEADER_LOG - Header Log Register (16 bytes) */
++ /* Enable Root Port's interrupt in response to error messages */
++ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND,
++ PCI_ERR_ROOT_CMD_COR_EN |
++ PCI_ERR_ROOT_CMD_NONFATAL_EN |
++ PCI_ERR_ROOT_CMD_FATAL_EN);
++ /* Clear the Root status register */
++ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &dconfig);
++ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig);
++ }
++#endif /* IFX_PCIE_ERROR_INT */
++ /* WAR, only 128 MRRS is supported, force all EPs to support this value */
++ pcie_set_readrq(dev, 128);
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s exit \n", __func__);
++ return 0;
++}
++
++static void
++pcie_phy_rst(int pcie_port)
++{
++ pcie_phy_rst_assert(pcie_port);
++ pcie_phy_rst_deassert(pcie_port);
++
++ /* Make sure PHY PLL is stable */
++ udelay(20);
++}
++
++static int
++pcie_rc_initialize(int pcie_port)
++{
++ int i;
++#define IFX_PCIE_PHY_LOOP_CNT 5
++
++ pcie_rcu_endian_setup(pcie_port);
++
++ pcie_ep_gpio_rst_init(pcie_port);
++
++ /*
++ * XXX, PCIe elastic buffer bug will cause not to be detected. One more
++ * reset PCIe PHY will solve this issue
++ */
++ for (i = 0; i < IFX_PCIE_PHY_LOOP_CNT; i++) {
++ /* Disable PCIe PHY Analog part for sanity check */
++ pcie_phy_pmu_disable(pcie_port);
++
++ pcie_phy_rst(pcie_port);
++
++ /* PCIe Core reset enabled, low active, sw programmed */
++ pcie_core_rst_assert(pcie_port);
++
++ /* Put PCIe EP in reset status */
++ pcie_device_rst_assert(pcie_port);
++
++ /* PCI PHY & Core reset disabled, high active, sw programmed */
++ pcie_core_rst_deassert(pcie_port);
++
++ /* Already in a quiet state, program PLL, enable PHY, check ready bit */
++ pcie_phy_clock_mode_setup(pcie_port);
++
++ /* Enable PCIe PHY and Clock */
++ pcie_core_pmu_setup(pcie_port);
++
++ /* Clear status registers */
++ pcie_status_register_clear(pcie_port);
++
++ #ifdef CONFIG_PCI_MSI
++ pcie_msi_init(pcie_port);
++ #endif /* CONFIG_PCI_MSI */
++ pcie_rc_cfg_reg_setup(pcie_port);
++
++ /* Once link is up, break out */
++ if (pcie_app_loigc_setup(pcie_port) == 0) {
++ break;
++ }
++ }
++ if (i >= IFX_PCIE_PHY_LOOP_CNT) {
++ printk(KERN_ERR "%s link up failed!!!!!\n", __func__);
++ return -EIO;
++ }
++ /* NB, don't increase ACK/NACK timer timeout value, which will cause a lot of COR errors */
++ pcie_replay_time_update(pcie_port);
++#ifdef IFX_PCIE_DBG
++ pcie_post_dump(pcie_port);
++ pcie_status_registers_dump(pcie_port);
++#endif /* IFX_PCIE_DBG */
++ return 0;
++}
++
++static int inline
++ifx_pcie_startup_port_nr(void)
++{
++ int pcie_port = IFX_PCIE_PORT0;
++
++#if defined (CONFIG_IFX_PCIE_1ST_CORE) && defined (CONFIG_IFX_PCIE_2ND_CORE)
++ pcie_port = IFX_PCIE_PORT0;
++#elif defined (CONFIG_IFX_PCIE_1ST_CORE)
++ pcie_port = IFX_PCIE_PORT0;
++#elif defined (CONFIG_IFX_PCIE_2ND_CORE)
++ pcie_port = IFX_PCIE_PORT1;
++#else
++ #error "Please choose valid PCIe Core"
++#endif
++ return pcie_port;
++}
++
++/**
++ * \fn static int __init ifx_pcie_bios_init(void)
++ * \brief Initialize the IFX PCIe controllers
++ *
++ * \return -EIO PCIe PHY link is not up
++ * \return -ENOMEM Configuration/IO space failed to map
++ * \return 0 OK
++ * \ingroup IFX_PCIE_OS
++ */
++extern int (*ltq_pci_plat_arch_init)(struct pci_dev *dev);
++extern int (*ltq_pci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
++
++static int __init
++ifx_pcie_bios_init(void)
++{
++ char ver_str[128] = {0};
++ void __iomem *io_map_base;
++ int pcie_port;
++ int startup_port;
++
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s enter \n", __func__);
++
++ ltq_pci_map_irq = ifx_pcie_bios_map_irq;
++ ltq_pci_plat_arch_init = ifx_pcie_bios_plat_dev_init;
++
++ /* Enable AHB Master/ Slave */
++ pcie_ahb_pmu_setup();
++
++ startup_port = ifx_pcie_startup_port_nr();
++
++ for (pcie_port = startup_port; pcie_port < IFX_PCIE_CORE_NR; pcie_port++){
++ if (pcie_rc_initialize(pcie_port) == 0) {
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s: ifx_pcie_cfg_base 0x%p\n",
++ __func__, PCIE_CFG_PORT_TO_BASE(pcie_port));
++ /* Otherwise, warning will pop up */
++ io_map_base = ioremap(PCIE_IO_PHY_PORT_TO_BASE(pcie_port), PCIE_IO_SIZE);
++ if (io_map_base == NULL) {
++ IFX_PCIE_PRINT(PCIE_MSG_ERR, "%s io space ioremap failed\n", __func__);
++ return -ENOMEM;
++ }
++ ifx_pcie_controller[pcie_port].pcic.io_map_base = (unsigned long)io_map_base;
++
++ register_pci_controller(&ifx_pcie_controller[pcie_port].pcic);
++ /* XXX, clear error status */
++
++ IFX_PCIE_PRINT(PCIE_MSG_INIT, "%s: mem_resource 0x%p, io_resource 0x%p\n",
++ __func__, &ifx_pcie_controller[pcie_port].pcic.mem_resource,
++ &ifx_pcie_controller[pcie_port].pcic.io_resource);
++
++ #ifdef IFX_PCIE_ERROR_INT
++ pcie_rc_core_int_init(pcie_port);
++ #endif /* IFX_PCIE_ERROR_INT */
++ }
++ }
++#ifdef CONFIG_IFX_PMCU
++ ifx_pcie_pmcu_init();
++#endif /* CONFIG_IFX_PMCU */
++
++ sprintf(ver_str, "PCIe Root Complex %d.%d.%d", IFX_PCIE_VER_MAJOR, IFX_PCIE_VER_MID, IFX_PCIE_VER_MINOR);
++ printk(KERN_INFO "%s", ver_str);
++ return 0;
++#undef IFX_PCIE_PHY_LOOP_CNT
++}
++arch_initcall(ifx_pcie_bios_init);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Chuanhua.Lei@infineon.com");
++MODULE_SUPPORTED_DEVICE("Infineon builtin PCIe RC module");
++MODULE_DESCRIPTION("Infineon builtin PCIe RC driver");
++
+diff --git a/arch/mips/pci/ifxmips_pcie.h b/arch/mips/pci/ifxmips_pcie.h
+new file mode 100644
+index 0000000..49a4d2f
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie.h
+@@ -0,0 +1,135 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_pcie.h
++** PROJECT : IFX UEIP for VRX200
++** MODULES : PCIe module
++**
++** DATE : 02 Mar 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIe Root Complex Driver
++** COPYRIGHT : Copyright (c) 2009
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++** HISTORY
++** $Version $Date $Author $Comment
++** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version
++*******************************************************************************/
++#ifndef IFXMIPS_PCIE_H
++#define IFXMIPS_PCIE_H
++#include <linux/version.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include "ifxmips_pci_common.h"
++#include "ifxmips_pcie_reg.h"
++
++/*!
++ \defgroup IFX_PCIE PCI Express bus driver module
++ \brief PCI Express IP module support VRX200
++*/
++
++/*!
++ \defgroup IFX_PCIE_OS OS APIs
++ \ingroup IFX_PCIE
++ \brief PCIe bus driver OS interface functions
++*/
++
++/*!
++ \file ifxmips_pcie.h
++ \ingroup IFX_PCIE
++ \brief header file for PCIe module common header file
++*/
++#define PCIE_IRQ_LOCK(lock) do { \
++ unsigned long flags; \
++ spin_lock_irqsave(&(lock), flags);
++#define PCIE_IRQ_UNLOCK(lock) \
++ spin_unlock_irqrestore(&(lock), flags); \
++} while (0)
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++#define IRQF_SHARED SA_SHIRQ
++#endif
++
++#define PCIE_MSG_MSI 0x00000001
++#define PCIE_MSG_ISR 0x00000002
++#define PCIE_MSG_FIXUP 0x00000004
++#define PCIE_MSG_READ_CFG 0x00000008
++#define PCIE_MSG_WRITE_CFG 0x00000010
++#define PCIE_MSG_CFG (PCIE_MSG_READ_CFG | PCIE_MSG_WRITE_CFG)
++#define PCIE_MSG_REG 0x00000020
++#define PCIE_MSG_INIT 0x00000040
++#define PCIE_MSG_ERR 0x00000080
++#define PCIE_MSG_PHY 0x00000100
++#define PCIE_MSG_ANY 0x000001ff
++
++#define IFX_PCIE_PORT0 0
++#define IFX_PCIE_PORT1 1
++
++#ifdef CONFIG_IFX_PCIE_2ND_CORE
++#define IFX_PCIE_CORE_NR 2
++#else
++#define IFX_PCIE_CORE_NR 1
++#endif
++
++#define IFX_PCIE_ERROR_INT
++
++//#define IFX_PCIE_DBG
++
++#if defined(IFX_PCIE_DBG)
++#define IFX_PCIE_PRINT(_m, _fmt, args...) do { \
++ ifx_pcie_debug((_fmt), ##args); \
++} while (0)
++
++#define INLINE
++#else
++#define IFX_PCIE_PRINT(_m, _fmt, args...) \
++ do {} while(0)
++#define INLINE inline
++#endif
++
++struct ifx_pci_controller {
++ struct pci_controller pcic;
++
++ /* RC specific, per host bus information */
++ u32 port; /* Port index, 0 -- 1st core, 1 -- 2nd core */
++};
++
++typedef struct ifx_pcie_ir_irq {
++ const unsigned int irq;
++ const char name[16];
++}ifx_pcie_ir_irq_t;
++
++typedef struct ifx_pcie_legacy_irq{
++ const u32 irq_bit;
++ const int irq;
++}ifx_pcie_legacy_irq_t;
++
++typedef struct ifx_pcie_irq {
++ ifx_pcie_ir_irq_t ir_irq;
++ ifx_pcie_legacy_irq_t legacy_irq[PCIE_LEGACY_INT_MAX];
++}ifx_pcie_irq_t;
++
++extern u32 g_pcie_debug_flag;
++extern void ifx_pcie_debug(const char *fmt, ...);
++extern void pcie_phy_clock_mode_setup(int pcie_port);
++extern void pcie_msi_pic_init(int pcie_port);
++extern u32 ifx_pcie_bus_enum_read_hack(int where, u32 value);
++extern u32 ifx_pcie_bus_enum_write_hack(int where, u32 value);
++
++#define CONFIG_VR9
++
++#ifdef CONFIG_VR9
++#include "ifxmips_pcie_vr9.h"
++#elif defined (CONFIG_AR10)
++#include "ifxmips_pcie_ar10.h"
++#else
++#error "PCIE: platform not defined"
++#endif /* CONFIG_VR9 */
++
++#endif /* IFXMIPS_PCIE_H */
++
+diff --git a/arch/mips/pci/ifxmips_pcie_ar10.h b/arch/mips/pci/ifxmips_pcie_ar10.h
+new file mode 100644
+index 0000000..99ff463
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie_ar10.h
+@@ -0,0 +1,290 @@
++/****************************************************************************
++ Copyright (c) 2010
++ Lantiq Deutschland GmbH
++ Am Campeon 3; 85579 Neubiberg, Germany
++
++ For licensing information, see the file 'LICENSE' in the root folder of
++ this software module.
++
++ *****************************************************************************/
++/*!
++ \file ifxmips_pcie_ar10.h
++ \ingroup IFX_PCIE
++ \brief PCIe RC driver ar10 specific file
++*/
++
++#ifndef IFXMIPS_PCIE_AR10_H
++#define IFXMIPS_PCIE_AR10_H
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif /* AUTOCONF_INCLUDED */
++#include <linux/types.h>
++#include <linux/delay.h>
++
++/* Project header file */
++#include <asm/ifx/ifx_types.h>
++#include <asm/ifx/ifx_pmu.h>
++#include <asm/ifx/ifx_gpio.h>
++#include <asm/ifx/ifx_ebu_led.h>
++
++static inline void pcie_ep_gpio_rst_init(int pcie_port)
++{
++ ifx_ebu_led_enable();
++ if (pcie_port == 0) {
++ ifx_ebu_led_set_data(11, 1);
++ }
++ else {
++ ifx_ebu_led_set_data(12, 1);
++ }
++}
++
++static inline void pcie_ahb_pmu_setup(void)
++{
++ /* XXX, moved to CGU to control AHBM */
++}
++
++static inline void pcie_rcu_endian_setup(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN);
++ /* Inbound, big endian */
++ reg |= IFX_RCU_BE_AHB4S;
++ if (pcie_port == 0) {
++ reg |= IFX_RCU_BE_PCIE0M;
++
++ #ifdef CONFIG_IFX_PCIE_HW_SWAP
++ /* Outbound, software swap needed */
++ reg |= IFX_RCU_BE_AHB3M;
++ reg &= ~IFX_RCU_BE_PCIE0S;
++ #else
++ /* Outbound little endian */
++ reg &= ~IFX_RCU_BE_AHB3M;
++ reg &= ~IFX_RCU_BE_PCIE0S;
++ #endif
++ }
++ else {
++ reg |= IFX_RCU_BE_PCIE1M;
++ #ifdef CONFIG_IFX_PCIE1_HW_SWAP
++ /* Outbound, software swap needed */
++ reg |= IFX_RCU_BE_AHB3M;
++ reg &= ~IFX_RCU_BE_PCIE1S;
++ #else
++ /* Outbound little endian */
++ reg &= ~IFX_RCU_BE_AHB3M;
++ reg &= ~IFX_RCU_BE_PCIE1S;
++ #endif
++ }
++
++ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN);
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s IFX_RCU_AHB_ENDIAN: 0x%08x\n", __func__, IFX_REG_R32(IFX_RCU_AHB_ENDIAN));
++}
++
++static inline void pcie_phy_pmu_enable(int pcie_port)
++{
++ if (pcie_port == 0) { /* XXX, should use macro*/
++ PCIE0_PHY_PMU_SETUP(IFX_PMU_ENABLE);
++ }
++ else {
++ PCIE1_PHY_PMU_SETUP(IFX_PMU_ENABLE);
++ }
++}
++
++static inline void pcie_phy_pmu_disable(int pcie_port)
++{
++ if (pcie_port == 0) { /* XXX, should use macro*/
++ PCIE0_PHY_PMU_SETUP(IFX_PMU_DISABLE);
++ }
++ else {
++ PCIE1_PHY_PMU_SETUP(IFX_PMU_DISABLE);
++ }
++}
++
++static inline void pcie_pdi_big_endian(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN);
++ if (pcie_port == 0) {
++ /* Config AHB->PCIe and PDI endianness */
++ reg |= IFX_RCU_BE_PCIE0_PDI;
++ }
++ else {
++ /* Config AHB->PCIe and PDI endianness */
++ reg |= IFX_RCU_BE_PCIE1_PDI;
++ }
++ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN);
++}
++
++static inline void pcie_pdi_pmu_enable(int pcie_port)
++{
++ if (pcie_port == 0) {
++ /* Enable PDI to access PCIe PHY register */
++ PDI0_PMU_SETUP(IFX_PMU_ENABLE);
++ }
++ else {
++ PDI1_PMU_SETUP(IFX_PMU_ENABLE);
++ }
++}
++
++static inline void pcie_core_rst_assert(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(IFX_RCU_RST_REQ);
++
++ /* Reset Core, bit 22 */
++ if (pcie_port == 0) {
++ reg |= 0x00400000;
++ }
++ else {
++ reg |= 0x08000000; /* Bit 27 */
++ }
++ IFX_REG_W32(reg, IFX_RCU_RST_REQ);
++}
++
++static inline void pcie_core_rst_deassert(int pcie_port)
++{
++ u32 reg;
++
++ /* Make sure one micro-second delay */
++ udelay(1);
++
++ reg = IFX_REG_R32(IFX_RCU_RST_REQ);
++ if (pcie_port == 0) {
++ reg &= ~0x00400000; /* bit 22 */
++ }
++ else {
++ reg &= ~0x08000000; /* Bit 27 */
++ }
++ IFX_REG_W32(reg, IFX_RCU_RST_REQ);
++}
++
++static inline void pcie_phy_rst_assert(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(IFX_RCU_RST_REQ);
++ if (pcie_port == 0) {
++ reg |= 0x00001000; /* Bit 12 */
++ }
++ else {
++ reg |= 0x00002000; /* Bit 13 */
++ }
++ IFX_REG_W32(reg, IFX_RCU_RST_REQ);
++}
++
++static inline void pcie_phy_rst_deassert(int pcie_port)
++{
++ u32 reg;
++
++ /* Make sure one micro-second delay */
++ udelay(1);
++
++ reg = IFX_REG_R32(IFX_RCU_RST_REQ);
++ if (pcie_port == 0) {
++ reg &= ~0x00001000; /* Bit 12 */
++ }
++ else {
++ reg &= ~0x00002000; /* Bit 13 */
++ }
++ IFX_REG_W32(reg, IFX_RCU_RST_REQ);
++}
++
++static inline void pcie_device_rst_assert(int pcie_port)
++{
++ if (pcie_port == 0) {
++ ifx_ebu_led_set_data(11, 0);
++ }
++ else {
++ ifx_ebu_led_set_data(12, 0);
++ }
++}
++
++static inline void pcie_device_rst_deassert(int pcie_port)
++{
++ mdelay(100);
++ if (pcie_port == 0) {
++ ifx_ebu_led_set_data(11, 1);
++ }
++ else {
++ ifx_ebu_led_set_data(12, 1);
++ }
++ ifx_ebu_led_disable();
++}
++
++static inline void pcie_core_pmu_setup(int pcie_port)
++{
++ if (pcie_port == 0) {
++ PCIE0_CTRL_PMU_SETUP(IFX_PMU_ENABLE);
++ }
++ else {
++ PCIE1_CTRL_PMU_SETUP(IFX_PMU_ENABLE);
++ }
++}
++
++static inline void pcie_msi_init(int pcie_port)
++{
++ pcie_msi_pic_init(pcie_port);
++ if (pcie_port == 0) {
++ MSI0_PMU_SETUP(IFX_PMU_ENABLE);
++ }
++ else {
++ MSI1_PMU_SETUP(IFX_PMU_ENABLE);
++ }
++}
++
++static inline u32
++ifx_pcie_bus_nr_deduct(u32 bus_number, int pcie_port)
++{
++ u32 tbus_number = bus_number;
++
++#ifdef CONFIG_IFX_PCIE_2ND_CORE
++ if (pcie_port == IFX_PCIE_PORT1) { /* Port 1 must check if there are two cores enabled */
++ if (pcibios_host_nr() > 1) {
++ tbus_number -= pcibios_1st_host_bus_nr();
++ }
++ }
++#endif /* CONFIG_IFX_PCI */
++ return tbus_number;
++}
++
++static inline u32
++ifx_pcie_bus_enum_hack(struct pci_bus *bus, u32 devfn, int where, u32 value, int pcie_port, int read)
++{
++ struct pci_dev *pdev;
++ u32 tvalue = value;
++
++ /* Sanity check */
++ pdev = pci_get_slot(bus, devfn);
++ if (pdev == NULL) {
++ return tvalue;
++ }
++
++ /* Only care about PCI bridge */
++ if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
++ return tvalue;
++ }
++
++ if (read) { /* Read hack */
++ #ifdef CONFIG_IFX_PCIE_2ND_CORE
++ if (pcie_port == IFX_PCIE_PORT1) { /* Port 1 must check if there are two cores enabled */
++ if (pcibios_host_nr() > 1) {
++ tvalue = ifx_pcie_bus_enum_read_hack(where, tvalue);
++ }
++ }
++ #endif /* CONFIG_IFX_PCIE_2ND_CORE */
++ }
++ else { /* Write hack */
++ #ifdef CONFIG_IFX_PCIE_2ND_CORE
++ if (pcie_port == IFX_PCIE_PORT1) { /* Port 1 must check if there are two cores enabled */
++ if (pcibios_host_nr() > 1) {
++ tvalue = ifx_pcie_bus_enum_write_hack(where, tvalue);
++ }
++ }
++ #endif
++ }
++ return tvalue;
++}
++
++#endif /* IFXMIPS_PCIE_AR10_H */
+diff --git a/arch/mips/pci/ifxmips_pcie_msi.c b/arch/mips/pci/ifxmips_pcie_msi.c
+new file mode 100644
+index 0000000..5bee7f8
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie_msi.c
+@@ -0,0 +1,392 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_pcie_msi.c
++** PROJECT : IFX UEIP for VRX200
++** MODULES : PCI MSI sub module
++**
++** DATE : 02 Mar 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIe MSI Driver
++** COPYRIGHT : Copyright (c) 2009
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++** HISTORY
++** $Date $Author $Comment
++** 02 Mar,2009 Lei Chuanhua Initial version
++*******************************************************************************/
++/*!
++ \defgroup IFX_PCIE_MSI MSI OS APIs
++ \ingroup IFX_PCIE
++ \brief PCIe bus driver OS interface functions
++*/
++
++/*!
++ \file ifxmips_pcie_msi.c
++ \ingroup IFX_PCIE
++ \brief PCIe MSI OS interface file
++*/
++
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif /* AUTOCONF_INCLUDED */
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/kernel_stat.h>
++#include <linux/pci.h>
++#include <linux/msi.h>
++#include <linux/module.h>
++#include <asm/bootinfo.h>
++#include <asm/irq.h>
++#include <asm/traps.h>
++
++#include <asm/ifx/ifx_types.h>
++#include <asm/ifx/ifx_regs.h>
++#include <asm/ifx/common_routines.h>
++#include <asm/ifx/irq.h>
++
++#include "ifxmips_pcie_reg.h"
++#include "ifxmips_pcie.h"
++
++#define IFX_MSI_IRQ_NUM 16
++
++enum {
++ IFX_PCIE_MSI_IDX0 = 0,
++ IFX_PCIE_MSI_IDX1,
++ IFX_PCIE_MSI_IDX2,
++ IFX_PCIE_MSI_IDX3,
++};
++
++typedef struct ifx_msi_irq_idx {
++ const int irq;
++ const int idx;
++}ifx_msi_irq_idx_t;
++
++struct ifx_msi_pic {
++ volatile u32 pic_table[IFX_MSI_IRQ_NUM];
++ volatile u32 pic_endian; /* 0x40 */
++};
++typedef struct ifx_msi_pic *ifx_msi_pic_t;
++
++typedef struct ifx_msi_irq {
++ const volatile ifx_msi_pic_t msi_pic_p;
++ const u32 msi_phy_base;
++ const ifx_msi_irq_idx_t msi_irq_idx[IFX_MSI_IRQ_NUM];
++ /*
++ * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
++ * in use.
++ */
++ u16 msi_free_irq_bitmask;
++
++ /*
++ * Each bit in msi_multiple_irq_bitmask tells that the device using
++ * this bit in msi_free_irq_bitmask is also using the next bit. This
++ * is used so we can disable all of the MSI interrupts when a device
++ * uses multiple.
++ */
++ u16 msi_multiple_irq_bitmask;
++}ifx_msi_irq_t;
++
++static ifx_msi_irq_t msi_irqs[IFX_PCIE_CORE_NR] = {
++ {
++ .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI_PIC_REG_BASE,
++ .msi_phy_base = PCIE_MSI_PHY_BASE,
++ .msi_irq_idx = {
++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
++ {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
++ {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
++ },
++ .msi_free_irq_bitmask = 0,
++ .msi_multiple_irq_bitmask= 0,
++ },
++#ifdef CONFIG_IFX_PCIE_2ND_CORE
++ {
++ .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI1_PIC_REG_BASE,
++ .msi_phy_base = PCIE1_MSI_PHY_BASE,
++ .msi_irq_idx = {
++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
++ {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
++ {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
++ },
++ .msi_free_irq_bitmask = 0,
++ .msi_multiple_irq_bitmask= 0,
++
++ },
++#endif /* CONFIG_IFX_PCIE_2ND_CORE */
++};
++
++/*
++ * This lock controls updates to msi_free_irq_bitmask,
++ * msi_multiple_irq_bitmask and pic register settting
++ */
++static DEFINE_SPINLOCK(ifx_pcie_msi_lock);
++
++void pcie_msi_pic_init(int pcie_port)
++{
++ spin_lock(&ifx_pcie_msi_lock);
++ msi_irqs[pcie_port].msi_pic_p->pic_endian = IFX_MSI_PIC_BIG_ENDIAN;
++ spin_unlock(&ifx_pcie_msi_lock);
++}
++
++/**
++ * \fn int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
++ * \brief Called when a driver request MSI interrupts instead of the
++ * legacy INT A-D. This routine will allocate multiple interrupts
++ * for MSI devices that support them. A device can override this by
++ * programming the MSI control bits [6:4] before calling
++ * pci_enable_msi().
++ *
++ * \param[in] pdev Device requesting MSI interrupts
++ * \param[in] desc MSI descriptor
++ *
++ * \return -EINVAL Invalid pcie root port or invalid msi bit
++ * \return 0 OK
++ * \ingroup IFX_PCIE_MSI
++ */
++int
++arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
++{
++ int irq, pos;
++ u16 control;
++ int irq_idx;
++ int irq_step;
++ int configured_private_bits;
++ int request_private_bits;
++ struct msi_msg msg;
++ u16 search_mask;
++ struct ifx_pci_controller *ctrl = pdev->bus->sysdata;
++ int pcie_port = ctrl->port;
++
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s %s enter\n", __func__, pci_name(pdev));
++
++ /* XXX, skip RC MSI itself */
++ if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s RC itself doesn't use MSI interrupt\n", __func__);
++ return -EINVAL;
++ }
++
++ /*
++ * Read the MSI config to figure out how many IRQs this device
++ * wants. Most devices only want 1, which will give
++ * configured_private_bits and request_private_bits equal 0.
++ */
++ pci_read_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &control);
++
++ /*
++ * If the number of private bits has been configured then use
++ * that value instead of the requested number. This gives the
++ * driver the chance to override the number of interrupts
++ * before calling pci_enable_msi().
++ */
++ configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4;
++ if (configured_private_bits == 0) {
++ /* Nothing is configured, so use the hardware requested size */
++ request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1;
++ }
++ else {
++ /*
++ * Use the number of configured bits, assuming the
++ * driver wanted to override the hardware request
++ * value.
++ */
++ request_private_bits = configured_private_bits;
++ }
++
++ /*
++ * The PCI 2.3 spec mandates that there are at most 32
++ * interrupts. If this device asks for more, only give it one.
++ */
++ if (request_private_bits > 5) {
++ request_private_bits = 0;
++ }
++again:
++ /*
++ * The IRQs have to be aligned on a power of two based on the
++ * number being requested.
++ */
++ irq_step = (1 << request_private_bits);
++
++ /* Mask with one bit for each IRQ */
++ search_mask = (1 << irq_step) - 1;
++
++ /*
++ * We're going to search msi_free_irq_bitmask_lock for zero
++ * bits. This represents an MSI interrupt number that isn't in
++ * use.
++ */
++ spin_lock(&ifx_pcie_msi_lock);
++ for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos += irq_step) {
++ if ((msi_irqs[pcie_port].msi_free_irq_bitmask & (search_mask << pos)) == 0) {
++ msi_irqs[pcie_port].msi_free_irq_bitmask |= search_mask << pos;
++ msi_irqs[pcie_port].msi_multiple_irq_bitmask |= (search_mask >> 1) << pos;
++ break;
++ }
++ }
++ spin_unlock(&ifx_pcie_msi_lock);
++
++ /* Make sure the search for available interrupts didn't fail */
++ if (pos >= IFX_MSI_IRQ_NUM) {
++ if (request_private_bits) {
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s: Unable to find %d free "
++ "interrupts, trying just one", __func__, 1 << request_private_bits);
++ request_private_bits = 0;
++ goto again;
++ }
++ else {
++ printk(KERN_ERR "%s: Unable to find a free MSI interrupt\n", __func__);
++ return -EINVAL;
++ }
++ }
++ irq = msi_irqs[pcie_port].msi_irq_idx[pos].irq;
++ irq_idx = msi_irqs[pcie_port].msi_irq_idx[pos].idx;
++
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "pos %d, irq %d irq_idx %d\n", pos, irq, irq_idx);
++
++ /*
++ * Initialize MSI. This has to match the memory-write endianess from the device
++ * Address bits [23:12]
++ */
++ spin_lock(&ifx_pcie_msi_lock);
++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] = SM(irq_idx, IFX_MSI_PIC_INT_LINE) |
++ SM((msi_irqs[pcie_port].msi_phy_base >> 12), IFX_MSI_PIC_MSG_ADDR) |
++ SM((1 << pos), IFX_MSI_PIC_MSG_DATA);
++
++ /* Enable this entry */
++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~IFX_MSI_PCI_INT_DISABLE;
++ spin_unlock(&ifx_pcie_msi_lock);
++
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "pic_table[%d]: 0x%08x\n",
++ pos, msi_irqs[pcie_port].msi_pic_p->pic_table[pos]);
++
++ /* Update the number of IRQs the device has available to it */
++ control &= ~PCI_MSI_FLAGS_QSIZE;
++ control |= (request_private_bits << 4);
++ pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, control);
++
++ set_irq_msi(irq, desc);
++ msg.address_hi = 0x0;
++ msg.address_lo = msi_irqs[pcie_port].msi_phy_base;
++ msg.data = SM((1 << pos), IFX_MSI_PIC_MSG_DATA);
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "msi_data: pos %d 0x%08x\n", pos, msg.data);
++
++ write_msi_msg(irq, &msg);
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__);
++ return 0;
++}
++
++static int
++pcie_msi_irq_to_port(unsigned int irq, int *port)
++{
++ int ret = 0;
++
++ if (irq == IFX_PCIE_MSI_IR0 || irq == IFX_PCIE_MSI_IR1 ||
++ irq == IFX_PCIE_MSI_IR2 || irq == IFX_PCIE_MSI_IR3) {
++ *port = IFX_PCIE_PORT0;
++ }
++#ifdef CONFIG_IFX_PCIE_2ND_CORE
++ else if (irq == IFX_PCIE1_MSI_IR0 || irq == IFX_PCIE1_MSI_IR1 ||
++ irq == IFX_PCIE1_MSI_IR2 || irq == IFX_PCIE1_MSI_IR3) {
++ *port = IFX_PCIE_PORT1;
++ }
++#endif /* CONFIG_IFX_PCIE_2ND_CORE */
++ else {
++ printk(KERN_ERR "%s: Attempted to teardown illegal "
++ "MSI interrupt (%d)\n", __func__, irq);
++ ret = -EINVAL;
++ }
++ return ret;
++}
++
++/**
++ * \fn void arch_teardown_msi_irq(unsigned int irq)
++ * \brief Called when a device no longer needs its MSI interrupts. All
++ * MSI interrupts for the device are freed.
++ *
++ * \param irq The devices first irq number. There may be multple in sequence.
++ * \return none
++ * \ingroup IFX_PCIE_MSI
++ */
++void
++arch_teardown_msi_irq(unsigned int irq)
++{
++ int pos;
++ int number_irqs;
++ u16 bitmask;
++ int pcie_port;
++
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s enter\n", __func__);
++
++ BUG_ON(irq > INT_NUM_IM4_IRL31);
++
++ if (pcie_msi_irq_to_port(irq, &pcie_port) != 0) {
++ return;
++ }
++
++ /* Shift the mask to the correct bit location, not always correct
++ * Probally, the first match will be chosen.
++ */
++ for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos++) {
++ if ((msi_irqs[pcie_port].msi_irq_idx[pos].irq == irq)
++ && (msi_irqs[pcie_port].msi_free_irq_bitmask & ( 1 << pos))) {
++ break;
++ }
++ }
++ if (pos >= IFX_MSI_IRQ_NUM) {
++ printk(KERN_ERR "%s: Unable to find a matched MSI interrupt\n", __func__);
++ return;
++ }
++ spin_lock(&ifx_pcie_msi_lock);
++ /* Disable this entry */
++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] |= IFX_MSI_PCI_INT_DISABLE;
++ msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~(IFX_MSI_PIC_INT_LINE | IFX_MSI_PIC_MSG_ADDR | IFX_MSI_PIC_MSG_DATA);
++ spin_unlock(&ifx_pcie_msi_lock);
++ /*
++ * Count the number of IRQs we need to free by looking at the
++ * msi_multiple_irq_bitmask. Each bit set means that the next
++ * IRQ is also owned by this device.
++ */
++ number_irqs = 0;
++ while (((pos + number_irqs) < IFX_MSI_IRQ_NUM) &&
++ (msi_irqs[pcie_port].msi_multiple_irq_bitmask & (1 << (pos + number_irqs)))) {
++ number_irqs++;
++ }
++ number_irqs++;
++
++ /* Mask with one bit for each IRQ */
++ bitmask = (1 << number_irqs) - 1;
++
++ bitmask <<= pos;
++ if ((msi_irqs[pcie_port].msi_free_irq_bitmask & bitmask) != bitmask) {
++ printk(KERN_ERR "%s: Attempted to teardown MSI "
++ "interrupt (%d) not in use\n", __func__, irq);
++ return;
++ }
++ /* Checks are done, update the in use bitmask */
++ spin_lock(&ifx_pcie_msi_lock);
++ msi_irqs[pcie_port].msi_free_irq_bitmask &= ~bitmask;
++ msi_irqs[pcie_port].msi_multiple_irq_bitmask &= ~(bitmask >> 1);
++ spin_unlock(&ifx_pcie_msi_lock);
++ IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__);
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Chuanhua.Lei@infineon.com");
++MODULE_SUPPORTED_DEVICE("Infineon PCIe IP builtin MSI PIC module");
++MODULE_DESCRIPTION("Infineon PCIe IP builtin MSI PIC driver");
++
+diff --git a/arch/mips/pci/ifxmips_pcie_phy.c b/arch/mips/pci/ifxmips_pcie_phy.c
+new file mode 100644
+index 0000000..a4171a7
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie_phy.c
+@@ -0,0 +1,478 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_pcie_phy.c
++** PROJECT : IFX UEIP for VRX200
++** MODULES : PCIe PHY sub module
++**
++** DATE : 14 May 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIe Root Complex Driver
++** COPYRIGHT : Copyright (c) 2009
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++** HISTORY
++** $Version $Date $Author $Comment
++** 0.0.1 14 May,2009 Lei Chuanhua Initial version
++*******************************************************************************/
++/*!
++ \file ifxmips_pcie_phy.c
++ \ingroup IFX_PCIE
++ \brief PCIe PHY PLL register programming source file
++*/
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <asm/paccess.h>
++#include <linux/delay.h>
++
++#include "ifxmips_pcie_reg.h"
++#include "ifxmips_pcie.h"
++
++/* PCIe PDI only supports 16 bit operation */
++
++#define IFX_PCIE_PHY_REG_WRITE16(__addr, __data) \
++ ((*(volatile u16 *) (__addr)) = (__data))
++
++#define IFX_PCIE_PHY_REG_READ16(__addr) \
++ (*(volatile u16 *) (__addr))
++
++#define IFX_PCIE_PHY_REG16(__addr) \
++ (*(volatile u16 *) (__addr))
++
++#define IFX_PCIE_PHY_REG(__reg, __value, __mask) do { \
++ u16 read_data; \
++ u16 write_data; \
++ read_data = IFX_PCIE_PHY_REG_READ16((__reg)); \
++ write_data = (read_data & ((u16)~(__mask))) | (((u16)(__value)) & ((u16)(__mask)));\
++ IFX_PCIE_PHY_REG_WRITE16((__reg), write_data); \
++} while (0)
++
++#define IFX_PCIE_PLL_TIMEOUT 1000 /* Tunnable */
++
++//#define IFX_PCI_PHY_REG_DUMP
++
++#ifdef IFX_PCI_PHY_REG_DUMP
++static void
++pcie_phy_reg_dump(int pcie_port)
++{
++ printk("PLL REGFILE\n");
++ printk("PCIE_PHY_PLL_CTRL1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_CTRL1(pcie_port)));
++ printk("PCIE_PHY_PLL_CTRL2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_CTRL2(pcie_port)));
++ printk("PCIE_PHY_PLL_CTRL3 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_CTRL3(pcie_port)));
++ printk("PCIE_PHY_PLL_CTRL4 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_CTRL4(pcie_port)));
++ printk("PCIE_PHY_PLL_CTRL5 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_CTRL5(pcie_port)));
++ printk("PCIE_PHY_PLL_CTRL6 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_CTRL6(pcie_port)));
++ printk("PCIE_PHY_PLL_CTRL7 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_CTRL7(pcie_port)));
++ printk("PCIE_PHY_PLL_A_CTRL1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_A_CTRL1(pcie_port)));
++ printk("PCIE_PHY_PLL_A_CTRL2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_A_CTRL2(pcie_port)));
++ printk("PCIE_PHY_PLL_A_CTRL3 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_A_CTRL3(pcie_port)));
++ printk("PCIE_PHY_PLL_STATUS 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_STATUS(pcie_port)));
++
++ printk("TX1 REGFILE\n");
++ printk("PCIE_PHY_TX1_CTRL1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX1_CTRL1(pcie_port)));
++ printk("PCIE_PHY_TX1_CTRL2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX1_CTRL2(pcie_port)));
++ printk("PCIE_PHY_TX1_CTRL3 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX1_CTRL3(pcie_port)));
++ printk("PCIE_PHY_TX1_A_CTRL1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX1_A_CTRL1(pcie_port)));
++ printk("PCIE_PHY_TX1_A_CTRL2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX1_A_CTRL2(pcie_port)));
++ printk("PCIE_PHY_TX1_MOD1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX1_MOD1(pcie_port)));
++ printk("PCIE_PHY_TX1_MOD2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX1_MOD2(pcie_port)));
++ printk("PCIE_PHY_TX1_MOD3 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX1_MOD3(pcie_port)));
++
++ printk("TX2 REGFILE\n");
++ printk("PCIE_PHY_TX2_CTRL1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX2_CTRL1(pcie_port)));
++ printk("PCIE_PHY_TX2_CTRL2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX2_CTRL2(pcie_port)));
++ printk("PCIE_PHY_TX2_A_CTRL1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX2_A_CTRL1(pcie_port)));
++ printk("PCIE_PHY_TX2_A_CTRL2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX2_A_CTRL2(pcie_port)));
++ printk("PCIE_PHY_TX2_MOD1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX2_MOD1(pcie_port)));
++ printk("PCIE_PHY_TX2_MOD2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX2_MOD2(pcie_port)));
++ printk("PCIE_PHY_TX2_MOD3 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_TX2_MOD3(pcie_port)));
++
++ printk("RX1 REGFILE\n");
++ printk("PCIE_PHY_RX1_CTRL1 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_RX1_CTRL1(pcie_port)));
++ printk("PCIE_PHY_RX1_CTRL2 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_RX1_CTRL2(pcie_port)));
++ printk("PCIE_PHY_RX1_CDR 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_RX1_CDR(pcie_port)));
++ printk("PCIE_PHY_RX1_EI 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_RX1_EI(pcie_port)));
++ printk("PCIE_PHY_RX1_A_CTRL 0x%04x\n", IFX_PCIE_PHY_REG16(PCIE_PHY_RX1_A_CTRL(pcie_port)));
++}
++#endif /* IFX_PCI_PHY_REG_DUMP */
++
++static void
++pcie_phy_comm_setup(int pcie_port)
++{
++ /* PLL Setting */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF);
++
++ /* increase the bias reference voltage */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF);
++
++ /* Endcnt */
++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF);
++
++ /* force */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008);
++
++ /* predrv_ser_en */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF);
++
++ /* ctrl_lim */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF);
++
++ /* ctrl */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00);
++
++ /* predrv_ser_en */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00);
++
++ /* RTERM*/
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF);
++
++ /* Improved 100MHz clock output */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF);
++
++ /* Reduced CDR BW to avoid glitches */
++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF);
++}
++
++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE
++static void
++pcie_phy_36mhz_mode_setup(int pcie_port)
++{
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port);
++#ifdef IFX_PCI_PHY_REG_DUMP
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "Initial PHY register dump\n");
++ pcie_phy_reg_dump(pcie_port);
++#endif
++
++ /* en_ext_mmd_div_ratio */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002);
++
++ /* ext_mmd_div_ratio*/
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070);
++
++ /* pll_ensdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200);
++
++ /* en_const_sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100);
++
++ /* mmd */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000);
++
++ /* lf_mode */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000);
++
++ /* const_sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF);
++
++ /* const sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF);
++
++ /* pllmod */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF);
++
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port);
++}
++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */
++
++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE
++static void
++pcie_phy_36mhz_ssc_mode_setup(int pcie_port)
++{
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port);
++#ifdef IFX_PCI_PHY_REG_DUMP
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "Initial PHY register dump\n");
++ pcie_phy_reg_dump(pcie_port);
++#endif
++
++ /* PLL Setting */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL1(pcie_port), 0x120e, 0xFFFF);
++
++ /* Increase the bias reference voltage */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x39D7, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x0900, 0xFFFF);
++
++ /* Endcnt */
++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_EI(pcie_port), 0x0004, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_A_CTRL(pcie_port), 0x6803, 0xFFFF);
++
++ /* Force */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0008, 0x0008);
++
++ /* Predrv_ser_en */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL2(pcie_port), 0x0706, 0xFFFF);
++
++ /* ctrl_lim */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL3(pcie_port), 0x1FFF, 0xFFFF);
++
++ /* ctrl */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_A_CTRL1(pcie_port), 0x0800, 0xFF00);
++
++ /* predrv_ser_en */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4702, 0x7F00);
++
++ /* RTERM*/
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL2(pcie_port), 0x2e00, 0xFFFF);
++
++ /* en_ext_mmd_div_ratio */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002);
++
++ /* ext_mmd_div_ratio*/
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070);
++
++ /* pll_ensdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0400, 0x0400);
++
++ /* en_const_sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200);
++
++ /* mmd */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000);
++
++ /* lf_mode */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000);
++
++ /* const_sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF);
++
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0100);
++ /* const sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF);
++
++ /* pllmod */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1c72, 0xFFFF);
++
++ /* improved 100MHz clock output */
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL2(pcie_port), 0x3096, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_A_CTRL2(pcie_port), 0x4707, 0xFFFF);
++
++ /* reduced CDR BW to avoid glitches */
++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CDR(pcie_port), 0x0235, 0xFFFF);
++
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port);
++}
++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE */
++
++#ifdef CONFIG_IFX_PCIE_PHY_25MHZ_MODE
++static void
++pcie_phy_25mhz_mode_setup(int pcie_port)
++{
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port);
++#ifdef IFX_PCI_PHY_REG_DUMP
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "Initial PHY register dump\n");
++ pcie_phy_reg_dump(pcie_port);
++#endif
++ /* en_const_sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100);
++
++ /* pll_ensdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0000, 0x0200);
++
++ /* en_ext_mmd_div_ratio*/
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0002, 0x0002);
++
++ /* ext_mmd_div_ratio*/
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0040, 0x0070);
++
++ /* mmd */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x6000, 0xe000);
++
++ /* lf_mode */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x4000, 0x4000);
++
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port);
++}
++#endif /* CONFIG_IFX_PCIE_PHY_25MHZ_MODE */
++
++#ifdef CONFIG_IFX_PCIE_PHY_100MHZ_MODE
++static void
++pcie_phy_100mhz_mode_setup(int pcie_port)
++{
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d enter\n", __func__, pcie_port);
++#ifdef IFX_PCI_PHY_REG_DUMP
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "Initial PHY register dump\n");
++ pcie_phy_reg_dump(pcie_port);
++#endif
++ /* en_ext_mmd_div_ratio */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0002);
++
++ /* ext_mmd_div_ratio*/
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL3(pcie_port), 0x0000, 0x0070);
++
++ /* pll_ensdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0200, 0x0200);
++
++ /* en_const_sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x0100, 0x0100);
++
++ /* mmd */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL3(pcie_port), 0x2000, 0xe000);
++
++ /* lf_mode */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_A_CTRL2(pcie_port), 0x0000, 0x4000);
++
++ /* const_sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL1(pcie_port), 0x38e4, 0xFFFF);
++
++ /* const sdm */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL2(pcie_port), 0x00ee, 0x00FF);
++
++ /* pllmod */
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL7(pcie_port), 0x0002, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL6(pcie_port), 0x3a04, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL5(pcie_port), 0xfae3, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_PLL_CTRL4(pcie_port), 0x1b72, 0xFFFF);
++
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "%s pcie_port %d exit\n", __func__, pcie_port);
++}
++#endif /* CONFIG_IFX_PCIE_PHY_100MHZ_MODE */
++
++static int
++pcie_phy_wait_startup_ready(int pcie_port)
++{
++ int i;
++
++ for (i = 0; i < IFX_PCIE_PLL_TIMEOUT; i++) {
++ if ((IFX_PCIE_PHY_REG16(PCIE_PHY_PLL_STATUS(pcie_port)) & 0x0040) != 0) {
++ break;
++ }
++ udelay(10);
++ }
++ if (i >= IFX_PCIE_PLL_TIMEOUT) {
++ printk(KERN_ERR "%s PLL Link timeout\n", __func__);
++ return -1;
++ }
++ return 0;
++}
++
++static void
++pcie_phy_load_enable(int pcie_port, int slice)
++{
++ /* Set the load_en of tx/rx slice to '1' */
++ switch (slice) {
++ case 1:
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0010, 0x0010);
++ break;
++ case 2:
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0010, 0x0010);
++ break;
++ case 3:
++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0002, 0x0002);
++ break;
++ }
++}
++
++static void
++pcie_phy_load_disable(int pcie_port, int slice)
++{
++ /* set the load_en of tx/rx slice to '0' */
++ switch (slice) {
++ case 1:
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_CTRL1(pcie_port), 0x0000, 0x0010);
++ break;
++ case 2:
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_CTRL1(pcie_port), 0x0000, 0x0010);
++ break;
++ case 3:
++ IFX_PCIE_PHY_REG(PCIE_PHY_RX1_CTRL1(pcie_port), 0x0000, 0x0002);
++ break;
++ }
++}
++
++static void
++pcie_phy_load_war(int pcie_port)
++{
++ int slice;
++
++ for (slice = 1; slice < 4; slice++) {
++ pcie_phy_load_enable(pcie_port, slice);
++ udelay(1);
++ pcie_phy_load_disable(pcie_port, slice);
++ }
++}
++
++static void
++pcie_phy_tx2_modulation(int pcie_port)
++{
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD1(pcie_port), 0x1FFE, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD2(pcie_port), 0xFFFE, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0601, 0xFFFF);
++ mdelay(1);
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX2_MOD3(pcie_port), 0x0001, 0xFFFF);
++}
++
++static void
++pcie_phy_tx1_modulation(int pcie_port)
++{
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD1(pcie_port), 0x1FFE, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD2(pcie_port), 0xFFFE, 0xFFFF);
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0601, 0xFFFF);
++ mdelay(1);
++ IFX_PCIE_PHY_REG(PCIE_PHY_TX1_MOD3(pcie_port), 0x0001, 0xFFFF);
++}
++
++static void
++pcie_phy_tx_modulation_war(int pcie_port)
++{
++ int i;
++
++#define PCIE_PHY_MODULATION_NUM 5
++ for (i = 0; i < PCIE_PHY_MODULATION_NUM; i++) {
++ pcie_phy_tx2_modulation(pcie_port);
++ pcie_phy_tx1_modulation(pcie_port);
++ }
++#undef PCIE_PHY_MODULATION_NUM
++}
++
++void
++pcie_phy_clock_mode_setup(int pcie_port)
++{
++ pcie_pdi_big_endian(pcie_port);
++
++ /* Enable PDI to access PCIe PHY register */
++ pcie_pdi_pmu_enable(pcie_port);
++
++ /* Configure PLL and PHY clock */
++ pcie_phy_comm_setup(pcie_port);
++
++#ifdef CONFIG_IFX_PCIE_PHY_36MHZ_MODE
++ pcie_phy_36mhz_mode_setup(pcie_port);
++#elif defined(CONFIG_IFX_PCIE_PHY_36MHZ_SSC_MODE)
++ pcie_phy_36mhz_ssc_mode_setup(pcie_port);
++#elif defined(CONFIG_IFX_PCIE_PHY_25MHZ_MODE)
++ pcie_phy_25mhz_mode_setup(pcie_port);
++#elif defined (CONFIG_IFX_PCIE_PHY_100MHZ_MODE)
++ pcie_phy_100mhz_mode_setup(pcie_port);
++#else
++ #error "PCIE PHY Clock Mode must be chosen first!!!!"
++#endif /* CONFIG_IFX_PCIE_PHY_36MHZ_MODE */
++
++ /* Enable PCIe PHY and make PLL setting take effect */
++ pcie_phy_pmu_enable(pcie_port);
++
++ /* Check if we are in startup_ready status */
++ pcie_phy_wait_startup_ready(pcie_port);
++
++ pcie_phy_load_war(pcie_port);
++
++ /* Apply TX modulation workarounds */
++ pcie_phy_tx_modulation_war(pcie_port);
++
++#ifdef IFX_PCI_PHY_REG_DUMP
++ IFX_PCIE_PRINT(PCIE_MSG_PHY, "Modified PHY register dump\n");
++ pcie_phy_reg_dump(pcie_port);
++#endif
++}
++
+diff --git a/arch/mips/pci/ifxmips_pcie_pm.c b/arch/mips/pci/ifxmips_pcie_pm.c
+new file mode 100644
+index 0000000..a10ecad
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie_pm.c
+@@ -0,0 +1,176 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_pcie_pm.c
++** PROJECT : IFX UEIP
++** MODULES : PCIE Root Complex Driver
++**
++** DATE : 21 Dec 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIE Root Complex Driver Power Managment
++** COPYRIGHT : Copyright (c) 2009
++** Lantiq Deutschland GmbH
++** Am Campeon 3, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** HISTORY
++** $Date $Author $Comment
++** 21 Dec,2009 Lei Chuanhua First UEIP release
++*******************************************************************************/
++/*!
++ \defgroup IFX_PCIE_PM Power Management functions
++ \ingroup IFX_PCIE
++ \brief IFX PCIE Root Complex Driver power management functions
++*/
++
++/*!
++ \file ifxmips_pcie_pm.c
++ \ingroup IFX_PCIE
++ \brief source file for PCIE Root Complex Driver Power Management
++*/
++
++#ifndef EXPORT_SYMTAB
++#define EXPORT_SYMTAB
++#endif
++#ifndef AUTOCONF_INCLUDED
++#include <linux/config.h>
++#endif /* AUTOCONF_INCLUDED */
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <asm/system.h>
++
++/* Project header */
++#include <asm/ifx/ifx_types.h>
++#include <asm/ifx/ifx_regs.h>
++#include <asm/ifx/common_routines.h>
++#include <asm/ifx/ifx_pmcu.h>
++#include "ifxmips_pcie_pm.h"
++
++/**
++ * \fn static IFX_PMCU_RETURN_t ifx_pcie_pmcu_state_change(IFX_PMCU_STATE_t pmcuState)
++ * \brief the callback function to request pmcu state in the power management hardware-dependent module
++ *
++ * \param pmcuState This parameter is a PMCU state.
++ *
++ * \return IFX_PMCU_RETURN_SUCCESS Set Power State successfully
++ * \return IFX_PMCU_RETURN_ERROR Failed to set power state.
++ * \return IFX_PMCU_RETURN_DENIED Not allowed to operate power state
++ * \ingroup IFX_PCIE_PM
++ */
++static IFX_PMCU_RETURN_t
++ifx_pcie_pmcu_state_change(IFX_PMCU_STATE_t pmcuState)
++{
++ switch(pmcuState)
++ {
++ case IFX_PMCU_STATE_D0:
++ return IFX_PMCU_RETURN_SUCCESS;
++ case IFX_PMCU_STATE_D1: // Not Applicable
++ return IFX_PMCU_RETURN_DENIED;
++ case IFX_PMCU_STATE_D2: // Not Applicable
++ return IFX_PMCU_RETURN_DENIED;
++ case IFX_PMCU_STATE_D3: // Module clock gating and Power gating
++ return IFX_PMCU_RETURN_SUCCESS;
++ default:
++ return IFX_PMCU_RETURN_DENIED;
++ }
++}
++
++/**
++ * \fn static IFX_PMCU_RETURN_t ifx_pcie_pmcu_state_get(IFX_PMCU_STATE_t *pmcuState)
++ * \brief the callback function to get pmcu state in the power management hardware-dependent module
++
++ * \param pmcuState Pointer to return power state.
++ *
++ * \return IFX_PMCU_RETURN_SUCCESS Set Power State successfully
++ * \return IFX_PMCU_RETURN_ERROR Failed to set power state.
++ * \return IFX_PMCU_RETURN_DENIED Not allowed to operate power state
++ * \ingroup IFX_PCIE_PM
++ */
++static IFX_PMCU_RETURN_t
++ifx_pcie_pmcu_state_get(IFX_PMCU_STATE_t *pmcuState)
++{
++ return IFX_PMCU_RETURN_SUCCESS;
++}
++
++/**
++ * \fn IFX_PMCU_RETURN_t ifx_pcie_pmcu_prechange(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState)
++ * \brief Apply all callbacks registered to be executed before a state change for pmcuModule
++ *
++ * \param pmcuModule Module
++ * \param newState New state
++ * \param oldState Old state
++ * \return IFX_PMCU_RETURN_SUCCESS Set Power State successfully
++ * \return IFX_PMCU_RETURN_ERROR Failed to set power state.
++ * \ingroup IFX_PCIE_PM
++ */
++static IFX_PMCU_RETURN_t
++ifx_pcie_pmcu_prechange(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState)
++{
++ return IFX_PMCU_RETURN_SUCCESS;
++}
++
++/**
++ * \fn IFX_PMCU_RETURN_t ifx_pcie_pmcu_postchange(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState)
++ * \brief Apply all callbacks registered to be executed before a state change for pmcuModule
++ *
++ * \param pmcuModule Module
++ * \param newState New state
++ * \param oldState Old state
++ * \return IFX_PMCU_RETURN_SUCCESS Set Power State successfully
++ * \return IFX_PMCU_RETURN_ERROR Failed to set power state.
++ * \ingroup IFX_PCIE_PM
++ */
++static IFX_PMCU_RETURN_t
++ifx_pcie_pmcu_postchange(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState)
++{
++ return IFX_PMCU_RETURN_SUCCESS;
++}
++
++/**
++ * \fn static void ifx_pcie_pmcu_init(void)
++ * \brief Register with central PMCU module
++ * \return none
++ * \ingroup IFX_PCIE_PM
++ */
++void
++ifx_pcie_pmcu_init(void)
++{
++ IFX_PMCU_REGISTER_t pmcuRegister;
++
++ /* XXX, hook driver context */
++
++ /* State function register */
++ memset(&pmcuRegister, 0, sizeof(IFX_PMCU_REGISTER_t));
++ pmcuRegister.pmcuModule = IFX_PMCU_MODULE_PCIE;
++ pmcuRegister.pmcuModuleNr = 0;
++ pmcuRegister.ifx_pmcu_state_change = ifx_pcie_pmcu_state_change;
++ pmcuRegister.ifx_pmcu_state_get = ifx_pcie_pmcu_state_get;
++ pmcuRegister.pre = ifx_pcie_pmcu_prechange;
++ pmcuRegister.post= ifx_pcie_pmcu_postchange;
++ ifx_pmcu_register(&pmcuRegister);
++}
++
++/**
++ * \fn static void ifx_pcie_pmcu_exit(void)
++ * \brief Unregister with central PMCU module
++ *
++ * \return none
++ * \ingroup IFX_PCIE_PM
++ */
++void
++ifx_pcie_pmcu_exit(void)
++{
++ IFX_PMCU_REGISTER_t pmcuUnRegister;
++
++ /* XXX, hook driver context */
++
++ pmcuUnRegister.pmcuModule = IFX_PMCU_MODULE_PCIE;
++ pmcuUnRegister.pmcuModuleNr = 0;
++ ifx_pmcu_unregister(&pmcuUnRegister);
++}
++
+diff --git a/arch/mips/pci/ifxmips_pcie_pm.h b/arch/mips/pci/ifxmips_pcie_pm.h
+new file mode 100644
+index 0000000..6ece20d
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie_pm.h
+@@ -0,0 +1,36 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_pcie_pm.h
++** PROJECT : IFX UEIP
++** MODULES : PCIe Root Complex Driver
++**
++** DATE : 21 Dec 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIe Root Complex Driver Power Managment
++** COPYRIGHT : Copyright (c) 2009
++** Lantiq Deutschland GmbH
++** Am Campeon 3, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** HISTORY
++** $Date $Author $Comment
++** 21 Dec,2009 Lei Chuanhua First UEIP release
++*******************************************************************************/
++/*!
++ \file ifxmips_pcie_pm.h
++ \ingroup IFX_PCIE
++ \brief header file for PCIe Root Complex Driver Power Management
++*/
++
++#ifndef IFXMIPS_PCIE_PM_H
++#define IFXMIPS_PCIE_PM_H
++
++void ifx_pcie_pmcu_init(void);
++void ifx_pcie_pmcu_exit(void);
++
++#endif /* IFXMIPS_PCIE_PM_H */
++
+diff --git a/arch/mips/pci/ifxmips_pcie_reg.h b/arch/mips/pci/ifxmips_pcie_reg.h
+new file mode 100644
+index 0000000..e7e4b6c
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie_reg.h
+@@ -0,0 +1,1001 @@
++/******************************************************************************
++**
++** FILE NAME : ifxmips_pcie_reg.h
++** PROJECT : IFX UEIP for VRX200
++** MODULES : PCIe module
++**
++** DATE : 02 Mar 2009
++** AUTHOR : Lei Chuanhua
++** DESCRIPTION : PCIe Root Complex Driver
++** COPYRIGHT : Copyright (c) 2009
++** Infineon Technologies AG
++** Am Campeon 1-12, 85579 Neubiberg, Germany
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++** HISTORY
++** $Version $Date $Author $Comment
++** 0.0.1 17 Mar,2009 Lei Chuanhua Initial version
++*******************************************************************************/
++#ifndef IFXMIPS_PCIE_REG_H
++#define IFXMIPS_PCIE_REG_H
++/*!
++ \file ifxmips_pcie_reg.h
++ \ingroup IFX_PCIE
++ \brief header file for PCIe module register definition
++*/
++/* PCIe Address Mapping Base */
++#define PCIE_CFG_PHY_BASE 0x1D000000UL
++#define PCIE_CFG_BASE (KSEG1 + PCIE_CFG_PHY_BASE)
++#define PCIE_CFG_SIZE (8 * 1024 * 1024)
++
++#define PCIE_MEM_PHY_BASE 0x1C000000UL
++#define PCIE_MEM_BASE (KSEG1 + PCIE_MEM_PHY_BASE)
++#define PCIE_MEM_SIZE (16 * 1024 * 1024)
++#define PCIE_MEM_PHY_END (PCIE_MEM_PHY_BASE + PCIE_MEM_SIZE - 1)
++
++#define PCIE_IO_PHY_BASE 0x1D800000UL
++#define PCIE_IO_BASE (KSEG1 + PCIE_IO_PHY_BASE)
++#define PCIE_IO_SIZE (1 * 1024 * 1024)
++#define PCIE_IO_PHY_END (PCIE_IO_PHY_BASE + PCIE_IO_SIZE - 1)
++
++#define PCIE_RC_CFG_BASE (KSEG1 + 0x1D900000)
++#define PCIE_APP_LOGIC_REG (KSEG1 + 0x1E100900)
++#define PCIE_MSI_PHY_BASE 0x1F600000UL
++
++#define PCIE_PDI_PHY_BASE 0x1F106800UL
++#define PCIE_PDI_BASE (KSEG1 + PCIE_PDI_PHY_BASE)
++#define PCIE_PDI_SIZE 0x400
++
++#define PCIE1_CFG_PHY_BASE 0x19000000UL
++#define PCIE1_CFG_BASE (KSEG1 + PCIE1_CFG_PHY_BASE)
++#define PCIE1_CFG_SIZE (8 * 1024 * 1024)
++
++#define PCIE1_MEM_PHY_BASE 0x18000000UL
++#define PCIE1_MEM_BASE (KSEG1 + PCIE1_MEM_PHY_BASE)
++#define PCIE1_MEM_SIZE (16 * 1024 * 1024)
++#define PCIE1_MEM_PHY_END (PCIE1_MEM_PHY_BASE + PCIE1_MEM_SIZE - 1)
++
++#define PCIE1_IO_PHY_BASE 0x19800000UL
++#define PCIE1_IO_BASE (KSEG1 + PCIE1_IO_PHY_BASE)
++#define PCIE1_IO_SIZE (1 * 1024 * 1024)
++#define PCIE1_IO_PHY_END (PCIE1_IO_PHY_BASE + PCIE1_IO_SIZE - 1)
++
++#define PCIE1_RC_CFG_BASE (KSEG1 + 0x19900000)
++#define PCIE1_APP_LOGIC_REG (KSEG1 + 0x1E100700)
++#define PCIE1_MSI_PHY_BASE 0x1F400000UL
++
++#define PCIE1_PDI_PHY_BASE 0x1F700400UL
++#define PCIE1_PDI_BASE (KSEG1 + PCIE1_PDI_PHY_BASE)
++#define PCIE1_PDI_SIZE 0x400
++
++#define PCIE_CFG_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_CFG_BASE) : (PCIE_CFG_BASE))
++#define PCIE_MEM_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_MEM_BASE) : (PCIE_MEM_BASE))
++#define PCIE_IO_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_IO_BASE) : (PCIE_IO_BASE))
++#define PCIE_MEM_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_MEM_PHY_BASE) : (PCIE_MEM_PHY_BASE))
++#define PCIE_MEM_PHY_PORT_TO_END(X) ((X) > 0 ? (PCIE1_MEM_PHY_END) : (PCIE_MEM_PHY_END))
++#define PCIE_IO_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_IO_PHY_BASE) : (PCIE_IO_PHY_BASE))
++#define PCIE_IO_PHY_PORT_TO_END(X) ((X) > 0 ? (PCIE1_IO_PHY_END) : (PCIE_IO_PHY_END))
++#define PCIE_APP_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_APP_LOGIC_REG) : (PCIE_APP_LOGIC_REG))
++#define PCIE_RC_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_RC_CFG_BASE) : (PCIE_RC_CFG_BASE))
++#define PCIE_PHY_PORT_TO_BASE(X) ((X) > 0 ? (PCIE1_PDI_BASE) : (PCIE_PDI_BASE))
++
++/* PCIe Application Logic Register */
++/* RC Core Control Register */
++#define PCIE_RC_CCR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x10)
++/* This should be enabled after initializing configuratin registers
++ * Also should check link status retraining bit
++ */
++#define PCIE_RC_CCR_LTSSM_ENABLE 0x00000001 /* Enable LTSSM to continue link establishment */
++
++/* RC Core Debug Register */
++#define PCIE_RC_DR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x14)
++#define PCIE_RC_DR_DLL_UP 0x00000001 /* Data Link Layer Up */
++#define PCIE_RC_DR_CURRENT_POWER_STATE 0x0000000E /* Current Power State */
++#define PCIE_RC_DR_CURRENT_POWER_STATE_S 1
++#define PCIE_RC_DR_CURRENT_LTSSM_STATE 0x000001F0 /* Current LTSSM State */
++#define PCIE_RC_DR_CURRENT_LTSSM_STATE_S 4
++
++#define PCIE_RC_DR_PM_DEV_STATE 0x00000E00 /* Power Management D-State */
++#define PCIE_RC_DR_PM_DEV_STATE_S 9
++
++#define PCIE_RC_DR_PM_ENABLED 0x00001000 /* Power Management State from PMU */
++#define PCIE_RC_DR_PME_EVENT_ENABLED 0x00002000 /* Power Management Event Enable State */
++#define PCIE_RC_DR_AUX_POWER_ENABLED 0x00004000 /* Auxiliary Power Enable */
++
++/* Current Power State Definition */
++enum {
++ PCIE_RC_DR_D0 = 0,
++ PCIE_RC_DR_D1, /* Not supported */
++ PCIE_RC_DR_D2, /* Not supported */
++ PCIE_RC_DR_D3,
++ PCIE_RC_DR_UN,
++};
++
++/* PHY Link Status Register */
++#define PCIE_PHY_SR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x18)
++#define PCIE_PHY_SR_PHY_LINK_UP 0x00000001 /* PHY Link Up/Down Indicator */
++
++/* Electromechanical Control Register */
++#define PCIE_EM_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x1C)
++#define PCIE_EM_CR_CARD_IS_PRESENT 0x00000001 /* Card Presence Detect State */
++#define PCIE_EM_CR_MRL_OPEN 0x00000002 /* MRL Sensor State */
++#define PCIE_EM_CR_POWER_FAULT_SET 0x00000004 /* Power Fault Detected */
++#define PCIE_EM_CR_MRL_SENSOR_SET 0x00000008 /* MRL Sensor Changed */
++#define PCIE_EM_CR_PRESENT_DETECT_SET 0x00000010 /* Card Presense Detect Changed */
++#define PCIE_EM_CR_CMD_CPL_INT_SET 0x00000020 /* Command Complete Interrupt */
++#define PCIE_EM_CR_SYS_INTERLOCK_SET 0x00000040 /* System Electromechanical IterLock Engaged */
++#define PCIE_EM_CR_ATTENTION_BUTTON_SET 0x00000080 /* Attention Button Pressed */
++
++/* Interrupt Status Register */
++#define PCIE_IR_SR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x20)
++#define PCIE_IR_SR_PME_CAUSE_MSI 0x00000002 /* MSI caused by PME */
++#define PCIE_IR_SR_HP_PME_WAKE_GEN 0x00000004 /* Hotplug PME Wake Generation */
++#define PCIE_IR_SR_HP_MSI 0x00000008 /* Hotplug MSI */
++#define PCIE_IR_SR_AHB_LU_ERR 0x00000030 /* AHB Bridge Lookup Error Signals */
++#define PCIE_IR_SR_AHB_LU_ERR_S 4
++#define PCIE_IR_SR_INT_MSG_NUM 0x00003E00 /* Interrupt Message Number */
++#define PCIE_IR_SR_INT_MSG_NUM_S 9
++#define PCIE_IR_SR_AER_INT_MSG_NUM 0xF8000000 /* Advanced Error Interrupt Message Number */
++#define PCIE_IR_SR_AER_INT_MSG_NUM_S 27
++
++/* Message Control Register */
++#define PCIE_MSG_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x30)
++#define PCIE_MSG_CR_GEN_PME_TURN_OFF_MSG 0x00000001 /* Generate PME Turn Off Message */
++#define PCIE_MSG_CR_GEN_UNLOCK_MSG 0x00000002 /* Generate Unlock Message */
++
++#define PCIE_VDM_DR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x34)
++
++/* Vendor-Defined Message Requester ID Register */
++#define PCIE_VDM_RID(X) (PCIE_APP_PORT_TO_BASE (X) + 0x38)
++#define PCIE_VDM_RID_VENROR_MSG_REQ_ID 0x0000FFFF
++#define PCIE_VDM_RID_VDMRID_S 0
++
++/* ASPM Control Register */
++#define PCIE_ASPM_CR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x40)
++#define PCIE_ASPM_CR_HOT_RST 0x00000001 /* Hot Reset Request to the downstream device */
++#define PCIE_ASPM_CR_REQ_EXIT_L1 0x00000002 /* Request to Exit L1 */
++#define PCIE_ASPM_CR_REQ_ENTER_L1 0x00000004 /* Request to Enter L1 */
++
++/* Vendor Message DW0 Register */
++#define PCIE_VM_MSG_DW0(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x50)
++#define PCIE_VM_MSG_DW0_TYPE 0x0000001F /* Message type */
++#define PCIE_VM_MSG_DW0_TYPE_S 0
++#define PCIE_VM_MSG_DW0_FORMAT 0x00000060 /* Format */
++#define PCIE_VM_MSG_DW0_FORMAT_S 5
++#define PCIE_VM_MSG_DW0_TC 0x00007000 /* Traffic Class */
++#define PCIE_VM_MSG_DW0_TC_S 12
++#define PCIE_VM_MSG_DW0_ATTR 0x000C0000 /* Atrributes */
++#define PCIE_VM_MSG_DW0_ATTR_S 18
++#define PCIE_VM_MSG_DW0_EP_TLP 0x00100000 /* Poisoned TLP */
++#define PCIE_VM_MSG_DW0_TD 0x00200000 /* TLP Digest */
++#define PCIE_VM_MSG_DW0_LEN 0xFFC00000 /* Length */
++#define PCIE_VM_MSG_DW0_LEN_S 22
++
++/* Format Definition */
++enum {
++ PCIE_VM_MSG_FORMAT_00 = 0, /* 3DW Hdr, no data*/
++ PCIE_VM_MSG_FORMAT_01, /* 4DW Hdr, no data */
++ PCIE_VM_MSG_FORMAT_10, /* 3DW Hdr, with data */
++ PCIE_VM_MSG_FORMAT_11, /* 4DW Hdr, with data */
++};
++
++/* Traffic Class Definition */
++enum {
++ PCIE_VM_MSG_TC0 = 0,
++ PCIE_VM_MSG_TC1,
++ PCIE_VM_MSG_TC2,
++ PCIE_VM_MSG_TC3,
++ PCIE_VM_MSG_TC4,
++ PCIE_VM_MSG_TC5,
++ PCIE_VM_MSG_TC6,
++ PCIE_VM_MSG_TC7,
++};
++
++/* Attributes Definition */
++enum {
++ PCIE_VM_MSG_ATTR_00 = 0, /* RO and No Snoop cleared */
++ PCIE_VM_MSG_ATTR_01, /* RO cleared , No Snoop set */
++ PCIE_VM_MSG_ATTR_10, /* RO set, No Snoop cleared*/
++ PCIE_VM_MSG_ATTR_11, /* RO and No Snoop set */
++};
++
++/* Payload Size Definition */
++#define PCIE_VM_MSG_LEN_MIN 0
++#define PCIE_VM_MSG_LEN_MAX 1024
++
++/* Vendor Message DW1 Register */
++#define PCIE_VM_MSG_DW1(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x54)
++#define PCIE_VM_MSG_DW1_FUNC_NUM 0x00000070 /* Function Number */
++#define PCIE_VM_MSG_DW1_FUNC_NUM_S 8
++#define PCIE_VM_MSG_DW1_CODE 0x00FF0000 /* Message Code */
++#define PCIE_VM_MSG_DW1_CODE_S 16
++#define PCIE_VM_MSG_DW1_TAG 0xFF000000 /* Tag */
++#define PCIE_VM_MSG_DW1_TAG_S 24
++
++#define PCIE_VM_MSG_DW2(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x58)
++#define PCIE_VM_MSG_DW3(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x5C)
++
++/* Vendor Message Request Register */
++#define PCIE_VM_MSG_REQR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x60)
++#define PCIE_VM_MSG_REQR_REQ 0x00000001 /* Vendor Message Request */
++
++
++/* AHB Slave Side Band Control Register */
++#define PCIE_AHB_SSB(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x70)
++#define PCIE_AHB_SSB_REQ_BCM 0x00000001 /* Slave Reques BCM filed */
++#define PCIE_AHB_SSB_REQ_EP 0x00000002 /* Slave Reques EP filed */
++#define PCIE_AHB_SSB_REQ_TD 0x00000004 /* Slave Reques TD filed */
++#define PCIE_AHB_SSB_REQ_ATTR 0x00000018 /* Slave Reques Attribute number */
++#define PCIE_AHB_SSB_REQ_ATTR_S 3
++#define PCIE_AHB_SSB_REQ_TC 0x000000E0 /* Slave Request TC Field */
++#define PCIE_AHB_SSB_REQ_TC_S 5
++
++/* AHB Master SideBand Ctrl Register */
++#define PCIE_AHB_MSB(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x74)
++#define PCIE_AHB_MSB_RESP_ATTR 0x00000003 /* Master Response Attribute number */
++#define PCIE_AHB_MSB_RESP_ATTR_S 0
++#define PCIE_AHB_MSB_RESP_BAD_EOT 0x00000004 /* Master Response Badeot filed */
++#define PCIE_AHB_MSB_RESP_BCM 0x00000008 /* Master Response BCM filed */
++#define PCIE_AHB_MSB_RESP_EP 0x00000010 /* Master Response EP filed */
++#define PCIE_AHB_MSB_RESP_TD 0x00000020 /* Master Response TD filed */
++#define PCIE_AHB_MSB_RESP_FUN_NUM 0x000003C0 /* Master Response Function number */
++#define PCIE_AHB_MSB_RESP_FUN_NUM_S 6
++
++/* AHB Control Register, fixed bus enumeration exception */
++#define PCIE_AHB_CTRL(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0x78)
++#define PCIE_AHB_CTRL_BUS_ERROR_SUPPRESS 0x00000001
++
++/* Interrupt Enalbe Register */
++#define PCIE_IRNEN(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xF4)
++#define PCIE_IRNCR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xF8)
++#define PCIE_IRNICR(X) (volatile u32*)(PCIE_APP_PORT_TO_BASE(X) + 0xFC)
++
++/* PCIe interrupt enable/control/capture register definition */
++#define PCIE_IRN_AER_REPORT 0x00000001 /* AER Interrupt */
++#define PCIE_IRN_AER_MSIX 0x00000002 /* Advanced Error MSI-X Interrupt */
++#define PCIE_IRN_PME 0x00000004 /* PME Interrupt */
++#define PCIE_IRN_HOTPLUG 0x00000008 /* Hotplug Interrupt */
++#define PCIE_IRN_RX_VDM_MSG 0x00000010 /* Vendor-Defined Message Interrupt */
++#define PCIE_IRN_RX_CORRECTABLE_ERR_MSG 0x00000020 /* Correctable Error Message Interrupt */
++#define PCIE_IRN_RX_NON_FATAL_ERR_MSG 0x00000040 /* Non-fatal Error Message */
++#define PCIE_IRN_RX_FATAL_ERR_MSG 0x00000080 /* Fatal Error Message */
++#define PCIE_IRN_RX_PME_MSG 0x00000100 /* PME Message Interrupt */
++#define PCIE_IRN_RX_PME_TURNOFF_ACK 0x00000200 /* PME Turnoff Ack Message Interrupt */
++#define PCIE_IRN_AHB_BR_FATAL_ERR 0x00000400 /* AHB Fatal Error Interrupt */
++#define PCIE_IRN_LINK_AUTO_BW_STATUS 0x00000800 /* Link Auto Bandwidth Status Interrupt */
++#define PCIE_IRN_BW_MGT 0x00001000 /* Bandwidth Managment Interrupt */
++#define PCIE_IRN_INTA 0x00002000 /* INTA */
++#define PCIE_IRN_INTB 0x00004000 /* INTB */
++#define PCIE_IRN_INTC 0x00008000 /* INTC */
++#define PCIE_IRN_INTD 0x00010000 /* INTD */
++#define PCIE_IRN_WAKEUP 0x00020000 /* Wake up Interrupt */
++
++#define PCIE_RC_CORE_COMBINED_INT (PCIE_IRN_AER_REPORT | PCIE_IRN_AER_MSIX | PCIE_IRN_PME | \
++ PCIE_IRN_HOTPLUG | PCIE_IRN_RX_VDM_MSG | PCIE_IRN_RX_CORRECTABLE_ERR_MSG |\
++ PCIE_IRN_RX_NON_FATAL_ERR_MSG | PCIE_IRN_RX_FATAL_ERR_MSG | \
++ PCIE_IRN_RX_PME_MSG | PCIE_IRN_RX_PME_TURNOFF_ACK | PCIE_IRN_AHB_BR_FATAL_ERR | \
++ PCIE_IRN_LINK_AUTO_BW_STATUS | PCIE_IRN_BW_MGT)
++/* PCIe RC Configuration Register */
++#define PCIE_VDID(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x00)
++
++/* Bit definition from pci_reg.h */
++#define PCIE_PCICMDSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x04)
++#define PCIE_CCRID(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x08)
++#define PCIE_CLSLTHTBR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x0C) /* EP only */
++/* BAR0, BAR1,Only necessary if the bridges implements a device-specific register set or memory buffer */
++#define PCIE_BAR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x10) /* Not used*/
++#define PCIE_BAR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x14) /* Not used */
++
++#define PCIE_BNR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x18) /* Mandatory */
++/* Bus Number Register bits */
++#define PCIE_BNR_PRIMARY_BUS_NUM 0x000000FF
++#define PCIE_BNR_PRIMARY_BUS_NUM_S 0
++#define PCIE_PNR_SECONDARY_BUS_NUM 0x0000FF00
++#define PCIE_PNR_SECONDARY_BUS_NUM_S 8
++#define PCIE_PNR_SUB_BUS_NUM 0x00FF0000
++#define PCIE_PNR_SUB_BUS_NUM_S 16
++
++/* IO Base/Limit Register bits */
++#define PCIE_IOBLSECS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x1C) /* RC only */
++#define PCIE_IOBLSECS_32BIT_IO_ADDR 0x00000001
++#define PCIE_IOBLSECS_IO_BASE_ADDR 0x000000F0
++#define PCIE_IOBLSECS_IO_BASE_ADDR_S 4
++#define PCIE_IOBLSECS_32BIT_IOLIMT 0x00000100
++#define PCIE_IOBLSECS_IO_LIMIT_ADDR 0x0000F000
++#define PCIE_IOBLSECS_IO_LIMIT_ADDR_S 12
++
++/* Non-prefetchable Memory Base/Limit Register bit */
++#define PCIE_MBML(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x20) /* RC only */
++#define PCIE_MBML_MEM_BASE_ADDR 0x0000FFF0
++#define PCIE_MBML_MEM_BASE_ADDR_S 4
++#define PCIE_MBML_MEM_LIMIT_ADDR 0xFFF00000
++#define PCIE_MBML_MEM_LIMIT_ADDR_S 20
++
++/* Prefetchable Memory Base/Limit Register bit */
++#define PCIE_PMBL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x24) /* RC only */
++#define PCIE_PMBL_64BIT_ADDR 0x00000001
++#define PCIE_PMBL_UPPER_12BIT 0x0000FFF0
++#define PCIE_PMBL_UPPER_12BIT_S 4
++#define PCIE_PMBL_E64MA 0x00010000
++#define PCIE_PMBL_END_ADDR 0xFFF00000
++#define PCIE_PMBL_END_ADDR_S 20
++#define PCIE_PMBU32(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x28) /* RC only */
++#define PCIE_PMLU32(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x2C) /* RC only */
++
++/* I/O Base/Limit Upper 16 bits register */
++#define PCIE_IO_BANDL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x30) /* RC only */
++#define PCIE_IO_BANDL_UPPER_16BIT_IO_BASE 0x0000FFFF
++#define PCIE_IO_BANDL_UPPER_16BIT_IO_BASE_S 0
++#define PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT 0xFFFF0000
++#define PCIE_IO_BANDL_UPPER_16BIT_IO_LIMIT_S 16
++
++#define PCIE_CPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x34)
++#define PCIE_EBBAR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x38)
++
++/* Interrupt and Secondary Bridge Control Register */
++#define PCIE_INTRBCTRL(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x3C)
++
++#define PCIE_INTRBCTRL_INT_LINE 0x000000FF
++#define PCIE_INTRBCTRL_INT_LINE_S 0
++#define PCIE_INTRBCTRL_INT_PIN 0x0000FF00
++#define PCIE_INTRBCTRL_INT_PIN_S 8
++#define PCIE_INTRBCTRL_PARITY_ERR_RESP_ENABLE 0x00010000 /* #PERR */
++#define PCIE_INTRBCTRL_SERR_ENABLE 0x00020000 /* #SERR */
++#define PCIE_INTRBCTRL_ISA_ENABLE 0x00040000 /* ISA enable, IO 64KB only */
++#define PCIE_INTRBCTRL_VGA_ENABLE 0x00080000 /* VGA enable */
++#define PCIE_INTRBCTRL_VGA_16BIT_DECODE 0x00100000 /* VGA 16bit decode */
++#define PCIE_INTRBCTRL_RST_SECONDARY_BUS 0x00400000 /* Secondary bus rest, hot rest, 1ms */
++/* Others are read only */
++enum {
++ PCIE_INTRBCTRL_INT_NON = 0,
++ PCIE_INTRBCTRL_INTA,
++ PCIE_INTRBCTRL_INTB,
++ PCIE_INTRBCTRL_INTC,
++ PCIE_INTRBCTRL_INTD,
++};
++
++#define PCIE_PM_CAPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x40)
++
++/* Power Management Control and Status Register */
++#define PCIE_PM_CSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x44)
++
++#define PCIE_PM_CSR_POWER_STATE 0x00000003 /* Power State */
++#define PCIE_PM_CSR_POWER_STATE_S 0
++#define PCIE_PM_CSR_SW_RST 0x00000008 /* Soft Reset Enabled */
++#define PCIE_PM_CSR_PME_ENABLE 0x00000100 /* PME Enable */
++#define PCIE_PM_CSR_PME_STATUS 0x00008000 /* PME status */
++
++/* MSI Capability Register for EP */
++#define PCIE_MCAPR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x50)
++
++#define PCIE_MCAPR_MSI_CAP_ID 0x000000FF /* MSI Capability ID */
++#define PCIE_MCAPR_MSI_CAP_ID_S 0
++#define PCIE_MCAPR_MSI_NEXT_CAP_PTR 0x0000FF00 /* Next Capability Pointer */
++#define PCIE_MCAPR_MSI_NEXT_CAP_PTR_S 8
++#define PCIE_MCAPR_MSI_ENABLE 0x00010000 /* MSI Enable */
++#define PCIE_MCAPR_MULTI_MSG_CAP 0x000E0000 /* Multiple Message Capable */
++#define PCIE_MCAPR_MULTI_MSG_CAP_S 17
++#define PCIE_MCAPR_MULTI_MSG_ENABLE 0x00700000 /* Multiple Message Enable */
++#define PCIE_MCAPR_MULTI_MSG_ENABLE_S 20
++#define PCIE_MCAPR_ADDR64_CAP 0X00800000 /* 64-bit Address Capable */
++
++/* MSI Message Address Register */
++#define PCIE_MA(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x54)
++
++#define PCIE_MA_ADDR_MASK 0xFFFFFFFC /* Message Address */
++
++/* MSI Message Upper Address Register */
++#define PCIE_MUA(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x58)
++
++/* MSI Message Data Register */
++#define PCIE_MD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x5C)
++
++#define PCIE_MD_DATA 0x0000FFFF /* Message Data */
++#define PCIE_MD_DATA_S 0
++
++/* PCI Express Capability Register */
++#define PCIE_XCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x70)
++
++#define PCIE_XCAP_ID 0x000000FF /* PCI Express Capability ID */
++#define PCIE_XCAP_ID_S 0
++#define PCIE_XCAP_NEXT_CAP 0x0000FF00 /* Next Capability Pointer */
++#define PCIE_XCAP_NEXT_CAP_S 8
++#define PCIE_XCAP_VER 0x000F0000 /* PCI Express Capability Version */
++#define PCIE_XCAP_VER_S 16
++#define PCIE_XCAP_DEV_PORT_TYPE 0x00F00000 /* Device Port Type */
++#define PCIE_XCAP_DEV_PORT_TYPE_S 20
++#define PCIE_XCAP_SLOT_IMPLEMENTED 0x01000000 /* Slot Implemented */
++#define PCIE_XCAP_MSG_INT_NUM 0x3E000000 /* Interrupt Message Number */
++#define PCIE_XCAP_MSG_INT_NUM_S 25
++
++/* Device Capability Register */
++#define PCIE_DCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x74)
++
++#define PCIE_DCAP_MAX_PAYLOAD_SIZE 0x00000007 /* Max Payload size */
++#define PCIE_DCAP_MAX_PAYLOAD_SIZE_S 0
++#define PCIE_DCAP_PHANTOM_FUNC 0x00000018 /* Phanton Function, not supported */
++#define PCIE_DCAP_PHANTOM_FUNC_S 3
++#define PCIE_DCAP_EXT_TAG 0x00000020 /* Extended Tag Field */
++#define PCIE_DCAP_EP_L0S_LATENCY 0x000001C0 /* EP L0s latency only */
++#define PCIE_DCAP_EP_L0S_LATENCY_S 6
++#define PCIE_DCAP_EP_L1_LATENCY 0x00000E00 /* EP L1 latency only */
++#define PCIE_DCAP_EP_L1_LATENCY_S 9
++#define PCIE_DCAP_ROLE_BASE_ERR_REPORT 0x00008000 /* Role Based ERR */
++
++/* Maximum payload size supported */
++enum {
++ PCIE_MAX_PAYLOAD_128 = 0,
++ PCIE_MAX_PAYLOAD_256,
++ PCIE_MAX_PAYLOAD_512,
++ PCIE_MAX_PAYLOAD_1024,
++ PCIE_MAX_PAYLOAD_2048,
++ PCIE_MAX_PAYLOAD_4096,
++};
++
++/* Device Control and Status Register */
++#define PCIE_DCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x78)
++
++#define PCIE_DCTLSTS_CORRECTABLE_ERR_EN 0x00000001 /* COR-ERR */
++#define PCIE_DCTLSTS_NONFATAL_ERR_EN 0x00000002 /* Non-fatal ERR */
++#define PCIE_DCTLSTS_FATAL_ERR_EN 0x00000004 /* Fatal ERR */
++#define PCIE_DCTLSYS_UR_REQ_EN 0x00000008 /* UR ERR */
++#define PCIE_DCTLSTS_RELAXED_ORDERING_EN 0x00000010 /* Enable relaxing ordering */
++#define PCIE_DCTLSTS_MAX_PAYLOAD_SIZE 0x000000E0 /* Max payload mask */
++#define PCIE_DCTLSTS_MAX_PAYLOAD_SIZE_S 5
++#define PCIE_DCTLSTS_EXT_TAG_EN 0x00000100 /* Extended tag field */
++#define PCIE_DCTLSTS_PHANTOM_FUNC_EN 0x00000200 /* Phantom Function Enable */
++#define PCIE_DCTLSTS_AUX_PM_EN 0x00000400 /* AUX Power PM Enable */
++#define PCIE_DCTLSTS_NO_SNOOP_EN 0x00000800 /* Enable no snoop, except root port*/
++#define PCIE_DCTLSTS_MAX_READ_SIZE 0x00007000 /* Max Read Request size*/
++#define PCIE_DCTLSTS_MAX_READ_SIZE_S 12
++#define PCIE_DCTLSTS_CORRECTABLE_ERR 0x00010000 /* COR-ERR Detected */
++#define PCIE_DCTLSTS_NONFATAL_ERR 0x00020000 /* Non-Fatal ERR Detected */
++#define PCIE_DCTLSTS_FATAL_ER 0x00040000 /* Fatal ERR Detected */
++#define PCIE_DCTLSTS_UNSUPPORTED_REQ 0x00080000 /* UR Detected */
++#define PCIE_DCTLSTS_AUX_POWER 0x00100000 /* Aux Power Detected */
++#define PCIE_DCTLSTS_TRANSACT_PENDING 0x00200000 /* Transaction pending */
++
++#define PCIE_DCTLSTS_ERR_EN (PCIE_DCTLSTS_CORRECTABLE_ERR_EN | \
++ PCIE_DCTLSTS_NONFATAL_ERR_EN | PCIE_DCTLSTS_FATAL_ERR_EN | \
++ PCIE_DCTLSYS_UR_REQ_EN)
++
++/* Link Capability Register */
++#define PCIE_LCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7C)
++#define PCIE_LCAP_MAX_LINK_SPEED 0x0000000F /* Max link speed, 0x1 by default */
++#define PCIE_LCAP_MAX_LINK_SPEED_S 0
++#define PCIE_LCAP_MAX_LENGTH_WIDTH 0x000003F0 /* Maxium Length Width */
++#define PCIE_LCAP_MAX_LENGTH_WIDTH_S 4
++#define PCIE_LCAP_ASPM_LEVEL 0x00000C00 /* Active State Link PM Support */
++#define PCIE_LCAP_ASPM_LEVEL_S 10
++#define PCIE_LCAP_L0S_EIXT_LATENCY 0x00007000 /* L0s Exit Latency */
++#define PCIE_LCAP_L0S_EIXT_LATENCY_S 12
++#define PCIE_LCAP_L1_EXIT_LATENCY 0x00038000 /* L1 Exit Latency */
++#define PCIE_LCAP_L1_EXIT_LATENCY_S 15
++#define PCIE_LCAP_CLK_PM 0x00040000 /* Clock Power Management */
++#define PCIE_LCAP_SDER 0x00080000 /* Surprise Down Error Reporting */
++#define PCIE_LCAP_DLL_ACTIVE_REPROT 0x00100000 /* Data Link Layer Active Reporting Capable */
++#define PCIE_LCAP_PORT_NUM 0xFF0000000 /* Port number */
++#define PCIE_LCAP_PORT_NUM_S 24
++
++/* Maximum Length width definition */
++#define PCIE_MAX_LENGTH_WIDTH_RES 0x00
++#define PCIE_MAX_LENGTH_WIDTH_X1 0x01 /* Default */
++#define PCIE_MAX_LENGTH_WIDTH_X2 0x02
++#define PCIE_MAX_LENGTH_WIDTH_X4 0x04
++#define PCIE_MAX_LENGTH_WIDTH_X8 0x08
++#define PCIE_MAX_LENGTH_WIDTH_X12 0x0C
++#define PCIE_MAX_LENGTH_WIDTH_X16 0x10
++#define PCIE_MAX_LENGTH_WIDTH_X32 0x20
++
++/* Active State Link PM definition */
++enum {
++ PCIE_ASPM_RES0 = 0,
++ PCIE_ASPM_L0S_ENTRY_SUPPORT, /* L0s */
++ PCIE_ASPM_RES1,
++ PCIE_ASPM_L0S_L1_ENTRY_SUPPORT, /* L0s and L1, default */
++};
++
++/* L0s Exit Latency definition */
++enum {
++ PCIE_L0S_EIXT_LATENCY_L64NS = 0, /* < 64 ns */
++ PCIE_L0S_EIXT_LATENCY_B64A128, /* > 64 ns < 128 ns */
++ PCIE_L0S_EIXT_LATENCY_B128A256, /* > 128 ns < 256 ns */
++ PCIE_L0S_EIXT_LATENCY_B256A512, /* > 256 ns < 512 ns */
++ PCIE_L0S_EIXT_LATENCY_B512TO1U, /* > 512 ns < 1 us */
++ PCIE_L0S_EIXT_LATENCY_B1A2U, /* > 1 us < 2 us */
++ PCIE_L0S_EIXT_LATENCY_B2A4U, /* > 2 us < 4 us */
++ PCIE_L0S_EIXT_LATENCY_M4US, /* > 4 us */
++};
++
++/* L1 Exit Latency definition */
++enum {
++ PCIE_L1_EXIT_LATENCY_L1US = 0, /* < 1 us */
++ PCIE_L1_EXIT_LATENCY_B1A2, /* > 1 us < 2 us */
++ PCIE_L1_EXIT_LATENCY_B2A4, /* > 2 us < 4 us */
++ PCIE_L1_EXIT_LATENCY_B4A8, /* > 4 us < 8 us */
++ PCIE_L1_EXIT_LATENCY_B8A16, /* > 8 us < 16 us */
++ PCIE_L1_EXIT_LATENCY_B16A32, /* > 16 us < 32 us */
++ PCIE_L1_EXIT_LATENCY_B32A64, /* > 32 us < 64 us */
++ PCIE_L1_EXIT_LATENCY_M64US, /* > 64 us */
++};
++
++/* Link Control and Status Register */
++#define PCIE_LCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x80)
++#define PCIE_LCTLSTS_ASPM_ENABLE 0x00000003 /* Active State Link PM Control */
++#define PCIE_LCTLSTS_ASPM_ENABLE_S 0
++#define PCIE_LCTLSTS_RCB128 0x00000008 /* Read Completion Boundary 128*/
++#define PCIE_LCTLSTS_LINK_DISABLE 0x00000010 /* Link Disable */
++#define PCIE_LCTLSTS_RETRIAN_LINK 0x00000020 /* Retrain Link */
++#define PCIE_LCTLSTS_COM_CLK_CFG 0x00000040 /* Common Clock Configuration */
++#define PCIE_LCTLSTS_EXT_SYNC 0x00000080 /* Extended Synch */
++#define PCIE_LCTLSTS_CLK_PM_EN 0x00000100 /* Enable Clock Powerm Management */
++#define PCIE_LCTLSTS_LINK_SPEED 0x000F0000 /* Link Speed */
++#define PCIE_LCTLSTS_LINK_SPEED_S 16
++#define PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH 0x03F00000 /* Negotiated Link Width */
++#define PCIE_LCTLSTS_NEGOTIATED_LINK_WIDTH_S 20
++#define PCIE_LCTLSTS_RETRAIN_PENDING 0x08000000 /* Link training is ongoing */
++#define PCIE_LCTLSTS_SLOT_CLK_CFG 0x10000000 /* Slot Clock Configuration */
++#define PCIE_LCTLSTS_DLL_ACTIVE 0x20000000 /* Data Link Layer Active */
++
++/* Slot Capabilities Register */
++#define PCIE_SLCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x84)
++
++/* Slot Capabilities */
++#define PCIE_SLCTLSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x88)
++
++/* Root Control and Capability Register */
++#define PCIE_RCTLCAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x8C)
++#define PCIE_RCTLCAP_SERR_ON_CORRECTABLE_ERR 0x00000001 /* #SERR on COR-ERR */
++#define PCIE_RCTLCAP_SERR_ON_NONFATAL_ERR 0x00000002 /* #SERR on Non-Fatal ERR */
++#define PCIE_RCTLCAP_SERR_ON_FATAL_ERR 0x00000004 /* #SERR on Fatal ERR */
++#define PCIE_RCTLCAP_PME_INT_EN 0x00000008 /* PME Interrupt Enable */
++#define PCIE_RCTLCAP_SERR_ENABLE (PCIE_RCTLCAP_SERR_ON_CORRECTABLE_ERR | \
++ PCIE_RCTLCAP_SERR_ON_NONFATAL_ERR | PCIE_RCTLCAP_SERR_ON_FATAL_ERR)
++/* Root Status Register */
++#define PCIE_RSTS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x90)
++#define PCIE_RSTS_PME_REQ_ID 0x0000FFFF /* PME Request ID */
++#define PCIE_RSTS_PME_REQ_ID_S 0
++#define PCIE_RSTS_PME_STATUS 0x00010000 /* PME Status */
++#define PCIE_RSTS_PME_PENDING 0x00020000 /* PME Pending */
++
++/* PCI Express Enhanced Capability Header */
++#define PCIE_ENHANCED_CAP(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x100)
++#define PCIE_ENHANCED_CAP_ID 0x0000FFFF /* PCI Express Extended Capability ID */
++#define PCIE_ENHANCED_CAP_ID_S 0
++#define PCIE_ENHANCED_CAP_VER 0x000F0000 /* Capability Version */
++#define PCIE_ENHANCED_CAP_VER_S 16
++#define PCIE_ENHANCED_CAP_NEXT_OFFSET 0xFFF00000 /* Next Capability Offset */
++#define PCIE_ENHANCED_CAP_NEXT_OFFSET_S 20
++
++/* Uncorrectable Error Status Register */
++#define PCIE_UES_R(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x104)
++#define PCIE_DATA_LINK_PROTOCOL_ERR 0x00000010 /* Data Link Protocol Error Status */
++#define PCIE_SURPRISE_DOWN_ERROR 0x00000020 /* Surprise Down Error Status */
++#define PCIE_POISONED_TLP 0x00001000 /* Poisoned TLP Status */
++#define PCIE_FC_PROTOCOL_ERR 0x00002000 /* Flow Control Protocol Error Status */
++#define PCIE_COMPLETION_TIMEOUT 0x00004000 /* Completion Timeout Status */
++#define PCIE_COMPLETOR_ABORT 0x00008000 /* Completer Abort Error */
++#define PCIE_UNEXPECTED_COMPLETION 0x00010000 /* Unexpected Completion Status */
++#define PCIE_RECEIVER_OVERFLOW 0x00020000 /* Receive Overflow Status */
++#define PCIE_MALFORNED_TLP 0x00040000 /* Malformed TLP Stauts */
++#define PCIE_ECRC_ERR 0x00080000 /* ECRC Error Stauts */
++#define PCIE_UR_REQ 0x00100000 /* Unsupported Request Error Status */
++#define PCIE_ALL_UNCORRECTABLE_ERR (PCIE_DATA_LINK_PROTOCOL_ERR | PCIE_SURPRISE_DOWN_ERROR | \
++ PCIE_POISONED_TLP | PCIE_FC_PROTOCOL_ERR | PCIE_COMPLETION_TIMEOUT | \
++ PCIE_COMPLETOR_ABORT | PCIE_UNEXPECTED_COMPLETION | PCIE_RECEIVER_OVERFLOW |\
++ PCIE_MALFORNED_TLP | PCIE_ECRC_ERR | PCIE_UR_REQ)
++
++/* Uncorrectable Error Mask Register, Mask means no report */
++#define PCIE_UEMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x108)
++
++/* Uncorrectable Error Severity Register */
++#define PCIE_UESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x10C)
++
++/* Correctable Error Status Register */
++#define PCIE_CESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x110)
++#define PCIE_RX_ERR 0x00000001 /* Receive Error Status */
++#define PCIE_BAD_TLP 0x00000040 /* Bad TLP Status */
++#define PCIE_BAD_DLLP 0x00000080 /* Bad DLLP Status */
++#define PCIE_REPLAY_NUM_ROLLOVER 0x00000100 /* Replay Number Rollover Status */
++#define PCIE_REPLAY_TIMER_TIMEOUT_ERR 0x00001000 /* Reply Timer Timeout Status */
++#define PCIE_ADVISORY_NONFTAL_ERR 0x00002000 /* Advisory Non-Fatal Error Status */
++#define PCIE_CORRECTABLE_ERR (PCIE_RX_ERR | PCIE_BAD_TLP | PCIE_BAD_DLLP | PCIE_REPLAY_NUM_ROLLOVER |\
++ PCIE_REPLAY_TIMER_TIMEOUT_ERR | PCIE_ADVISORY_NONFTAL_ERR)
++
++/* Correctable Error Mask Register */
++#define PCIE_CEMR(X) (volatile u32*)(PCIE_RC_CFG_BASE + 0x114)
++
++/* Advanced Error Capabilities and Control Register */
++#define PCIE_AECCR(X) (volatile u32*)(PCIE_RC_CFG_BASE + 0x118)
++#define PCIE_AECCR_FIRST_ERR_PTR 0x0000001F /* First Error Pointer */
++#define PCIE_AECCR_FIRST_ERR_PTR_S 0
++#define PCIE_AECCR_ECRC_GEN_CAP 0x00000020 /* ECRC Generation Capable */
++#define PCIE_AECCR_ECRC_GEN_EN 0x00000040 /* ECRC Generation Enable */
++#define PCIE_AECCR_ECRC_CHECK_CAP 0x00000080 /* ECRC Check Capable */
++#define PCIE_AECCR_ECRC_CHECK_EN 0x00000100 /* ECRC Check Enable */
++
++/* Header Log Register 1 */
++#define PCIE_HLR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x11C)
++
++/* Header Log Register 2 */
++#define PCIE_HLR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x120)
++
++/* Header Log Register 3 */
++#define PCIE_HLR3(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x124)
++
++/* Header Log Register 4 */
++#define PCIE_HLR4(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x128)
++
++/* Root Error Command Register */
++#define PCIE_RECR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x12C)
++#define PCIE_RECR_CORRECTABLE_ERR_REPORT_EN 0x00000001 /* COR-ERR */
++#define PCIE_RECR_NONFATAL_ERR_REPORT_EN 0x00000002 /* Non-Fatal ERR */
++#define PCIE_RECR_FATAL_ERR_REPORT_EN 0x00000004 /* Fatal ERR */
++#define PCIE_RECR_ERR_REPORT_EN (PCIE_RECR_CORRECTABLE_ERR_REPORT_EN | \
++ PCIE_RECR_NONFATAL_ERR_REPORT_EN | PCIE_RECR_FATAL_ERR_REPORT_EN)
++
++/* Root Error Status Register */
++#define PCIE_RESR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x130)
++#define PCIE_RESR_CORRECTABLE_ERR 0x00000001 /* COR-ERR Receveid */
++#define PCIE_RESR_MULTI_CORRECTABLE_ERR 0x00000002 /* Multiple COR-ERR Received */
++#define PCIE_RESR_FATAL_NOFATAL_ERR 0x00000004 /* ERR Fatal/Non-Fatal Received */
++#define PCIE_RESR_MULTI_FATAL_NOFATAL_ERR 0x00000008 /* Multiple ERR Fatal/Non-Fatal Received */
++#define PCIE_RESR_FIRST_UNCORRECTABLE_FATAL_ERR 0x00000010 /* First UN-COR Fatal */
++#define PCIR_RESR_NON_FATAL_ERR 0x00000020 /* Non-Fatal Error Message Received */
++#define PCIE_RESR_FATAL_ERR 0x00000040 /* Fatal Message Received */
++#define PCIE_RESR_AER_INT_MSG_NUM 0xF8000000 /* Advanced Error Interrupt Message Number */
++#define PCIE_RESR_AER_INT_MSG_NUM_S 27
++
++/* Error Source Indentification Register */
++#define PCIE_ESIR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x134)
++#define PCIE_ESIR_CORRECTABLE_ERR_SRC_ID 0x0000FFFF
++#define PCIE_ESIR_CORRECTABLE_ERR_SRC_ID_S 0
++#define PCIE_ESIR_FATAL_NON_FATAL_SRC_ID 0xFFFF0000
++#define PCIE_ESIR_FATAL_NON_FATAL_SRC_ID_S 16
++
++/* VC Enhanced Capability Header */
++#define PCIE_VC_ECH(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x140)
++
++/* Port VC Capability Register */
++#define PCIE_PVC1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x144)
++#define PCIE_PVC1_EXT_VC_CNT 0x00000007 /* Extended VC Count */
++#define PCIE_PVC1_EXT_VC_CNT_S 0
++#define PCIE_PVC1_LOW_PRI_EXT_VC_CNT 0x00000070 /* Low Priority Extended VC Count */
++#define PCIE_PVC1_LOW_PRI_EXT_VC_CNT_S 4
++#define PCIE_PVC1_REF_CLK 0x00000300 /* Reference Clock */
++#define PCIE_PVC1_REF_CLK_S 8
++#define PCIE_PVC1_PORT_ARB_TAB_ENTRY_SIZE 0x00000C00 /* Port Arbitration Table Entry Size */
++#define PCIE_PVC1_PORT_ARB_TAB_ENTRY_SIZE_S 10
++
++/* Extended Virtual Channel Count Defintion */
++#define PCIE_EXT_VC_CNT_MIN 0
++#define PCIE_EXT_VC_CNT_MAX 7
++
++/* Port Arbitration Table Entry Size Definition */
++enum {
++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S1BIT = 0,
++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S2BIT,
++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S4BIT,
++ PCIE_PORT_ARB_TAB_ENTRY_SIZE_S8BIT,
++};
++
++/* Port VC Capability Register 2 */
++#define PCIE_PVC2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x148)
++#define PCIE_PVC2_VC_ARB_16P_FIXED_WRR 0x00000001 /* HW Fixed arbitration, 16 phase WRR */
++#define PCIE_PVC2_VC_ARB_32P_WRR 0x00000002 /* 32 phase WRR */
++#define PCIE_PVC2_VC_ARB_64P_WRR 0x00000004 /* 64 phase WRR */
++#define PCIE_PVC2_VC_ARB_128P_WRR 0x00000008 /* 128 phase WRR */
++#define PCIE_PVC2_VC_ARB_WRR 0x0000000F
++#define PCIE_PVC2_VC_ARB_TAB_OFFSET 0xFF000000 /* VC arbitration table offset, not support */
++#define PCIE_PVC2_VC_ARB_TAB_OFFSET_S 24
++
++/* Port VC Control and Status Register */
++#define PCIE_PVCCRSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x14C)
++#define PCIE_PVCCRSR_LOAD_VC_ARB_TAB 0x00000001 /* Load VC Arbitration Table */
++#define PCIE_PVCCRSR_VC_ARB_SEL 0x0000000E /* VC Arbitration Select */
++#define PCIE_PVCCRSR_VC_ARB_SEL_S 1
++#define PCIE_PVCCRSR_VC_ARB_TAB_STATUS 0x00010000 /* Arbitration Status */
++
++/* VC0 Resource Capability Register */
++#define PCIE_VC0_RC(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x150)
++#define PCIE_VC0_RC_PORT_ARB_HW_FIXED 0x00000001 /* HW Fixed arbitration */
++#define PCIE_VC0_RC_PORT_ARB_32P_WRR 0x00000002 /* 32 phase WRR */
++#define PCIE_VC0_RC_PORT_ARB_64P_WRR 0x00000004 /* 64 phase WRR */
++#define PCIE_VC0_RC_PORT_ARB_128P_WRR 0x00000008 /* 128 phase WRR */
++#define PCIE_VC0_RC_PORT_ARB_TM_128P_WRR 0x00000010 /* Time-based 128 phase WRR */
++#define PCIE_VC0_RC_PORT_ARB_TM_256P_WRR 0x00000020 /* Time-based 256 phase WRR */
++#define PCIE_VC0_RC_PORT_ARB (PCIE_VC0_RC_PORT_ARB_HW_FIXED | PCIE_VC0_RC_PORT_ARB_32P_WRR |\
++ PCIE_VC0_RC_PORT_ARB_64P_WRR | PCIE_VC0_RC_PORT_ARB_128P_WRR | \
++ PCIE_VC0_RC_PORT_ARB_TM_128P_WRR | PCIE_VC0_RC_PORT_ARB_TM_256P_WRR)
++
++#define PCIE_VC0_RC_REJECT_SNOOP 0x00008000 /* Reject Snoop Transactioin */
++#define PCIE_VC0_RC_MAX_TIMESLOTS 0x007F0000 /* Maximum time Slots */
++#define PCIE_VC0_RC_MAX_TIMESLOTS_S 16
++#define PCIE_VC0_RC_PORT_ARB_TAB_OFFSET 0xFF000000 /* Port Arbitration Table Offset */
++#define PCIE_VC0_RC_PORT_ARB_TAB_OFFSET_S 24
++
++/* VC0 Resource Control Register */
++#define PCIE_VC0_RC0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x154)
++#define PCIE_VC0_RC0_TVM0 0x00000001 /* TC0 and VC0 */
++#define PCIE_VC0_RC0_TVM1 0x00000002 /* TC1 and VC1 */
++#define PCIE_VC0_RC0_TVM2 0x00000004 /* TC2 and VC2 */
++#define PCIE_VC0_RC0_TVM3 0x00000008 /* TC3 and VC3 */
++#define PCIE_VC0_RC0_TVM4 0x00000010 /* TC4 and VC4 */
++#define PCIE_VC0_RC0_TVM5 0x00000020 /* TC5 and VC5 */
++#define PCIE_VC0_RC0_TVM6 0x00000040 /* TC6 and VC6 */
++#define PCIE_VC0_RC0_TVM7 0x00000080 /* TC7 and VC7 */
++#define PCIE_VC0_RC0_TC_VC 0x000000FF /* TC/VC mask */
++
++#define PCIE_VC0_RC0_LOAD_PORT_ARB_TAB 0x00010000 /* Load Port Arbitration Table */
++#define PCIE_VC0_RC0_PORT_ARB_SEL 0x000E0000 /* Port Arbitration Select */
++#define PCIE_VC0_RC0_PORT_ARB_SEL_S 17
++#define PCIE_VC0_RC0_VC_ID 0x07000000 /* VC ID */
++#define PCIE_VC0_RC0_VC_ID_S 24
++#define PCIE_VC0_RC0_VC_EN 0x80000000 /* VC Enable */
++
++/* VC0 Resource Status Register */
++#define PCIE_VC0_RSR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x158)
++#define PCIE_VC0_RSR0_PORT_ARB_TAB_STATUS 0x00010000 /* Port Arbitration Table Status,not used */
++#define PCIE_VC0_RSR0_VC_NEG_PENDING 0x00020000 /* VC Negotiation Pending */
++
++/* Ack Latency Timer and Replay Timer Register */
++#define PCIE_ALTRT(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x700)
++#define PCIE_ALTRT_ROUND_TRIP_LATENCY_LIMIT 0x0000FFFF /* Round Trip Latency Time Limit */
++#define PCIE_ALTRT_ROUND_TRIP_LATENCY_LIMIT_S 0
++#define PCIE_ALTRT_REPLAY_TIME_LIMIT 0xFFFF0000 /* Replay Time Limit */
++#define PCIE_ALTRT_REPLAY_TIME_LIMIT_S 16
++
++/* Other Message Register */
++#define PCIE_OMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x704)
++
++/* Port Force Link Register */
++#define PCIE_PFLR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x708)
++#define PCIE_PFLR_LINK_NUM 0x000000FF /* Link Number */
++#define PCIE_PFLR_LINK_NUM_S 0
++#define PCIE_PFLR_FORCE_LINK 0x00008000 /* Force link */
++#define PCIE_PFLR_LINK_STATE 0x003F0000 /* Link State */
++#define PCIE_PFLR_LINK_STATE_S 16
++#define PCIE_PFLR_LOW_POWER_ENTRY_CNT 0xFF000000 /* Low Power Entrance Count, only for EP */
++#define PCIE_PFLR_LOW_POWER_ENTRY_CNT_S 24
++
++/* Ack Frequency Register */
++#define PCIE_AFR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x70C)
++#define PCIE_AFR_AF 0x000000FF /* Ack Frequency */
++#define PCIE_AFR_AF_S 0
++#define PCIE_AFR_FTS_NUM 0x0000FF00 /* The number of Fast Training Sequence from L0S to L0 */
++#define PCIE_AFR_FTS_NUM_S 8
++#define PCIE_AFR_COM_FTS_NUM 0x00FF0000 /* N_FTS; when common clock is used*/
++#define PCIE_AFR_COM_FTS_NUM_S 16
++#define PCIE_AFR_L0S_ENTRY_LATENCY 0x07000000 /* L0s Entrance Latency */
++#define PCIE_AFR_L0S_ENTRY_LATENCY_S 24
++#define PCIE_AFR_L1_ENTRY_LATENCY 0x38000000 /* L1 Entrance Latency */
++#define PCIE_AFR_L1_ENTRY_LATENCY_S 27
++#define PCIE_AFR_FTS_NUM_DEFAULT 32
++#define PCIE_AFR_L0S_ENTRY_LATENCY_DEFAULT 7
++#define PCIE_AFR_L1_ENTRY_LATENCY_DEFAULT 5
++
++/* Port Link Control Register */
++#define PCIE_PLCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x710)
++#define PCIE_PLCR_OTHER_MSG_REQ 0x00000001 /* Other Message Request */
++#define PCIE_PLCR_SCRAMBLE_DISABLE 0x00000002 /* Scramble Disable */
++#define PCIE_PLCR_LOOPBACK_EN 0x00000004 /* Loopback Enable */
++#define PCIE_PLCR_LTSSM_HOT_RST 0x00000008 /* Force LTSSM to the hot reset */
++#define PCIE_PLCR_DLL_LINK_EN 0x00000020 /* Enable Link initialization */
++#define PCIE_PLCR_FAST_LINK_SIM_EN 0x00000080 /* Sets all internal timers to fast mode for simulation purposes */
++#define PCIE_PLCR_LINK_MODE 0x003F0000 /* Link Mode Enable Mask */
++#define PCIE_PLCR_LINK_MODE_S 16
++#define PCIE_PLCR_CORRUPTED_CRC_EN 0x02000000 /* Enabled Corrupt CRC */
++
++/* Lane Skew Register */
++#define PCIE_LSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x714)
++#define PCIE_LSR_LANE_SKEW_NUM 0x00FFFFFF /* Insert Lane Skew for Transmit, not applicable */
++#define PCIE_LSR_LANE_SKEW_NUM_S 0
++#define PCIE_LSR_FC_DISABLE 0x01000000 /* Disable of Flow Control */
++#define PCIE_LSR_ACKNAK_DISABLE 0x02000000 /* Disable of Ack/Nak */
++#define PCIE_LSR_LANE_DESKEW_DISABLE 0x80000000 /* Disable of Lane-to-Lane Skew */
++
++/* Symbol Number Register */
++#define PCIE_SNR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x718)
++#define PCIE_SNR_TS 0x0000000F /* Number of TS Symbol */
++#define PCIE_SNR_TS_S 0
++#define PCIE_SNR_SKP 0x00000700 /* Number of SKP Symbol */
++#define PCIE_SNR_SKP_S 8
++#define PCIE_SNR_REPLAY_TIMER 0x0007C000 /* Timer Modifier for Replay Timer */
++#define PCIE_SNR_REPLAY_TIMER_S 14
++#define PCIE_SNR_ACKNAK_LATENCY_TIMER 0x00F80000 /* Timer Modifier for Ack/Nak Latency Timer */
++#define PCIE_SNR_ACKNAK_LATENCY_TIMER_S 19
++#define PCIE_SNR_FC_TIMER 0x1F000000 /* Timer Modifier for Flow Control Watchdog Timer */
++#define PCIE_SNR_FC_TIMER_S 28
++
++/* Symbol Timer Register and Filter Mask Register 1 */
++#define PCIE_STRFMR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x71C)
++#define PCIE_STRFMR_SKP_INTERVAL 0x000007FF /* SKP lnterval Value */
++#define PCIE_STRFMR_SKP_INTERVAL_S 0
++#define PCIE_STRFMR_FC_WDT_DISABLE 0x00008000 /* Disable of FC Watchdog Timer */
++#define PCIE_STRFMR_TLP_FUNC_MISMATCH_OK 0x00010000 /* Mask Function Mismatch Filtering for Incoming Requests */
++#define PCIE_STRFMR_POISONED_TLP_OK 0x00020000 /* Mask Poisoned TLP Filtering */
++#define PCIE_STRFMR_BAR_MATCH_OK 0x00040000 /* Mask BAR Match Filtering */
++#define PCIE_STRFMR_TYPE1_CFG_REQ_OK 0x00080000 /* Mask Type 1 Configuration Request Filtering */
++#define PCIE_STRFMR_LOCKED_REQ_OK 0x00100000 /* Mask Locked Request Filtering */
++#define PCIE_STRFMR_CPL_TAG_ERR_RULES_OK 0x00200000 /* Mask Tag Error Rules for Received Completions */
++#define PCIE_STRFMR_CPL_REQUESTOR_ID_MISMATCH_OK 0x00400000 /* Mask Requester ID Mismatch Error for Received Completions */
++#define PCIE_STRFMR_CPL_FUNC_MISMATCH_OK 0x00800000 /* Mask Function Mismatch Error for Received Completions */
++#define PCIE_STRFMR_CPL_TC_MISMATCH_OK 0x01000000 /* Mask Traffic Class Mismatch Error for Received Completions */
++#define PCIE_STRFMR_CPL_ATTR_MISMATCH_OK 0x02000000 /* Mask Attribute Mismatch Error for Received Completions */
++#define PCIE_STRFMR_CPL_LENGTH_MISMATCH_OK 0x04000000 /* Mask Length Mismatch Error for Received Completions */
++#define PCIE_STRFMR_TLP_ECRC_ERR_OK 0x08000000 /* Mask ECRC Error Filtering */
++#define PCIE_STRFMR_CPL_TLP_ECRC_OK 0x10000000 /* Mask ECRC Error Filtering for Completions */
++#define PCIE_STRFMR_RX_TLP_MSG_NO_DROP 0x20000000 /* Send Message TLPs */
++#define PCIE_STRFMR_RX_IO_TRANS_ENABLE 0x40000000 /* Mask Filtering of received I/O Requests */
++#define PCIE_STRFMR_RX_CFG_TRANS_ENABLE 0x80000000 /* Mask Filtering of Received Configuration Requests */
++
++#define PCIE_DEF_SKP_INTERVAL 700 /* 1180 ~1538 , 125MHz * 2, 250MHz * 1 */
++
++/* Filter Masker Register 2 */
++#define PCIE_FMR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x720)
++#define PCIE_FMR2_VENDOR_MSG0_PASSED_TO_TRGT1 0x00000001 /* Mask RADM Filtering and Error Handling Rules */
++#define PCIE_FMR2_VENDOR_MSG1_PASSED_TO_TRGT1 0x00000002 /* Mask RADM Filtering and Error Handling Rules */
++
++/* Debug Register 0 */
++#define PCIE_DBR0(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x728)
++
++/* Debug Register 1 */
++#define PCIE_DBR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x72C)
++
++/* Transmit Posted FC Credit Status Register */
++#define PCIE_TPFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x730)
++#define PCIE_TPFCS_TX_P_DATA_FC_CREDITS 0x00000FFF /* Transmit Posted Data FC Credits */
++#define PCIE_TPFCS_TX_P_DATA_FC_CREDITS_S 0
++#define PCIE_TPFCS_TX_P_HDR_FC_CREDITS 0x000FF000 /* Transmit Posted Header FC Credits */
++#define PCIE_TPFCS_TX_P_HDR_FC_CREDITS_S 12
++
++/* Transmit Non-Posted FC Credit Status */
++#define PCIE_TNPFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x734)
++#define PCIE_TNPFCS_TX_NP_DATA_FC_CREDITS 0x00000FFF /* Transmit Non-Posted Data FC Credits */
++#define PCIE_TNPFCS_TX_NP_DATA_FC_CREDITS_S 0
++#define PCIE_TNPFCS_TX_NP_HDR_FC_CREDITS 0x000FF000 /* Transmit Non-Posted Header FC Credits */
++#define PCIE_TNPFCS_TX_NP_HDR_FC_CREDITS_S 12
++
++/* Transmit Complete FC Credit Status Register */
++#define PCIE_TCFCS(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x738)
++#define PCIE_TCFCS_TX_CPL_DATA_FC_CREDITS 0x00000FFF /* Transmit Completion Data FC Credits */
++#define PCIE_TCFCS_TX_CPL_DATA_FC_CREDITS_S 0
++#define PCIE_TCFCS_TX_CPL_HDR_FC_CREDITS 0x000FF000 /* Transmit Completion Header FC Credits */
++#define PCIE_TCFCS_TX_CPL_HDR_FC_CREDITS_S 12
++
++/* Queue Status Register */
++#define PCIE_QSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x73C)
++#define PCIE_QSR_WAIT_UPDATE_FC_DLL 0x00000001 /* Received TLP FC Credits Not Returned */
++#define PCIE_QSR_TX_RETRY_BUF_NOT_EMPTY 0x00000002 /* Transmit Retry Buffer Not Empty */
++#define PCIE_QSR_RX_QUEUE_NOT_EMPTY 0x00000004 /* Received Queue Not Empty */
++
++/* VC Transmit Arbitration Register 1 */
++#define PCIE_VCTAR1(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x740)
++#define PCIE_VCTAR1_WRR_WEIGHT_VC0 0x000000FF /* WRR Weight for VC0 */
++#define PCIE_VCTAR1_WRR_WEIGHT_VC1 0x0000FF00 /* WRR Weight for VC1 */
++#define PCIE_VCTAR1_WRR_WEIGHT_VC2 0x00FF0000 /* WRR Weight for VC2 */
++#define PCIE_VCTAR1_WRR_WEIGHT_VC3 0xFF000000 /* WRR Weight for VC3 */
++
++/* VC Transmit Arbitration Register 2 */
++#define PCIE_VCTAR2(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x744)
++#define PCIE_VCTAR2_WRR_WEIGHT_VC4 0x000000FF /* WRR Weight for VC4 */
++#define PCIE_VCTAR2_WRR_WEIGHT_VC5 0x0000FF00 /* WRR Weight for VC5 */
++#define PCIE_VCTAR2_WRR_WEIGHT_VC6 0x00FF0000 /* WRR Weight for VC6 */
++#define PCIE_VCTAR2_WRR_WEIGHT_VC7 0xFF000000 /* WRR Weight for VC7 */
++
++/* VC0 Posted Receive Queue Control Register */
++#define PCIE_VC0_PRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x748)
++#define PCIE_VC0_PRQCR_P_DATA_CREDITS 0x00000FFF /* VC0 Posted Data Credits */
++#define PCIE_VC0_PRQCR_P_DATA_CREDITS_S 0
++#define PCIE_VC0_PRQCR_P_HDR_CREDITS 0x000FF000 /* VC0 Posted Header Credits */
++#define PCIE_VC0_PRQCR_P_HDR_CREDITS_S 12
++#define PCIE_VC0_PRQCR_P_TLP_QUEUE_MODE 0x00E00000 /* VC0 Posted TLP Queue Mode */
++#define PCIE_VC0_PRQCR_P_TLP_QUEUE_MODE_S 20
++#define PCIE_VC0_PRQCR_TLP_RELAX_ORDER 0x40000000 /* TLP Type Ordering for VC0 */
++#define PCIE_VC0_PRQCR_VC_STRICT_ORDER 0x80000000 /* VC0 Ordering for Receive Queues */
++
++/* VC0 Non-Posted Receive Queue Control */
++#define PCIE_VC0_NPRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x74C)
++#define PCIE_VC0_NPRQCR_NP_DATA_CREDITS 0x00000FFF /* VC0 Non-Posted Data Credits */
++#define PCIE_VC0_NPRQCR_NP_DATA_CREDITS_S 0
++#define PCIE_VC0_NPRQCR_NP_HDR_CREDITS 0x000FF000 /* VC0 Non-Posted Header Credits */
++#define PCIE_VC0_NPRQCR_NP_HDR_CREDITS_S 12
++#define PCIE_VC0_NPRQCR_NP_TLP_QUEUE_MODE 0x00E00000 /* VC0 Non-Posted TLP Queue Mode */
++#define PCIE_VC0_NPRQCR_NP_TLP_QUEUE_MODE_S 20
++
++/* VC0 Completion Receive Queue Control */
++#define PCIE_VC0_CRQCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x750)
++#define PCIE_VC0_CRQCR_CPL_DATA_CREDITS 0x00000FFF /* VC0 Completion TLP Queue Mode */
++#define PCIE_VC0_CRQCR_CPL_DATA_CREDITS_S 0
++#define PCIE_VC0_CRQCR_CPL_HDR_CREDITS 0x000FF000 /* VC0 Completion Header Credits */
++#define PCIE_VC0_CRQCR_CPL_HDR_CREDITS_S 12
++#define PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE 0x00E00000 /* VC0 Completion Data Credits */
++#define PCIE_VC0_CRQCR_CPL_TLP_QUEUE_MODE_S 21
++
++/* Applicable to the above three registers */
++enum {
++ PCIE_VC0_TLP_QUEUE_MODE_STORE_FORWARD = 1,
++ PCIE_VC0_TLP_QUEUE_MODE_CUT_THROUGH = 2,
++ PCIE_VC0_TLP_QUEUE_MODE_BYPASS = 4,
++};
++
++/* VC0 Posted Buffer Depth Register */
++#define PCIE_VC0_PBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7A8)
++#define PCIE_VC0_PBD_P_DATA_QUEUE_ENTRIES 0x00003FFF /* VC0 Posted Data Queue Depth */
++#define PCIE_VC0_PBD_P_DATA_QUEUE_ENTRIES_S 0
++#define PCIE_VC0_PBD_P_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Posted Header Queue Depth */
++#define PCIE_VC0_PBD_P_HDR_QUEUE_ENTRIES_S 16
++
++/* VC0 Non-Posted Buffer Depth Register */
++#define PCIE_VC0_NPBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7AC)
++#define PCIE_VC0_NPBD_NP_DATA_QUEUE_ENTRIES 0x00003FFF /* VC0 Non-Posted Data Queue Depth */
++#define PCIE_VC0_NPBD_NP_DATA_QUEUE_ENTRIES_S 0
++#define PCIE_VC0_NPBD_NP_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Non-Posted Header Queue Depth */
++#define PCIE_VC0_NPBD_NP_HDR_QUEUE_ENTRIES_S 16
++
++/* VC0 Completion Buffer Depth Register */
++#define PCIE_VC0_CBD(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x7B0)
++#define PCIE_VC0_CBD_CPL_DATA_QUEUE_ENTRIES 0x00003FFF /* C0 Completion Data Queue Depth */
++#define PCIE_VC0_CBD_CPL_DATA_QUEUE_ENTRIES_S 0
++#define PCIE_VC0_CBD_CPL_HDR_QUEUE_ENTRIES 0x03FF0000 /* VC0 Completion Header Queue Depth */
++#define PCIE_VC0_CBD_CPL_HDR_QUEUE_ENTRIES_S 16
++
++/* PHY Status Register, all zeros in VR9 */
++#define PCIE_PHYSR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x810)
++
++/* PHY Control Register, all zeros in VR9 */
++#define PCIE_PHYCR(X) (volatile u32*)(PCIE_RC_PORT_TO_BASE(X) + 0x814)
++
++/*
++ * PCIe PDI PHY register definition, suppose all the following
++ * stuff is confidential.
++ * XXX, detailed bit definition
++ */
++#define PCIE_PHY_PLL_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x22 << 1))
++#define PCIE_PHY_PLL_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x23 << 1))
++#define PCIE_PHY_PLL_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x24 << 1))
++#define PCIE_PHY_PLL_CTRL4(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x25 << 1))
++#define PCIE_PHY_PLL_CTRL5(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x26 << 1))
++#define PCIE_PHY_PLL_CTRL6(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x27 << 1))
++#define PCIE_PHY_PLL_CTRL7(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x28 << 1))
++#define PCIE_PHY_PLL_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x29 << 1))
++#define PCIE_PHY_PLL_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2A << 1))
++#define PCIE_PHY_PLL_A_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2B << 1))
++#define PCIE_PHY_PLL_STATUS(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x2C << 1))
++
++#define PCIE_PHY_TX1_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x30 << 1))
++#define PCIE_PHY_TX1_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x31 << 1))
++#define PCIE_PHY_TX1_CTRL3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x32 << 1))
++#define PCIE_PHY_TX1_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x33 << 1))
++#define PCIE_PHY_TX1_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x34 << 1))
++#define PCIE_PHY_TX1_MOD1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x35 << 1))
++#define PCIE_PHY_TX1_MOD2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x36 << 1))
++#define PCIE_PHY_TX1_MOD3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x37 << 1))
++
++#define PCIE_PHY_TX2_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x38 << 1))
++#define PCIE_PHY_TX2_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x39 << 1))
++#define PCIE_PHY_TX2_A_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3B << 1))
++#define PCIE_PHY_TX2_A_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3C << 1))
++#define PCIE_PHY_TX2_MOD1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3D << 1))
++#define PCIE_PHY_TX2_MOD2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3E << 1))
++#define PCIE_PHY_TX2_MOD3(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x3F << 1))
++
++#define PCIE_PHY_RX1_CTRL1(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x50 << 1))
++#define PCIE_PHY_RX1_CTRL2(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x51 << 1))
++#define PCIE_PHY_RX1_CDR(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x52 << 1))
++#define PCIE_PHY_RX1_EI(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x53 << 1))
++#define PCIE_PHY_RX1_A_CTRL(X) (PCIE_PHY_PORT_TO_BASE(X) + (0x55 << 1))
++
++/* Interrupt related stuff */
++#define PCIE_LEGACY_DISABLE 0
++#define PCIE_LEGACY_INTA 1
++#define PCIE_LEGACY_INTB 2
++#define PCIE_LEGACY_INTC 3
++#define PCIE_LEGACY_INTD 4
++#define PCIE_LEGACY_INT_MAX PCIE_LEGACY_INTD
++
++#endif /* IFXMIPS_PCIE_REG_H */
++
+diff --git a/arch/mips/pci/ifxmips_pcie_vr9.h b/arch/mips/pci/ifxmips_pcie_vr9.h
+new file mode 100644
+index 0000000..57d9368
+--- /dev/null
++++ b/arch/mips/pci/ifxmips_pcie_vr9.h
+@@ -0,0 +1,271 @@
++/****************************************************************************
++ Copyright (c) 2010
++ Lantiq Deutschland GmbH
++ Am Campeon 3; 85579 Neubiberg, Germany
++
++ For licensing information, see the file 'LICENSE' in the root folder of
++ this software module.
++
++ *****************************************************************************/
++/*!
++ \file ifxmips_pcie_vr9.h
++ \ingroup IFX_PCIE
++ \brief PCIe RC driver vr9 specific file
++*/
++
++#ifndef IFXMIPS_PCIE_VR9_H
++#define IFXMIPS_PCIE_VR9_H
++
++#include <linux/types.h>
++#include <linux/delay.h>
++
++#include <linux/gpio.h>
++#include <lantiq_soc.h>
++
++#define IFX_PCIE_GPIO_RESET 238
++
++#define IFX_REG_R32 ltq_r32
++#define IFX_REG_W32 ltq_w32
++#define CONFIG_IFX_PCIE_HW_SWAP
++#define IFX_RCU_AHB_ENDIAN ((volatile u32*)(IFX_RCU + 0x004C))
++#define IFX_RCU_RST_REQ ((volatile u32*)(IFX_RCU + 0x0010))
++#define IFX_RCU_AHB_BE_PCIE_PDI 0x00000080 /* Configure PCIE PDI module in big endian*/
++
++#define IFX_RCU (KSEG1 | 0x1F203000)
++#define IFX_RCU_AHB_BE_PCIE_M 0x00000001 /* Configure AHB master port that connects to PCIe RC in big endian */
++#define IFX_RCU_AHB_BE_PCIE_S 0x00000010 /* Configure AHB slave port that connects to PCIe RC in little endian */
++#define IFX_RCU_AHB_BE_XBAR_M 0x00000002 /* Configure AHB master port that connects to XBAR in big endian */
++#define CONFIG_IFX_PCIE_PHY_36MHZ_MODE
++
++#define IFX_PMU1_MODULE_PCIE_PHY (0)
++#define IFX_PMU1_MODULE_PCIE_CTRL (1)
++#define IFX_PMU1_MODULE_PDI (4)
++#define IFX_PMU1_MODULE_MSI (5)
++
++#define IFX_PMU_MODULE_PCIE_L0_CLK (31)
++
++
++#define IFX_GPIO (KSEG1 | 0x1E100B00)
++#define ALT0 ((volatile u32*)(IFX_GPIO + 0x007c))
++#define ALT1 ((volatile u32*)(IFX_GPIO + 0x0080))
++#define OD ((volatile u32*)(IFX_GPIO + 0x0084))
++#define DIR ((volatile u32*)(IFX_GPIO + 0x0078))
++#define OUT ((volatile u32*)(IFX_GPIO + 0x0070))
++
++
++static inline void pcie_ep_gpio_rst_init(int pcie_port)
++{
++
++ gpio_request(IFX_PCIE_GPIO_RESET, "pcie-reset");
++ gpio_direction_output(IFX_PCIE_GPIO_RESET, 1);
++ gpio_set_value(IFX_PCIE_GPIO_RESET, 1);
++
++/* ifx_gpio_pin_reserve(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id);
++ ifx_gpio_output_set(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id);
++ ifx_gpio_dir_out_set(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id);
++ ifx_gpio_altsel0_clear(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id);
++ ifx_gpio_altsel1_clear(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id);
++ ifx_gpio_open_drain_set(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id);*/
++}
++
++static inline void pcie_ahb_pmu_setup(void)
++{
++ /* Enable AHB bus master/slave */
++ struct clk *clk;
++ clk = clk_get_sys("1d900000.pcie", "ahb");
++ clk_enable(clk);
++
++ //AHBM_PMU_SETUP(IFX_PMU_ENABLE);
++ //AHBS_PMU_SETUP(IFX_PMU_ENABLE);
++}
++
++static inline void pcie_rcu_endian_setup(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN);
++#ifdef CONFIG_IFX_PCIE_HW_SWAP
++ reg |= IFX_RCU_AHB_BE_PCIE_M;
++ reg |= IFX_RCU_AHB_BE_PCIE_S;
++ reg &= ~IFX_RCU_AHB_BE_XBAR_M;
++#else
++ reg |= IFX_RCU_AHB_BE_PCIE_M;
++ reg &= ~IFX_RCU_AHB_BE_PCIE_S;
++ reg &= ~IFX_RCU_AHB_BE_XBAR_M;
++#endif /* CONFIG_IFX_PCIE_HW_SWAP */
++ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN);
++ IFX_PCIE_PRINT(PCIE_MSG_REG, "%s IFX_RCU_AHB_ENDIAN: 0x%08x\n", __func__, IFX_REG_R32(IFX_RCU_AHB_ENDIAN));
++}
++
++static inline void pcie_phy_pmu_enable(int pcie_port)
++{
++ struct clk *clk;
++ clk = clk_get_sys("1d900000.pcie", "phy");
++ clk_enable(clk);
++
++ //PCIE_PHY_PMU_SETUP(IFX_PMU_ENABLE);
++}
++
++static inline void pcie_phy_pmu_disable(int pcie_port)
++{
++ struct clk *clk;
++ clk = clk_get_sys("1d900000.pcie", "phy");
++ clk_disable(clk);
++
++// PCIE_PHY_PMU_SETUP(IFX_PMU_DISABLE);
++}
++
++static inline void pcie_pdi_big_endian(int pcie_port)
++{
++ u32 reg;
++
++ /* SRAM2PDI endianness control. */
++ reg = IFX_REG_R32(IFX_RCU_AHB_ENDIAN);
++ /* Config AHB->PCIe and PDI endianness */
++ reg |= IFX_RCU_AHB_BE_PCIE_PDI;
++ IFX_REG_W32(reg, IFX_RCU_AHB_ENDIAN);
++}
++
++static inline void pcie_pdi_pmu_enable(int pcie_port)
++{
++ /* Enable PDI to access PCIe PHY register */
++ struct clk *clk;
++ clk = clk_get_sys("1d900000.pcie", "pdi");
++ clk_enable(clk);
++ //PDI_PMU_SETUP(IFX_PMU_ENABLE);
++}
++
++static inline void pcie_core_rst_assert(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(IFX_RCU_RST_REQ);
++
++ /* Reset PCIe PHY & Core, bit 22, bit 26 may be affected if write it directly */
++ reg |= 0x00400000;
++ IFX_REG_W32(reg, IFX_RCU_RST_REQ);
++}
++
++static inline void pcie_core_rst_deassert(int pcie_port)
++{
++ u32 reg;
++
++ /* Make sure one micro-second delay */
++ udelay(1);
++
++ /* Reset PCIe PHY & Core, bit 22 */
++ reg = IFX_REG_R32(IFX_RCU_RST_REQ);
++ reg &= ~0x00400000;
++ IFX_REG_W32(reg, IFX_RCU_RST_REQ);
++}
++
++static inline void pcie_phy_rst_assert(int pcie_port)
++{
++ u32 reg;
++
++ reg = IFX_REG_R32(IFX_RCU_RST_REQ);
++ reg |= 0x00001000; /* Bit 12 */
++ IFX_REG_W32(reg, IFX_RCU_RST_REQ);
++}
++
++static inline void pcie_phy_rst_deassert(int pcie_port)
++{
++ u32 reg;
++
++ /* Make sure one micro-second delay */
++ udelay(1);
++
++ reg = IFX_REG_R32(IFX_RCU_RST_REQ);
++ reg &= ~0x00001000; /* Bit 12 */
++ IFX_REG_W32(reg, IFX_RCU_RST_REQ);
++}
++
++static inline void pcie_device_rst_assert(int pcie_port)
++{
++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++ gpio_set_value(IFX_PCIE_GPIO_RESET, 0);
++// ifx_gpio_output_clear(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id);
++}
++
++static inline void pcie_device_rst_deassert(int pcie_port)
++{
++ mdelay(100);
++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
++ gpio_direction_output(IFX_PCIE_GPIO_RESET, 1);
++// gpio_set_value(IFX_PCIE_GPIO_RESET, 1);
++ //ifx_gpio_output_set(IFX_PCIE_GPIO_RESET, ifx_pcie_gpio_module_id);
++}
++
++static inline void pcie_core_pmu_setup(int pcie_port)
++{
++ struct clk *clk;
++ clk = clk_get_sys("1d900000.pcie", "ctl");
++ clk_enable(clk);
++ clk = clk_get_sys("1d900000.pcie", "bus");
++ clk_enable(clk);
++
++ /* PCIe Core controller enabled */
++// PCIE_CTRL_PMU_SETUP(IFX_PMU_ENABLE);
++
++ /* Enable PCIe L0 Clock */
++// PCIE_L0_CLK_PMU_SETUP(IFX_PMU_ENABLE);
++}
++
++static inline void pcie_msi_init(int pcie_port)
++{
++ struct clk *clk;
++ pcie_msi_pic_init(pcie_port);
++ clk = clk_get_sys("ltq_pcie", "msi");
++ clk_enable(clk);
++// MSI_PMU_SETUP(IFX_PMU_ENABLE);
++}
++
++static inline u32
++ifx_pcie_bus_nr_deduct(u32 bus_number, int pcie_port)
++{
++ u32 tbus_number = bus_number;
++
++#ifdef CONFIG_IFX_PCI
++ if (pcibios_host_nr() > 1) {
++ tbus_number -= pcibios_1st_host_bus_nr();
++ }
++#endif /* CONFIG_IFX_PCI */
++ return tbus_number;
++}
++
++static inline u32
++ifx_pcie_bus_enum_hack(struct pci_bus *bus, u32 devfn, int where, u32 value, int pcie_port, int read)
++{
++ struct pci_dev *pdev;
++ u32 tvalue = value;
++
++ /* Sanity check */
++ pdev = pci_get_slot(bus, devfn);
++ if (pdev == NULL) {
++ return tvalue;
++ }
++
++ /* Only care about PCI bridge */
++ if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
++ return tvalue;
++ }
++
++ if (read) { /* Read hack */
++ #ifdef CONFIG_IFX_PCI
++ if (pcibios_host_nr() > 1) {
++ tvalue = ifx_pcie_bus_enum_read_hack(where, tvalue);
++ }
++ #endif /* CONFIG_IFX_PCI */
++ }
++ else { /* Write hack */
++ #ifdef CONFIG_IFX_PCI
++ if (pcibios_host_nr() > 1) {
++ tvalue = ifx_pcie_bus_enum_write_hack(where, tvalue);
++ }
++ #endif
++ }
++ return tvalue;
++}
++
++#endif /* IFXMIPS_PCIE_VR9_H */
++
+diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
+index 04e35bc..2e85529 100644
+--- a/arch/mips/pci/pci.c
++++ b/arch/mips/pci/pci.c
+@@ -250,6 +250,31 @@ static int __init pcibios_init(void)
+
+ subsys_initcall(pcibios_init);
+
++int pcibios_host_nr(void)
++{
++ int count;
++ struct pci_controller *hose;
++ for (count = 0, hose = hose_head; hose; hose = hose->next, count++) {
++ ;
++ }
++ return count;
++}
++EXPORT_SYMBOL(pcibios_host_nr);
++
++int pcibios_1st_host_bus_nr(void)
++{
++ int bus_nr = 0;
++ struct pci_controller *hose = hose_head;
++
++ if (hose != NULL) {
++ if (hose->bus != NULL) {
++ bus_nr = hose->bus->number + 1;
++ }
++ }
++ return bus_nr;
++}
++EXPORT_SYMBOL(pcibios_1st_host_bus_nr);
++
+ static int pcibios_enable_resources(struct pci_dev *dev, int mask)
+ {
+ u16 cmd, old_cmd;
+diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig
+index 50e94e0..4bf848f 100644
+--- a/drivers/pci/pcie/aer/Kconfig
++++ b/drivers/pci/pcie/aer/Kconfig
+@@ -5,7 +5,7 @@
+ config PCIEAER
+ boolean "Root Port Advanced Error Reporting support"
+ depends on PCIEPORTBUS
+- default y
++ default n
+ help
+ This enables PCI Express Root Port Advanced Error Reporting
+ (AER) driver support. Error reporting messages sent to Root
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index ee21795..0d08026 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -1038,6 +1038,8 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),
+ int pci_cfg_space_size_ext(struct pci_dev *dev);
+ int pci_cfg_space_size(struct pci_dev *dev);
+ unsigned char pci_bus_max_busnr(struct pci_bus *bus);
++int pcibios_host_nr(void);
++int pcibios_1st_host_bus_nr(void);
+ void pci_setup_bridge(struct pci_bus *bus);
+ resource_size_t pcibios_window_alignment(struct pci_bus *bus,
+ unsigned long type);
+diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
+index 9d36b82..493ada4 100644
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -1040,6 +1040,12 @@
+ #define PCI_DEVICE_ID_SGI_LITHIUM 0x1002
+ #define PCI_DEVICE_ID_SGI_IOC4 0x100a
+
++#define PCI_VENDOR_ID_INFINEON 0x15D1
++#define PCI_DEVICE_ID_INFINEON_DANUBE 0x000F
++#define PCI_DEVICE_ID_INFINEON_PCIE 0x0011
++#define PCI_VENDOR_ID_LANTIQ 0x1BEF
++#define PCI_DEVICE_ID_LANTIQ_PCIE 0x00
++
+ #define PCI_VENDOR_ID_WINBOND 0x10ad
+ #define PCI_DEVICE_ID_WINBOND_82C105 0x0105
+ #define PCI_DEVICE_ID_WINBOND_83C553 0x0565
+--
+1.7.10.4
+
diff --git a/target/linux/lantiq/patches-3.7/0123-USB-fix-roothub-for-IFXHCD.patch b/target/linux/lantiq/patches-3.7/0123-USB-fix-roothub-for-IFXHCD.patch
new file mode 100644
index 0000000000..0d1feb59a4
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0123-USB-fix-roothub-for-IFXHCD.patch
@@ -0,0 +1,34 @@
+From 1b6941ae603f2885e6cf729119ef753deb7eb835 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Thu, 6 Dec 2012 19:59:53 +0100
+Subject: [PATCH 123/123] USB: fix roothub for IFXHCD
+
+---
+ drivers/usb/core/hub.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: linux-3.7-rc8/drivers/usb/core/hub.c
+===================================================================
+--- linux-3.7-rc8.orig/drivers/usb/core/hub.c 2012-12-03 20:22:37.000000000 +0100
++++ linux-3.7-rc8/drivers/usb/core/hub.c 2012-12-10 23:37:16.658956109 +0100
+@@ -3839,7 +3839,7 @@
+ udev->ttport = hdev->ttport;
+ } else if (udev->speed != USB_SPEED_HIGH
+ && hdev->speed == USB_SPEED_HIGH) {
+- if (!hub->tt.hub) {
++ if (hdev->parent && !hub->tt.hub) {
+ dev_err(&udev->dev, "parent hub has no TT\n");
+ retval = -EINVAL;
+ goto fail;
+Index: linux-3.7-rc8/arch/mips/lantiq/Kconfig
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/lantiq/Kconfig 2012-12-10 23:37:16.622956108 +0100
++++ linux-3.7-rc8/arch/mips/lantiq/Kconfig 2012-12-11 13:58:10.816251053 +0100
+@@ -3,6 +3,7 @@
+ config SOC_TYPE_XWAY
+ bool
+ select PINCTRL_XWAY
++ select USB_ARCH_HAS_HCD
+ default n
+
+ choice
diff --git a/target/linux/lantiq/patches-3.7/0124-pci_fix.patch b/target/linux/lantiq/patches-3.7/0124-pci_fix.patch
new file mode 100644
index 0000000000..013dac76cb
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0124-pci_fix.patch
@@ -0,0 +1,22 @@
+Index: linux-3.7-rc8/arch/mips/pci/pci-lantiq.c
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/pci/pci-lantiq.c 2012-12-03 20:22:37.000000000 +0100
++++ linux-3.7-rc8/arch/mips/pci/pci-lantiq.c 2012-12-14 23:28:24.355606776 +0100
+@@ -129,8 +129,15 @@
+
+ /* setup reset gpio used by pci */
+ reset_gpio = of_get_named_gpio(node, "gpio-reset", 0);
+- if (gpio_is_valid(reset_gpio))
+- devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset");
++ if (gpio_is_valid(reset_gpio)) {
++ int ret = devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset");
++ if (ret) {
++ dev_err(&pdev->dev,
++ "failed to request gpio %d\n", reset_gpio);
++ return ret;
++ }
++ gpio_direction_output(reset_gpio, 1);
++ }
+
+ /* enable auto-switching between PCI and EBU */
+ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL);
diff --git a/target/linux/lantiq/patches-3.7/0300-owrt-mtd-split.patch b/target/linux/lantiq/patches-3.7/0300-owrt-mtd-split.patch
new file mode 100644
index 0000000000..4f69ef96b3
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0300-owrt-mtd-split.patch
@@ -0,0 +1,230 @@
+From 2a295753a10823a47542c779a25bbb1f52c71281 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Fri, 3 Aug 2012 10:27:13 +0200
+Subject: [PATCH 19/25] owrt mtd split
+
+---
+ .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 1 +
+ arch/mips/lantiq/setup.c | 7 +
+ drivers/mtd/Kconfig | 4 +
+ drivers/mtd/mtdpart.c | 173 +++++++++++++++++++-
+ 4 files changed, 184 insertions(+), 1 deletions(-)
+
+diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+index 1ec8f2a..1ff93cc 100644
+diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
+index 982a98b..e2f3f3e 100644
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -31,6 +31,10 @@ config MTD_ROOTFS_SPLIT
+ bool "Automatically split 'rootfs' partition for squashfs"
+ default y
+
++config MTD_UIMAGE_SPLIT
++ bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'"
++ default y
++
+ config MTD_REDBOOT_PARTS
+ tristate "RedBoot partition table parsing"
+ ---help---
+diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
+index 855b70b..93711e2 100644
+--- a/drivers/mtd/mtdpart.c
++++ b/drivers/mtd/mtdpart.c
+@@ -867,6 +867,168 @@ static int refresh_rootfs_split(struct mtd_info *mtd)
+ }
+ #endif /* CONFIG_MTD_ROOTFS_SPLIT */
+
++#ifdef CONFIG_MTD_UIMAGE_SPLIT
++static unsigned long find_uimage_size(struct mtd_info *mtd,
++ unsigned long offset)
++{
++#define UBOOT_MAGIC 0x56190527
++ unsigned long magic = 0;
++ unsigned long temp;
++ size_t len;
++ int ret;
++
++ ret = mtd_read(mtd, offset, 4, &len, (void *)&magic);
++ if (ret || len != sizeof(magic))
++ return 0;
++
++ if (le32_to_cpu(magic) != UBOOT_MAGIC)
++ return 0;
++
++ ret = mtd_read(mtd, offset + 12, 4, &len, (void *)&temp);
++ if (ret || len != sizeof(temp))
++ return 0;
++
++ return temp + 0x40;
++}
++
++static unsigned long find_eva_size(struct mtd_info *mtd,
++ unsigned long offset)
++{
++#define EVA_MAGIC 0xfeed1281
++ unsigned long magic = 0;
++ unsigned long temp;
++ size_t len;
++ int ret;
++
++ ret = mtd_read(mtd, offset, 4, &len, (void *)&magic);
++ if (ret || len != sizeof(magic))
++ return 0;
++
++ if (le32_to_cpu(magic) != EVA_MAGIC)
++ return 0;
++
++ ret = mtd_read(mtd, offset + 4, 4, &len, (void *)&temp);
++ if (ret || len != sizeof(temp))
++ return 0;
++
++ /* add eva header size */
++ temp = le32_to_cpu(temp) + 0x18;
++
++ temp &= ~0xffff;
++ temp += 0x10000;
++ return temp;
++}
++
++static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset)
++{
++ unsigned long temp;
++ size_t len;
++ int ret;
++
++ ret = mtd_read(mtd, offset, 4, &len, (void *)&temp);
++ if (ret || len != sizeof(temp))
++ return 0;
++
++
++ return le32_to_cpu(temp) == SQUASHFS_MAGIC;
++}
++
++static int detect_eva_squashfs_partition(struct mtd_info *mtd, unsigned long offset)
++{
++ unsigned long temp;
++ size_t len;
++ int ret;
++
++ ret = mtd_read(mtd, offset, 4, &len, (void *)&temp);
++ if (ret || len != sizeof(temp))
++ return 0;
++
++ return be32_to_cpu(temp) == SQUASHFS_MAGIC;
++}
++
++static unsigned long find_brnimage_size(struct mtd_info *mtd,
++ unsigned long offset)
++{
++ unsigned long buf[4];
++ // Assume at most 2MB of kernel image
++ unsigned long end = offset + (2 << 20);
++ unsigned long ptr = offset + 0x400 - 12;
++ size_t len;
++ int ret;
++
++ while (ptr < end) {
++ long size_min = ptr - 0x400 - 12 - offset;
++ long size_max = ptr + 12 - offset;
++ ret = mtd_read(mtd, ptr, 16, &len, (void *)buf);
++ if (ret || len != 16)
++ return 0;
++
++ if (le32_to_cpu(buf[0]) < size_min ||
++ le32_to_cpu(buf[0]) > size_max) {
++ ptr += 0x400;
++ continue;
++ }
++
++ if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC)
++ return ptr + 12 - offset;
++
++ ptr += 0x400;
++ }
++
++ return 0;
++}
++
++static int split_uimage(struct mtd_info *mtd,
++ const struct mtd_partition *part)
++{
++ static struct mtd_partition split_partitions[] = {
++ {
++ .name = "kernel",
++ .offset = 0x0,
++ .size = 0x0,
++ }, {
++ .name = "rootfs",
++ .offset = 0x0,
++ .size = 0x0,
++ },
++ };
++
++ split_partitions[0].size = find_uimage_size(mtd, part->offset);
++ if (!split_partitions[0].size) {
++ split_partitions[0].size = find_eva_size(mtd, part->offset);
++ if (!split_partitions[0].size) {
++ split_partitions[0].size = find_brnimage_size(mtd, part->offset);
++ if (!split_partitions[0].size) {
++ printk(KERN_NOTICE "no uImage or brnImage or eva found in linux partition\n");
++ return -1;
++ }
++ }
++ }
++
++ if (detect_eva_squashfs_partition(mtd,
++ part->offset
++ + split_partitions[0].size)) {
++ split_partitions[0].size += 0x100;
++ pr_info("found eva dummy squashfs behind kernel\n");
++ } else if (!detect_squashfs_partition(mtd,
++ part->offset
++ + split_partitions[0].size)) {
++ split_partitions[0].size &= ~(mtd->erasesize - 1);
++ split_partitions[0].size += mtd->erasesize;
++ } else {
++ pr_info("found squashfs behind kernel\n");
++ }
++
++ split_partitions[0].offset = part->offset;
++ split_partitions[1].offset = part->offset + split_partitions[0].size;
++ split_partitions[1].size = part->size - split_partitions[0].size;
++
++ add_mtd_partitions(mtd, split_partitions, 2);
++
++ return 0;
++}
++#endif
++
+ /*
+ * This function, given a master MTD object and a partition table, creates
+ * and registers slave MTD objects which are bound to the master according to
+@@ -883,7 +1045,7 @@ int add_mtd_partitions(struct mtd_info *master,
+ struct mtd_part *slave;
+ uint64_t cur_offset = 0;
+ int i;
+-#ifdef CONFIG_MTD_ROOTFS_SPLIT
++#if defined(CONFIG_MTD_ROOTFS_SPLIT) || defined(CONFIG_MTD_UIMAGE_SPLIT)
+ int ret;
+ #endif
+
+@@ -900,6 +1062,15 @@ int add_mtd_partitions(struct mtd_info *master,
+
+ add_mtd_device(&slave->mtd);
+
++#ifdef CONFIG_MTD_UIMAGE_SPLIT
++ if (!strcmp(parts[i].name, "linux")) {
++ ret = split_uimage(master, &parts[i]);
++
++ if (ret)
++ printk(KERN_WARNING "Can't split linux partition\n");
++ }
++#endif
++
+ if (!strcmp(parts[i].name, "rootfs")) {
+ #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
+ if (ROOT_DEV == 0) {
+--
+1.7.9.1
+
diff --git a/target/linux/lantiq/patches-3.7/0301-gptu.path b/target/linux/lantiq/patches-3.7/0301-gptu.path
new file mode 100644
index 0000000000..d6d1ae88f9
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0301-gptu.path
@@ -0,0 +1,1049 @@
+Index: linux-3.7-rc8/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-12-13 10:34:27.044276614 +0100
++++ linux-3.7-rc8/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-12-13 10:41:34.332287326 +0100
+@@ -90,5 +90,8 @@
+ extern void ltq_pmu_enable(unsigned int module);
+ extern void ltq_pmu_disable(unsigned int module);
+
++/* allow tapi driver to read the gptu value */
++long gptu_get_count(struct clk *clk);
++
+ #endif /* CONFIG_SOC_TYPE_XWAY */
+ #endif /* _LTQ_XWAY_H__ */
+Index: linux-3.7-rc8/arch/mips/lantiq/xway/gptu.c
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/lantiq/xway/gptu.c 2012-12-13 10:34:27.044276614 +0100
++++ linux-3.7-rc8/arch/mips/lantiq/xway/gptu.c 2012-12-13 10:34:30.564276702 +0100
+@@ -105,8 +105,11 @@
+ gptu_w32(CON_CNT | CON_EDGE_ANY | CON_SYNC | CON_CLK_INT,
+ GPTU_CON(clk->bits));
+ gptu_w32(1, GPTU_RLD(clk->bits));
+- gptu_w32(gptu_r32(GPTU_IRNEN) | BIT(clk->bits), GPTU_IRNEN);
++/* gptu_w32(gptu_r32(GPTU_IRNEN) | BIT(clk->bits), GPTU_IRNEN);*/
+ gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits));
++
++ printk("%s:%s[%d]%X %X %X\n", __FILE__, __func__, __LINE__, gptu_r32(GPTU_CON(clk->bits)), gptu_r32(GPTU_RLD(clk->bits)), gptu_r32(GPTU_RUN(clk->bits)));
++
+ return 0;
+ }
+
+@@ -119,6 +122,12 @@
+ free_irq(irqres[clk->bits].start, NULL);
+ }
+
++long gptu_get_count(struct clk *clk)
++{
++ return gptu_r32(GPTU_CNT(clk->bits));
++}
++EXPORT_SYMBOL_GPL(gptu_get_count);
++
+ static inline void clkdev_add_gptu(struct device *dev, const char *con,
+ unsigned int timer)
+ {
+Index: linux-3.7-rc8/arch/mips/lantiq/xway/timer.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.7-rc8/arch/mips/lantiq/xway/timer.c 2012-12-13 10:41:16.360286872 +0100
+@@ -0,0 +1,841 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <linux/uaccess.h>
++#include <linux/unistd.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/irq.h>
++#include <asm/div64.h>
++#include "../clk.h"
++
++#include <lantiq_soc.h>
++#include <lantiq_irq.h>
++#include <lantiq_timer.h>
++
++#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6
++
++#ifdef TIMER1A
++#define FIRST_TIMER TIMER1A
++#else
++#define FIRST_TIMER 2
++#endif
++
++/*
++ * GPTC divider is set or not.
++ */
++#define GPTU_CLC_RMC_IS_SET 0
++
++/*
++ * Timer Interrupt (IRQ)
++ */
++/* Must be adjusted when ICU driver is available */
++#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22)
++
++/*
++ * Bits Operation
++ */
++#define GET_BITS(x, msb, lsb) \
++ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
++#define SET_BITS(x, msb, lsb, value) \
++ (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \
++ (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
++
++/*
++ * GPTU Register Mapping
++ */
++#define LQ_GPTU (KSEG1 + 0x1E100A00)
++#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000))
++#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008))
++#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
++#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
++#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
++#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
++#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4))
++#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8))
++#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC))
++
++/*
++ * Clock Control Register
++ */
++#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16)
++#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8)
++#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5))
++#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3))
++#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2))
++#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1))
++#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0))
++
++#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value))
++#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value))
++#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0)
++#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0)
++#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0)
++#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0)
++#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0)
++
++/*
++ * ID Register
++ */
++#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8)
++#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5)
++#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0)
++
++/*
++ * Control Register of Timer/Counter nX
++ * n is the index of block (1 based index)
++ * X is either A or B
++ */
++#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10))
++#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9))
++#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8))
++#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6)
++#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5))
++#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */
++#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3))
++#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2))
++#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1))
++#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0))
++
++#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10))
++#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0)
++#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0)
++#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value))
++#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0)
++#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0)
++#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0)
++#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0)
++#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0)
++
++#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0)
++#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0)
++#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0)
++
++#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
++#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
++
++#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001)
++#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002)
++#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004)
++#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008)
++#define TIMER_FLAG_NONE_EDGE 0x0000
++#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030)
++#define TIMER_FLAG_REAL 0x0000
++#define TIMER_FLAG_INVERT 0x0040
++#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040)
++#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070)
++#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080)
++#define TIMER_FLAG_CALLBACK_IN_HB 0x0200
++#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300)
++#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000)
++
++struct timer_dev_timer {
++ unsigned int f_irq_on;
++ unsigned int irq;
++ unsigned int flag;
++ unsigned long arg1;
++ unsigned long arg2;
++};
++
++struct timer_dev {
++ struct mutex gptu_mutex;
++ unsigned int number_of_timers;
++ unsigned int occupation;
++ unsigned int f_gptu_on;
++ struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2];
++};
++
++
++unsigned int ltq_get_fpi_bus_clock(int fpi) {
++ struct clk *clk = clk_get_fpi();
++ return clk_get_rate(clk);
++}
++
++
++static long gptu_ioctl(struct file *, unsigned int, unsigned long);
++static int gptu_open(struct inode *, struct file *);
++static int gptu_release(struct inode *, struct file *);
++
++static struct file_operations gptu_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = gptu_ioctl,
++ .open = gptu_open,
++ .release = gptu_release
++};
++
++static struct miscdevice gptu_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR,
++ .name = "gptu",
++ .fops = &gptu_fops,
++};
++
++static struct timer_dev timer_dev;
++
++static irqreturn_t timer_irq_handler(int irq, void *p)
++{
++ unsigned int timer;
++ unsigned int flag;
++ struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p;
++
++ timer = irq - TIMER_INTERRUPT;
++ if (timer < timer_dev.number_of_timers
++ && dev_timer == &timer_dev.timer[timer]) {
++ /* Clear interrupt. */
++ ltq_w32(1 << timer, LQ_GPTU_IRNCR);
++
++ /* Call user hanler or signal. */
++ flag = dev_timer->flag;
++ if (!(timer & 0x01)
++ || TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) {
++ /* 16-bit timer or timer A of 32-bit timer */
++ switch (TIMER_FLAG_MASK_HANDLE(flag)) {
++ case TIMER_FLAG_CALLBACK_IN_IRQ:
++ case TIMER_FLAG_CALLBACK_IN_HB:
++ if (dev_timer->arg1)
++ (*(timer_callback)dev_timer->arg1)(dev_timer->arg2);
++ break;
++ case TIMER_FLAG_SIGNAL:
++ send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0);
++ break;
++ }
++ }
++ }
++ return IRQ_HANDLED;
++}
++
++static inline void lq_enable_gptu(void)
++{
++ struct clk *clk = clk_get_sys("ltq_gptu", NULL);
++ clk_enable(clk);
++
++ //ltq_pmu_enable(PMU_GPT);
++
++ /* Set divider as 1, disable write protection for SPEN, enable module. */
++ *LQ_GPTU_CLC =
++ GPTU_CLC_SMC_SET(0x00) |
++ GPTU_CLC_RMC_SET(0x01) |
++ GPTU_CLC_FSOE_SET(0) |
++ GPTU_CLC_SBWE_SET(1) |
++ GPTU_CLC_EDIS_SET(0) |
++ GPTU_CLC_SPEN_SET(0) |
++ GPTU_CLC_DISR_SET(0);
++}
++
++static inline void lq_disable_gptu(void)
++{
++ struct clk *clk = clk_get_sys("ltq_gptu", NULL);
++ ltq_w32(0x00, LQ_GPTU_IRNEN);
++ ltq_w32(0xfff, LQ_GPTU_IRNCR);
++
++ /* Set divider as 0, enable write protection for SPEN, disable module. */
++ *LQ_GPTU_CLC =
++ GPTU_CLC_SMC_SET(0x00) |
++ GPTU_CLC_RMC_SET(0x00) |
++ GPTU_CLC_FSOE_SET(0) |
++ GPTU_CLC_SBWE_SET(0) |
++ GPTU_CLC_EDIS_SET(0) |
++ GPTU_CLC_SPEN_SET(0) |
++ GPTU_CLC_DISR_SET(1);
++
++ clk_enable(clk);
++}
++
++int lq_request_timer(unsigned int timer, unsigned int flag,
++ unsigned long value, unsigned long arg1, unsigned long arg2)
++{
++ int ret = 0;
++ unsigned int con_reg, irnen_reg;
++ int n, X;
++
++ if (timer >= FIRST_TIMER + timer_dev.number_of_timers)
++ return -EINVAL;
++
++ printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...",
++ timer, flag, value);
++
++ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT)
++ value &= 0xFFFF;
++ else
++ timer &= ~0x01;
++
++ mutex_lock(&timer_dev.gptu_mutex);
++
++ /*
++ * Allocate timer.
++ */
++ if (timer < FIRST_TIMER) {
++ unsigned int mask;
++ unsigned int shift;
++ /* This takes care of TIMER1B which is the only choice for Voice TAPI system */
++ unsigned int offset = TIMER2A;
++
++ /*
++ * Pick up a free timer.
++ */
++ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) {
++ mask = 1 << offset;
++ shift = 1;
++ } else {
++ mask = 3 << offset;
++ shift = 2;
++ }
++ for (timer = offset;
++ timer < offset + timer_dev.number_of_timers;
++ timer += shift, mask <<= shift)
++ if (!(timer_dev.occupation & mask)) {
++ timer_dev.occupation |= mask;
++ break;
++ }
++ if (timer >= offset + timer_dev.number_of_timers) {
++ printk("failed![%d]\n", __LINE__);
++ mutex_unlock(&timer_dev.gptu_mutex);
++ return -EINVAL;
++ } else
++ ret = timer;
++ } else {
++ register unsigned int mask;
++
++ /*
++ * Check if the requested timer is free.
++ */
++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
++ if ((timer_dev.occupation & mask)) {
++ printk("failed![%d] mask %#x, timer_dev.occupation %#x\n",
++ __LINE__, mask, timer_dev.occupation);
++ mutex_unlock(&timer_dev.gptu_mutex);
++ return -EBUSY;
++ } else {
++ timer_dev.occupation |= mask;
++ ret = 0;
++ }
++ }
++
++ /*
++ * Prepare control register value.
++ */
++ switch (TIMER_FLAG_MASK_EDGE(flag)) {
++ default:
++ case TIMER_FLAG_NONE_EDGE:
++ con_reg = GPTU_CON_EDGE_SET(0x00);
++ break;
++ case TIMER_FLAG_RISE_EDGE:
++ con_reg = GPTU_CON_EDGE_SET(0x01);
++ break;
++ case TIMER_FLAG_FALL_EDGE:
++ con_reg = GPTU_CON_EDGE_SET(0x02);
++ break;
++ case TIMER_FLAG_ANY_EDGE:
++ con_reg = GPTU_CON_EDGE_SET(0x03);
++ break;
++ }
++ if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER)
++ con_reg |=
++ TIMER_FLAG_MASK_SRC(flag) ==
++ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) :
++ GPTU_CON_SRC_EXT_SET(0);
++ else
++ con_reg |=
++ TIMER_FLAG_MASK_SRC(flag) ==
++ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) :
++ GPTU_CON_SRC_EG_SET(0);
++ con_reg |=
++ TIMER_FLAG_MASK_SYNC(flag) ==
++ TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) :
++ GPTU_CON_SYNC_SET(1);
++ con_reg |=
++ TIMER_FLAG_MASK_INVERT(flag) ==
++ TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1);
++ con_reg |=
++ TIMER_FLAG_MASK_SIZE(flag) ==
++ TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) :
++ GPTU_CON_EXT_SET(1);
++ con_reg |=
++ TIMER_FLAG_MASK_STOP(flag) ==
++ TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0);
++ con_reg |=
++ TIMER_FLAG_MASK_TYPE(flag) ==
++ TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) :
++ GPTU_CON_CNT_SET(1);
++ con_reg |=
++ TIMER_FLAG_MASK_DIR(flag) ==
++ TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0);
++
++ /*
++ * Fill up running data.
++ */
++ timer_dev.timer[timer - FIRST_TIMER].flag = flag;
++ timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1;
++ timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2;
++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
++ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag;
++
++ /*
++ * Enable GPTU module.
++ */
++ if (!timer_dev.f_gptu_on) {
++ lq_enable_gptu();
++ timer_dev.f_gptu_on = 1;
++ }
++
++ /*
++ * Enable IRQ.
++ */
++ if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) {
++ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL)
++ timer_dev.timer[timer - FIRST_TIMER].arg1 =
++ (unsigned long) find_task_by_vpid((int) arg1);
++
++ irnen_reg = 1 << (timer - FIRST_TIMER);
++
++ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL
++ || (TIMER_FLAG_MASK_HANDLE(flag) ==
++ TIMER_FLAG_CALLBACK_IN_IRQ
++ && timer_dev.timer[timer - FIRST_TIMER].arg1)) {
++ enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq);
++ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1;
++ }
++ } else
++ irnen_reg = 0;
++
++ /*
++ * Write config register, reload value and enable interrupt.
++ */
++ n = timer >> 1;
++ X = timer & 0x01;
++ *LQ_GPTU_CON(n, X) = con_reg;
++ *LQ_GPTU_RELOAD(n, X) = value;
++ /* printk("reload value = %d\n", (u32)value); */
++ *LQ_GPTU_IRNEN |= irnen_reg;
++
++ mutex_unlock(&timer_dev.gptu_mutex);
++ printk("successful!\n");
++ return ret;
++}
++EXPORT_SYMBOL(lq_request_timer);
++
++int lq_free_timer(unsigned int timer)
++{
++ unsigned int flag;
++ unsigned int mask;
++ int n, X;
++
++ if (!timer_dev.f_gptu_on)
++ return -EINVAL;
++
++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
++ return -EINVAL;
++
++ mutex_lock(&timer_dev.gptu_mutex);
++
++ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
++ timer &= ~0x01;
++
++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
++ if (((timer_dev.occupation & mask) ^ mask)) {
++ mutex_unlock(&timer_dev.gptu_mutex);
++ return -EINVAL;
++ }
++
++ n = timer >> 1;
++ X = timer & 0x01;
++
++ if (GPTU_CON_EN(n, X))
++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1);
++
++ *LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1);
++ *LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1);
++
++ if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) {
++ disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq);
++ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0;
++ }
++
++ timer_dev.occupation &= ~mask;
++ if (!timer_dev.occupation && timer_dev.f_gptu_on) {
++ lq_disable_gptu();
++ timer_dev.f_gptu_on = 0;
++ }
++
++ mutex_unlock(&timer_dev.gptu_mutex);
++
++ return 0;
++}
++EXPORT_SYMBOL(lq_free_timer);
++
++int lq_start_timer(unsigned int timer, int is_resume)
++{
++ unsigned int flag;
++ unsigned int mask;
++ int n, X;
++
++ if (!timer_dev.f_gptu_on)
++ return -EINVAL;
++
++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
++ return -EINVAL;
++
++ mutex_lock(&timer_dev.gptu_mutex);
++
++ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
++ timer &= ~0x01;
++
++ mask = (TIMER_FLAG_MASK_SIZE(flag) ==
++ TIMER_FLAG_16BIT ? 1 : 3) << timer;
++ if (((timer_dev.occupation & mask) ^ mask)) {
++ mutex_unlock(&timer_dev.gptu_mutex);
++ return -EINVAL;
++ }
++
++ n = timer >> 1;
++ X = timer & 0x01;
++
++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1);
++
++
++ mutex_unlock(&timer_dev.gptu_mutex);
++
++ return 0;
++}
++EXPORT_SYMBOL(lq_start_timer);
++
++int lq_stop_timer(unsigned int timer)
++{
++ unsigned int flag;
++ unsigned int mask;
++ int n, X;
++
++ if (!timer_dev.f_gptu_on)
++ return -EINVAL;
++
++ if (timer < FIRST_TIMER
++ || timer >= FIRST_TIMER + timer_dev.number_of_timers)
++ return -EINVAL;
++
++ mutex_lock(&timer_dev.gptu_mutex);
++
++ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
++ timer &= ~0x01;
++
++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
++ if (((timer_dev.occupation & mask) ^ mask)) {
++ mutex_unlock(&timer_dev.gptu_mutex);
++ return -EINVAL;
++ }
++
++ n = timer >> 1;
++ X = timer & 0x01;
++
++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1);
++
++ mutex_unlock(&timer_dev.gptu_mutex);
++
++ return 0;
++}
++EXPORT_SYMBOL(lq_stop_timer);
++
++int lq_reset_counter_flags(u32 timer, u32 flags)
++{
++ unsigned int oflag;
++ unsigned int mask, con_reg;
++ int n, X;
++
++ if (!timer_dev.f_gptu_on)
++ return -EINVAL;
++
++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
++ return -EINVAL;
++
++ mutex_lock(&timer_dev.gptu_mutex);
++
++ oflag = timer_dev.timer[timer - FIRST_TIMER].flag;
++ if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT)
++ timer &= ~0x01;
++
++ mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
++ if (((timer_dev.occupation & mask) ^ mask)) {
++ mutex_unlock(&timer_dev.gptu_mutex);
++ return -EINVAL;
++ }
++
++ switch (TIMER_FLAG_MASK_EDGE(flags)) {
++ default:
++ case TIMER_FLAG_NONE_EDGE:
++ con_reg = GPTU_CON_EDGE_SET(0x00);
++ break;
++ case TIMER_FLAG_RISE_EDGE:
++ con_reg = GPTU_CON_EDGE_SET(0x01);
++ break;
++ case TIMER_FLAG_FALL_EDGE:
++ con_reg = GPTU_CON_EDGE_SET(0x02);
++ break;
++ case TIMER_FLAG_ANY_EDGE:
++ con_reg = GPTU_CON_EDGE_SET(0x03);
++ break;
++ }
++ if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER)
++ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0);
++ else
++ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0);
++ con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1);
++ con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1);
++ con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1);
++ con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0);
++ con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1);
++ con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0);
++
++ timer_dev.timer[timer - FIRST_TIMER].flag = flags;
++ if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT)
++ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags;
++
++ n = timer >> 1;
++ X = timer & 0x01;
++
++ *LQ_GPTU_CON(n, X) = con_reg;
++ smp_wmb();
++ mutex_unlock(&timer_dev.gptu_mutex);
++ return 0;
++}
++EXPORT_SYMBOL(lq_reset_counter_flags);
++
++int lq_get_count_value(unsigned int timer, unsigned long *value)
++{
++ unsigned int flag;
++ unsigned int mask;
++ int n, X;
++
++ if (!timer_dev.f_gptu_on)
++ return -EINVAL;
++
++ if (timer < FIRST_TIMER
++ || timer >= FIRST_TIMER + timer_dev.number_of_timers)
++ return -EINVAL;
++
++ mutex_lock(&timer_dev.gptu_mutex);
++
++ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
++ timer &= ~0x01;
++
++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
++ if (((timer_dev.occupation & mask) ^ mask)) {
++ mutex_unlock(&timer_dev.gptu_mutex);
++ return -EINVAL;
++ }
++
++ n = timer >> 1;
++ X = timer & 0x01;
++
++ *value = *LQ_GPTU_COUNT(n, X);
++
++
++ mutex_unlock(&timer_dev.gptu_mutex);
++
++ return 0;
++}
++EXPORT_SYMBOL(lq_get_count_value);
++
++u32 lq_cal_divider(unsigned long freq)
++{
++ u64 module_freq, fpi = ltq_get_fpi_bus_clock(2);
++ u32 clock_divider = 1;
++ module_freq = fpi * 1000;
++ do_div(module_freq, clock_divider * freq);
++ return module_freq;
++}
++EXPORT_SYMBOL(lq_cal_divider);
++
++int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic,
++ int is_ext_src, unsigned int handle_flag, unsigned long arg1,
++ unsigned long arg2)
++{
++ unsigned long divider;
++ unsigned int flag;
++
++ divider = lq_cal_divider(freq);
++ if (divider == 0)
++ return -EINVAL;
++ flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT)
++ | (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE)
++ | (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC)
++ | TIMER_FLAG_TIMER | TIMER_FLAG_DOWN
++ | TIMER_FLAG_MASK_HANDLE(handle_flag);
++
++ printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n",
++ timer, freq, divider);
++ return lq_request_timer(timer, flag, divider, arg1, arg2);
++}
++EXPORT_SYMBOL(lq_set_timer);
++
++int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload,
++ unsigned long arg1, unsigned long arg2)
++{
++ printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload);
++ return lq_request_timer(timer, flag, reload, arg1, arg2);
++}
++EXPORT_SYMBOL(lq_set_counter);
++
++static long gptu_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret;
++ struct gptu_ioctl_param param;
++
++ if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param)))
++ return -EFAULT;
++ copy_from_user(&param, (void *) arg, sizeof(param));
++
++ if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER
++ || GPTU_SET_COUNTER) && param.timer < 2)
++ || cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER)
++ && !access_ok(VERIFY_WRITE, arg,
++ sizeof(struct gptu_ioctl_param)))
++ return -EFAULT;
++
++ switch (cmd) {
++ case GPTU_REQUEST_TIMER:
++ ret = lq_request_timer(param.timer, param.flag, param.value,
++ (unsigned long) param.pid,
++ (unsigned long) param.sig);
++ if (ret > 0) {
++ copy_to_user(&((struct gptu_ioctl_param *) arg)->
++ timer, &ret, sizeof(&ret));
++ ret = 0;
++ }
++ break;
++ case GPTU_FREE_TIMER:
++ ret = lq_free_timer(param.timer);
++ break;
++ case GPTU_START_TIMER:
++ ret = lq_start_timer(param.timer, param.flag);
++ break;
++ case GPTU_STOP_TIMER:
++ ret = lq_stop_timer(param.timer);
++ break;
++ case GPTU_GET_COUNT_VALUE:
++ ret = lq_get_count_value(param.timer, &param.value);
++ if (!ret)
++ copy_to_user(&((struct gptu_ioctl_param *) arg)->
++ value, &param.value,
++ sizeof(param.value));
++ break;
++ case GPTU_CALCULATE_DIVIDER:
++ param.value = lq_cal_divider(param.value);
++ if (param.value == 0)
++ ret = -EINVAL;
++ else {
++ copy_to_user(&((struct gptu_ioctl_param *) arg)->
++ value, &param.value,
++ sizeof(param.value));
++ ret = 0;
++ }
++ break;
++ case GPTU_SET_TIMER:
++ ret = lq_set_timer(param.timer, param.value,
++ TIMER_FLAG_MASK_STOP(param.flag) !=
++ TIMER_FLAG_ONCE ? 1 : 0,
++ TIMER_FLAG_MASK_SRC(param.flag) ==
++ TIMER_FLAG_EXT_SRC ? 1 : 0,
++ TIMER_FLAG_MASK_HANDLE(param.flag) ==
++ TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL :
++ TIMER_FLAG_NO_HANDLE,
++ (unsigned long) param.pid,
++ (unsigned long) param.sig);
++ if (ret > 0) {
++ copy_to_user(&((struct gptu_ioctl_param *) arg)->
++ timer, &ret, sizeof(&ret));
++ ret = 0;
++ }
++ break;
++ case GPTU_SET_COUNTER:
++ lq_set_counter(param.timer, param.flag, param.value, 0, 0);
++ if (ret > 0) {
++ copy_to_user(&((struct gptu_ioctl_param *) arg)->
++ timer, &ret, sizeof(&ret));
++ ret = 0;
++ }
++ break;
++ default:
++ ret = -ENOTTY;
++ }
++
++ return ret;
++}
++
++static int gptu_open(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++static int gptu_release(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++int __init lq_gptu_init(void)
++{
++ int ret;
++ unsigned int i;
++
++ ltq_w32(0, LQ_GPTU_IRNEN);
++ ltq_w32(0xfff, LQ_GPTU_IRNCR);
++
++ memset(&timer_dev, 0, sizeof(timer_dev));
++ mutex_init(&timer_dev.gptu_mutex);
++
++ lq_enable_gptu();
++ timer_dev.number_of_timers = GPTU_ID_CFG * 2;
++ lq_disable_gptu();
++ if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2)
++ timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2;
++ printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers);
++
++ ret = misc_register(&gptu_miscdev);
++ if (ret) {
++ printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret);
++ return ret;
++ } else {
++ printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor);
++ }
++
++ for (i = 0; i < timer_dev.number_of_timers; i++) {
++ ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]);
++ if (ret) {
++ for (; i >= 0; i--)
++ free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]);
++ misc_deregister(&gptu_miscdev);
++ printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret);
++ return ret;
++ } else {
++ timer_dev.timer[i].irq = TIMER_INTERRUPT + i;
++ disable_irq(timer_dev.timer[i].irq);
++ printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq);
++ }
++ }
++
++ return 0;
++}
++
++void __exit lq_gptu_exit(void)
++{
++ unsigned int i;
++
++ for (i = 0; i < timer_dev.number_of_timers; i++) {
++ if (timer_dev.timer[i].f_irq_on)
++ disable_irq(timer_dev.timer[i].irq);
++ free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]);
++ }
++ lq_disable_gptu();
++ misc_deregister(&gptu_miscdev);
++}
++
++module_init(lq_gptu_init);
++module_exit(lq_gptu_exit);
+Index: linux-3.7-rc8/arch/mips/include/asm/mach-lantiq/lantiq_timer.h
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.7-rc8/arch/mips/include/asm/mach-lantiq/lantiq_timer.h 2012-12-13 10:34:30.564276702 +0100
+@@ -0,0 +1,155 @@
++#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
++#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
++
++
++/******************************************************************************
++ Copyright (c) 2002, Infineon Technologies. All rights reserved.
++
++ No Warranty
++ Because the program is licensed free of charge, there is no warranty for
++ the program, to the extent permitted by applicable law. Except when
++ otherwise stated in writing the copyright holders and/or other parties
++ provide the program "as is" without warranty of any kind, either
++ expressed or implied, including, but not limited to, the implied
++ warranties of merchantability and fitness for a particular purpose. The
++ entire risk as to the quality and performance of the program is with
++ you. should the program prove defective, you assume the cost of all
++ necessary servicing, repair or correction.
++
++ In no event unless required by applicable law or agreed to in writing
++ will any copyright holder, or any other party who may modify and/or
++ redistribute the program as permitted above, be liable to you for
++ damages, including any general, special, incidental or consequential
++ damages arising out of the use or inability to use the program
++ (including but not limited to loss of data or data being rendered
++ inaccurate or losses sustained by you or third parties or a failure of
++ the program to operate with any other programs), even if such holder or
++ other party has been advised of the possibility of such damages.
++******************************************************************************/
++
++
++/*
++ * ####################################
++ * Definition
++ * ####################################
++ */
++
++/*
++ * Available Timer/Counter Index
++ */
++#define TIMER(n, X) (n * 2 + (X ? 1 : 0))
++#define TIMER_ANY 0x00
++#define TIMER1A TIMER(1, 0)
++#define TIMER1B TIMER(1, 1)
++#define TIMER2A TIMER(2, 0)
++#define TIMER2B TIMER(2, 1)
++#define TIMER3A TIMER(3, 0)
++#define TIMER3B TIMER(3, 1)
++
++/*
++ * Flag of Timer/Counter
++ * These flags specify the way in which timer is configured.
++ */
++/* Bit size of timer/counter. */
++#define TIMER_FLAG_16BIT 0x0000
++#define TIMER_FLAG_32BIT 0x0001
++/* Switch between timer and counter. */
++#define TIMER_FLAG_TIMER 0x0000
++#define TIMER_FLAG_COUNTER 0x0002
++/* Stop or continue when overflowing/underflowing. */
++#define TIMER_FLAG_ONCE 0x0000
++#define TIMER_FLAG_CYCLIC 0x0004
++/* Count up or counter down. */
++#define TIMER_FLAG_UP 0x0000
++#define TIMER_FLAG_DOWN 0x0008
++/* Count on specific level or edge. */
++#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000
++#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040
++#define TIMER_FLAG_RISE_EDGE 0x0010
++#define TIMER_FLAG_FALL_EDGE 0x0020
++#define TIMER_FLAG_ANY_EDGE 0x0030
++/* Signal is syncronous to module clock or not. */
++#define TIMER_FLAG_UNSYNC 0x0000
++#define TIMER_FLAG_SYNC 0x0080
++/* Different interrupt handle type. */
++#define TIMER_FLAG_NO_HANDLE 0x0000
++#if defined(__KERNEL__)
++ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100
++#endif // defined(__KERNEL__)
++#define TIMER_FLAG_SIGNAL 0x0300
++/* Internal clock source or external clock source */
++#define TIMER_FLAG_INT_SRC 0x0000
++#define TIMER_FLAG_EXT_SRC 0x1000
++
++
++/*
++ * ioctl Command
++ */
++#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */
++#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */
++#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */
++#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */
++#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */
++#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/
++#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */
++#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */
++
++/*
++ * Data Type Used to Call ioctl
++ */
++struct gptu_ioctl_param {
++ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
++ * GPTU_SET_COUNTER, this field is ID of expected *
++ * timer/counter. If it's zero, a timer/counter would *
++ * be dynamically allocated and ID would be stored in *
++ * this field. *
++ * In command GPTU_GET_COUNT_VALUE, this field is *
++ * ignored. *
++ * In other command, this field is ID of timer/counter *
++ * allocated. */
++ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
++ * GPTU_SET_COUNTER, this field contains flags to *
++ * specify how to configure timer/counter. *
++ * In command GPTU_START_TIMER, zero indicate start *
++ * and non-zero indicate resume timer/counter. *
++ * In other command, this field is ignored. */
++ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains *
++ * init/reload value. *
++ * In command GPTU_SET_TIMER, this field contains *
++ * frequency (0.001Hz) of timer. *
++ * In command GPTU_GET_COUNT_VALUE, current count *
++ * value would be stored in this field. *
++ * In command GPTU_CALCULATE_DIVIDER, this field *
++ * contains frequency wanted, and after calculation, *
++ * divider would be stored in this field to overwrite *
++ * the frequency. *
++ * In other command, this field is ignored. */
++ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
++ * if signal is required, this field contains process *
++ * ID to which signal would be sent. *
++ * In other command, this field is ignored. */
++ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
++ * if signal is required, this field contains signal *
++ * number which would be sent. *
++ * In other command, this field is ignored. */
++};
++
++/*
++ * ####################################
++ * Data Type
++ * ####################################
++ */
++typedef void (*timer_callback)(unsigned long arg);
++
++extern int lq_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long);
++extern int lq_free_timer(unsigned int);
++extern int lq_start_timer(unsigned int, int);
++extern int lq_stop_timer(unsigned int);
++extern int lq_reset_counter_flags(u32 timer, u32 flags);
++extern int lq_get_count_value(unsigned int, unsigned long *);
++extern u32 lq_cal_divider(unsigned long);
++extern int lq_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long);
++extern int lq_set_counter(unsigned int timer, unsigned int flag,
++ u32 reload, unsigned long arg1, unsigned long arg2);
++
++#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */
diff --git a/target/linux/lantiq/patches-3.7/0302-wifi-eep.patch b/target/linux/lantiq/patches-3.7/0302-wifi-eep.patch
new file mode 100644
index 0000000000..65ec0d17b6
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0302-wifi-eep.patch
@@ -0,0 +1,319 @@
+Index: linux-3.7-rc8/arch/mips/lantiq/xway/Makefile
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/lantiq/xway/Makefile 2012-12-13 10:59:54.176314899 +0100
++++ linux-3.7-rc8/arch/mips/lantiq/xway/Makefile 2012-12-13 13:58:51.696584083 +0100
+@@ -1,3 +1,5 @@
+ obj-y := prom.o sysctrl.o clk.o reset.o dma.o timer.o dcdc.o
+
++obj-y += ath_eep.o rt_eep.o eth_mac.o
++
+ obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o
+Index: linux-3.7-rc8/arch/mips/lantiq/xway/ath_eep.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.7-rc8/arch/mips/lantiq/xway/ath_eep.c 2012-12-13 13:49:12.472569552 +0100
+@@ -0,0 +1,120 @@
++/*
++ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
++ * Copyright (C) 2011 Andrej Vlašić <andrej.vlasic0@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/etherdevice.h>
++#include <linux/ath5k_platform.h>
++#include <linux/ath9k_platform.h>
++#include <linux/pci.h>
++
++extern int (*ltq_pci_plat_dev_init)(struct pci_dev *dev);
++struct ath5k_platform_data ath5k_pdata;
++/*struct ath9k_platform_data ath9k_pdata = {
++ .led_pin = -1,
++ .endian_check = true,
++};*/
++static u16 ath5k_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS];
++//static u16 ath9k_eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
++static u8 athxk_eeprom_mac[6];
++
++/*static int
++ath9k_pci_plat_dev_init(struct pci_dev *dev)
++{
++ dev->dev.platform_data = &ath9k_pdata;
++ return 0;
++}
++
++void __init
++ltq_register_ath9k(u16 *eeprom_data, u8 *macaddr)
++{
++ memcpy(ath9k_pdata.eeprom_data, eeprom_data, sizeof(ath9k_pdata.eeprom_data));
++ ath9k_pdata.macaddr = macaddr;
++ ltq_pci_plat_dev_init = ath9k_pci_plat_dev_init;
++}
++*/
++static int ath5k_pci_plat_dev_init(struct pci_dev *dev)
++{
++ dev->dev.platform_data = &ath5k_pdata;
++ return 0;
++}
++
++int __init of_ath5k_eeprom_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct resource *eep_res, *mac_res;
++ void __iomem *eep, *mac;
++ int mac_offset;
++ u32 mac_inc = 0;
++ int i;
++
++ eep_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ mac_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++
++ if (!eep_res) {
++ dev_err(&pdev->dev, "failed to load eeprom address\n");
++ return -ENODEV;
++ }
++ if (resource_size(eep_res) != ATH5K_PLAT_EEP_MAX_WORDS) {
++ dev_err(&pdev->dev, "eeprom has an invalid size\n");
++ return -EINVAL;
++ }
++
++ eep = ioremap(eep_res->start, resource_size(eep_res));
++ memcpy_fromio(ath5k_eeprom_data, eep, ATH5K_PLAT_EEP_MAX_WORDS);
++
++ if (of_find_property(np, "ath,eep-swap", NULL))
++ for (i = 0; i < (ATH5K_PLAT_EEP_MAX_WORDS >> 1); i++)
++ ath5k_eeprom_data[i] = swab16(ath5k_eeprom_data[i]);
++
++ if (!of_property_read_u32(np, "ath,mac-offset", &mac_offset)) {
++ memcpy_fromio(athxk_eeprom_mac, (void*) ath5k_eeprom_data, 6);
++ } else if (mac_res) {
++ if (resource_size(mac_res) != 6) {
++ dev_err(&pdev->dev, "mac has an invalid size\n");
++ return -EINVAL;
++ }
++ mac = ioremap(mac_res->start, resource_size(mac_res));
++ memcpy_fromio(athxk_eeprom_mac, mac, 6);
++ } else {
++ dev_warn(&pdev->dev, "using random mac\n");
++ random_ether_addr(athxk_eeprom_mac);
++ }
++
++ if (!of_property_read_u32(np, "ath,mac-increment", &mac_inc))
++ athxk_eeprom_mac[5] += mac_inc;
++
++ ath5k_pdata.eeprom_data = ath5k_eeprom_data;
++ ath5k_pdata.macaddr = athxk_eeprom_mac;
++ ltq_pci_plat_dev_init = ath5k_pci_plat_dev_init;
++
++ dev_info(&pdev->dev, "loaded ath5k eeprom\n");
++
++ return 0;
++}
++
++static struct of_device_id ath5k_eeprom_ids[] = {
++ { .compatible = "ath5k,eeprom" },
++ { }
++};
++
++static struct platform_driver ath5k_eeprom_driver = {
++ .driver = {
++ .name = "ath5k,eeprom",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(ath5k_eeprom_ids),
++ },
++};
++
++static int __init of_ath5k_eeprom_init(void)
++{
++ return platform_driver_probe(&ath5k_eeprom_driver, of_ath5k_eeprom_probe);
++}
++device_initcall(of_ath5k_eeprom_init);
+Index: linux-3.7-rc8/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-12-13 10:59:57.300314976 +0100
++++ linux-3.7-rc8/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-12-13 10:59:57.308314977 +0100
+@@ -93,5 +93,8 @@
+ /* allow tapi driver to read the gptu value */
+ long gptu_get_count(struct clk *clk);
+
++/* allow the ethernet driver to load a flash mapped mac addr */
++const u8* ltq_get_eth_mac(void);
++
+ #endif /* CONFIG_SOC_TYPE_XWAY */
+ #endif /* _LTQ_XWAY_H__ */
+Index: linux-3.7-rc8/arch/mips/lantiq/xway/eth_mac.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.7-rc8/arch/mips/lantiq/xway/eth_mac.c 2012-12-13 10:59:57.308314977 +0100
+@@ -0,0 +1,76 @@
++/*
++ * Copyright (C) 2012 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/init.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/if_ether.h>
++
++static u8 eth_mac[6];
++static int eth_mac_set;
++
++const u8* ltq_get_eth_mac(void)
++{
++ return eth_mac;
++}
++
++static int __init setup_ethaddr(char *str)
++{
++ eth_mac_set = mac_pton(str, eth_mac);
++ return !eth_mac_set;
++}
++__setup("ethaddr=", setup_ethaddr);
++
++int __init of_eth_mac_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct resource *mac_res;
++ void __iomem *mac;
++ u32 mac_inc = 0;
++
++ if (eth_mac_set) {
++ dev_err(&pdev->dev, "mac was already set by bootloader\n");
++ return -EINVAL;
++ }
++ mac_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++ if (!mac_res) {
++ dev_err(&pdev->dev, "failed to load mac\n");
++ return -EINVAL;
++ }
++ if (resource_size(mac_res) != 6) {
++ dev_err(&pdev->dev, "mac has an invalid size\n");
++ return -EINVAL;
++ }
++ mac = ioremap(mac_res->start, resource_size(mac_res));
++ memcpy_fromio(eth_mac, mac, 6);
++
++ if (!of_property_read_u32(np, "mac-increment", &mac_inc))
++ eth_mac[5] += mac_inc;
++
++ return 0;
++}
++
++static struct of_device_id eth_mac_ids[] = {
++ { .compatible = "lantiq,eth-mac" },
++ { /* sentinel */ }
++};
++
++static struct platform_driver eth_mac_driver = {
++ .driver = {
++ .name = "lantiq,eth-mac",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(eth_mac_ids),
++ },
++};
++
++static int __init of_eth_mac_init(void)
++{
++ return platform_driver_probe(&eth_mac_driver, of_eth_mac_probe);
++}
++device_initcall(of_eth_mac_init);
+Index: linux-3.7-rc8/drivers/net/ethernet/lantiq_etop.c
+===================================================================
+--- linux-3.7-rc8.orig/drivers/net/ethernet/lantiq_etop.c 2012-12-13 10:59:54.176314899 +0100
++++ linux-3.7-rc8/drivers/net/ethernet/lantiq_etop.c 2012-12-13 10:59:57.308314977 +0100
+@@ -816,7 +816,8 @@
+
+ ltq_etop_change_mtu(dev, 1500);
+
+- memcpy(&mac.sa_data, priv->mac, ETH_ALEN);
++ if (priv->mac)
++ memcpy(&mac.sa_data, priv->mac, ETH_ALEN);
+ if (!is_valid_ether_addr(mac.sa_data)) {
+ pr_warn("etop: invalid MAC, using random\n");
+ random_ether_addr(mac.sa_data);
+@@ -940,7 +941,9 @@
+ priv->tx_irq = irqres[0].start;
+ priv->rx_irq = irqres[1].start;
+ priv->mii_mode = of_get_phy_mode(pdev->dev.of_node);
+- priv->mac = of_get_mac_address(pdev->dev.of_node);
++ priv->mac = ltq_get_eth_mac();
++ if (!priv->mac)
++ priv->mac = of_get_mac_address(pdev->dev.of_node);
+
+ priv->clk_ppe = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk_ppe))
+Index: linux-3.7-rc8/arch/mips/lantiq/xway/rt_eep.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.7-rc8/arch/mips/lantiq/xway/rt_eep.c 2012-12-13 13:55:43.132579350 +0100
+@@ -0,0 +1,60 @@
++/*
++ * Copyright (C) 2011 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/init.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/rt2x00_platform.h>
++
++extern int (*ltq_pci_plat_dev_init)(struct pci_dev *dev);
++static struct rt2x00_platform_data rt2x00_pdata;
++
++static int rt2x00_pci_plat_dev_init(struct pci_dev *dev)
++{
++ dev->dev.platform_data = &rt2x00_pdata;
++ return 0;
++}
++
++int __init of_ralink_eeprom_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ const char *eeprom;
++
++ if (of_property_read_string(np, "ralink,eeprom", &eeprom)) {
++ dev_err(&pdev->dev, "failed to load eeprom filename\n");
++ return 0;
++ }
++
++ rt2x00_pdata.eeprom_file_name = kstrdup(eeprom, GFP_KERNEL);
++// rt2x00_pdata.mac_address = mac;
++ ltq_pci_plat_dev_init = rt2x00_pci_plat_dev_init;
++
++ dev_info(&pdev->dev, "using %s as eeprom\n", eeprom);
++
++ return 0;
++}
++
++static struct of_device_id ralink_eeprom_ids[] = {
++ { .compatible = "ralink,eeprom" },
++ { }
++};
++
++static struct platform_driver ralink_eeprom_driver = {
++ .driver = {
++ .name = "ralink,eeprom",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(ralink_eeprom_ids),
++ },
++};
++
++static int __init of_ralink_eeprom_init(void)
++{
++ return platform_driver_probe(&ralink_eeprom_driver, of_ralink_eeprom_probe);
++}
++device_initcall(of_ralink_eeprom_init);
diff --git a/target/linux/lantiq/patches-3.7/0303-vmmc.patch b/target/linux/lantiq/patches-3.7/0303-vmmc.patch
new file mode 100644
index 0000000000..f0bd584e38
--- /dev/null
+++ b/target/linux/lantiq/patches-3.7/0303-vmmc.patch
@@ -0,0 +1,79 @@
+Index: linux-3.7-rc8/arch/mips/lantiq/xway/Makefile
+===================================================================
+--- linux-3.7-rc8.orig/arch/mips/lantiq/xway/Makefile 2012-12-13 13:40:23.000000000 +0100
++++ linux-3.7-rc8/arch/mips/lantiq/xway/Makefile 2012-12-13 13:40:49.788556963 +0100
+@@ -1,5 +1,5 @@
+ obj-y := prom.o sysctrl.o clk.o reset.o dma.o timer.o dcdc.o
+
+-obj-y += ath_eep.o rt_eep.o eth_mac.o
++obj-y += ath_eep.o rt_eep.o eth_mac.o vmmc.o
+
+ obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o
+Index: linux-3.7-rc8/arch/mips/lantiq/xway/vmmc.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-3.7-rc8/arch/mips/lantiq/xway/vmmc.c 2012-12-13 13:40:30.520556476 +0100
+@@ -0,0 +1,63 @@
++/*
++ * 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) 2012 John Crispin <blogic@openwrt.org>
++ */
++
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/of_gpio.h>
++#include <linux/dma-mapping.h>
++
++#include <lantiq_soc.h>
++
++static unsigned int *cp1_base = 0;
++unsigned int* ltq_get_cp1_base(void)
++{
++ if (!cp1_base)
++ panic("no cp1 base was set\n");
++ return cp1_base;
++}
++EXPORT_SYMBOL(ltq_get_cp1_base);
++
++static int __devinit vmmc_probe(struct platform_device *pdev)
++{
++#define CP1_SIZE (1 << 20)
++ int gpio_count;
++ dma_addr_t dma;
++ cp1_base =
++ (void*)CPHYSADDR(dma_alloc_coherent(NULL, CP1_SIZE, &dma, GFP_ATOMIC));
++
++ gpio_count = of_gpio_count(pdev->dev.of_node);
++ while (gpio_count) {
++ enum of_gpio_flags flags;
++ int gpio = of_get_gpio_flags(pdev->dev.of_node, --gpio_count, &flags);
++ if (gpio_request(gpio, "vmmc-relay"))
++ continue;
++ dev_info(&pdev->dev, "requested GPIO %d\n", gpio);
++ gpio_direction_output(gpio, (flags & OF_GPIO_ACTIVE_LOW) ? (0) : (1));
++ }
++
++ dev_info(&pdev->dev, "reserved %dMB at 0x%p", CP1_SIZE >> 20, cp1_base);
++
++ return 0;
++}
++
++static const struct of_device_id vmmc_match[] = {
++ { .compatible = "lantiq,vmmc" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, vmmc_match);
++
++static struct platform_driver vmmc_driver = {
++ .probe = vmmc_probe,
++ .driver = {
++ .name = "lantiq,vmmc",
++ .owner = THIS_MODULE,
++ .of_match_table = vmmc_match,
++ },
++};
++
++module_platform_driver(vmmc_driver);
diff --git a/target/linux/lantiq/xway/config-default b/target/linux/lantiq/xway/config-default
index 23200b367f..6ee3a3bc54 100644
--- a/target/linux/lantiq/xway/config-default
+++ b/target/linux/lantiq/xway/config-default
@@ -5,15 +5,28 @@ CONFIG_INPUT=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_POLLDEV=y
# CONFIG_ISDN is not set
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_M25PXX_USE_FAST_READ=y
+CONFIG_MTD_M25P80=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_PLATFORM=y
CONFIG_MTD_NAND_XWAY=y
# CONFIG_MTD_PHYSMAP_OF is not set
# CONFIG_MTD_SM_COMMON is not set
-CONFIG_MTD_UIMAGE_SPLIT=y
+CONFIG_NLS=y
# CONFIG_PROC_DEVICETREE is not set
CONFIG_RTL8306_PHY=y
+CONFIG_RTL8366S_PHY=y
+CONFIG_RTL8367B_PHY=y
+CONFIG_RTL8367_PHY=y
CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
CONFIG_SPI_MASTER=y
+CONFIG_SPI_XWAY=y
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+# CONFIG_USB_EHCI_HCD is not set
CONFIG_USB_SUPPORT=y
+# CONFIG_USB_UHCI_HCD is not set
diff --git a/target/linux/lantiq/xway/profiles/arv.mk b/target/linux/lantiq/xway/profiles/arv.mk
index e8d371f8fb..c0c7c7c810 100644
--- a/target/linux/lantiq/xway/profiles/arv.mk
+++ b/target/linux/lantiq/xway/profiles/arv.mk
@@ -1,25 +1,104 @@
+define Profile/ARV4525PW
+ NAME:=Speedport W502V Typ A - ARV4525PW
+ PACKAGES:=kmod-ath5k wpad-mini \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa
+endef
+
+$(eval $(call Profile,ARV4525PW))
+
define Profile/ARV7525PW
- NAME:=Speedport W303V - ARV7525PW
+ NAME:=Speedport W303V Typ A - ARV7525PW
+ PACKAGES:=kmod-rt2800-pci wpad-mini \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa
endef
$(eval $(call Profile,ARV7525PW))
+define Profile/ARV4518PW
+ NAME:=SMC7908A-ISP, Airties WAV-221 - ARV4518PW
+ PACKAGES:=kmod-ltq-hcd-danube kmod-ledtrig-usbdev \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-ath5k wpad-mini \
+ swconfig
+endef
+
+$(eval $(call Profile,ARV4518PW))
+
+define Profile/ARV4510PW
+ NAME:=Wippies Homebox - ARV4510PW
+ PACKAGES:=kmod-ledtrig-usbdev kmod-usb2 kmod-usb-uhci \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-rt61 wpad-mini \
+ swconfig
+endef
+
+$(eval $(call Profile,ARV4510PW))
+
+define Profile/ARV7518PW
+ NAME:=Astoria - ARV7518PW
+ PACKAGES:=kmod-ltq-hcd-danube kmod-ledtrig-usbdev \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-ath9k wpad-mini \
+ swconfig
+endef
+
+$(eval $(call Profile,ARV7518PW))
+
define Profile/ARV4520PW
NAME:=Easybox 800, WAV-281 - ARV4520PW
+ PACKAGES:=kmod-ltq-hcd-danube kmod-ledtrig-usbdev \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-rt61-pci wpad-mini \
+ swconfig
endef
$(eval $(call Profile,ARV4520PW))
+define Profile/ARV452CQW
+ NAME:=Easybox 801 - ARV452CQW
+ PACKAGES:=kmod-ltq-hcd-danube kmod-ledtrig-usbdev \
+ kmod-ath5k wpad-mini \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa \
+ swconfig
+endef
+
+$(eval $(call Profile,ARV452CQW))
+
define Profile/ARV752DPW
NAME:=Easybox 802 - ARV752DPW
+ PACKAGES:=kmod-ltq-hcd-danube kmod-ledtrig-usbdev \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-ltq-tapi kmod-ltq-vmmc \
+ kmod-rt2800-pci wpad-mini \
+ swconfig
endef
$(eval $(call Profile,ARV752DPW))
define Profile/ARV752DPW22
NAME:=Easybox 803 - ARV752DPW22
- PACKAGES:= kmod-usb-core kmod-usb2 kmod-usb-uhci kmod-usb-dwc-otg kmod-ledtrig-usbdev \
- kmod-ltq-dsl-firmware-b-danube
+ PACKAGES:=kmod-usb2 kmod-usb-uhci kmod-ltq-hcd-danube kmod-ledtrig-usbdev \
+ kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+ kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-ltq-tapi kmod-ltq-vmmc \
+ swconfig
endef
$(eval $(call Profile,ARV752DPW22))
diff --git a/target/linux/lantiq/xway/profiles/avm.mk b/target/linux/lantiq/xway/profiles/avm.mk
new file mode 100644
index 0000000000..75db65e31b
--- /dev/null
+++ b/target/linux/lantiq/xway/profiles/avm.mk
@@ -0,0 +1,10 @@
+define Profile/FRITZ7320
+ NAME:=1&1 HomeServer - FRITZ7320
+ PACKAGES:=kmod-ath9k wpad-mini \
+ kmod-ltq-adsl-ar9-mei kmod-ltq-adsl-ar9 \
+ kmod-ltq-adsl-ar9-fw-b kmod-ltq-atm-ar9 \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-ltq-deu-ar9
+endef
+
+$(eval $(call Profile,FRITZ7320))
diff --git a/target/linux/lantiq/xway/profiles/lantiq.mk b/target/linux/lantiq/xway/profiles/lantiq.mk
index 2c24d3c95e..b4c914dd50 100644
--- a/target/linux/lantiq/xway/profiles/lantiq.mk
+++ b/target/linux/lantiq/xway/profiles/lantiq.mk
@@ -1,19 +1,17 @@
-define Profile/EASY80920-NOR
- NAME:=EASY80920-NOR
+define Profile/EASY50712
+ NAME:=Lantiq Danube - EASY50712
endef
-define Profile/EASY80920-NOR/Description
- Lantiq EASY80920 evalkit (NOR)
-endef
-
-$(eval $(call Profile,EASY80920-NOR))
+$(eval $(call Profile,EASY50712))
-define Profile/EASY80920-NAND
- NAME:=EASY80920-NAND
+define Profile/EASY80920NOR
+ NAME:=Lantiq VR9 - EASY80920NOR
endef
-define Profile/EASY80920-NAND/Description
- Lantiq EASY80920 evalkit (NAND)
+$(eval $(call Profile,EASY80920NOR))
+
+define Profile/EASY80920NAND
+ NAME:=Lantiq VR9 - EASY80920NAND
endef
-$(eval $(call Profile,EASY80920-NAND))
+$(eval $(call Profile,EASY80920NAND))
diff --git a/target/linux/lantiq/xway/profiles/netgear.mk b/target/linux/lantiq/xway/profiles/netgear.mk
new file mode 100644
index 0000000000..e7b16eee42
--- /dev/null
+++ b/target/linux/lantiq/xway/profiles/netgear.mk
@@ -0,0 +1,21 @@
+define Profile/DGN3500A
+ NAME:=Netgear DGN3500A
+ PACKAGES:=kmod-ath9k wpad-mini \
+ kmod-ltq-adsl-ar9-mei kmod-ltq-adsl-ar9 \
+ kmod-ltq-adsl-ar9-fw-a kmod-ltq-atm-ar9 \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-ltq-deu-ar9
+endef
+
+$(eval $(call Profile,DGN3500A))
+
+define Profile/DGN3500B
+ NAME:=Netgear DGN3500B
+ PACKAGES:=kmod-ath9k wpad-mini \
+ kmod-ltq-adsl-ar9-mei kmod-ltq-adsl-ar9 \
+ kmod-ltq-adsl-ar9-fw-b kmod-ltq-atm-ar9 \
+ ltq-adsl-app ppp-mod-pppoa \
+ kmod-ltq-deu-ar9
+endef
+
+$(eval $(call Profile,DGN3500B))
diff --git a/target/linux/lantiq/xway/target.mk b/target/linux/lantiq/xway/target.mk
index 6674665ccb..a58debdc62 100644
--- a/target/linux/lantiq/xway/target.mk
+++ b/target/linux/lantiq/xway/target.mk
@@ -3,7 +3,7 @@ SUBTARGET:=xway
BOARDNAME:=XWAY
FEATURES:=squashfs jffs2 atm
-DEFAULT_PACKAGES+=swconfig kmod-leds-gpio kmod-button-hotplug
+DEFAULT_PACKAGES+=kmod-leds-gpio kmod-button-hotplug kmod-input-gpio-keys-polled
define Target/Description
Lantiq XWAY